# Gestor de secretos para agentes de IA: almacenar no es controlar acciones

Un gestor de secretos para agentes de IA es necesario, pero no resuelve la parte peligrosa: qué ocurre después de que un agente solicite una credencial. Si el gestor devuelve el texto plano al proceso del agente, el secreto ya cruzó la frontera que querías proteger.

La diferencia parece minuciosa hasta que un agente sigue una instrucción manipulada, invoca una herramienta inesperada, escribe un archivo de diagnóstico o contacta con el host equivocado. Una bóveda puede mantener un token cifrado durante años y deshacer gran parte de ese trabajo en una sola llamada de recuperación. Para el trabajo con agentes, el diseño más seguro mantiene la credencial en un ejecutor de confianza y permite que el agente solicite una acción autenticada.

## Una bóveda protege el almacenamiento, no el uso de una credencial

Un gestor de secretos tradicional responde a una pregunta de almacenamiento: ¿quién puede recuperar este valor? Los agentes autónomos introducen una pregunta de uso: ¿puede este proceso realizar esta acción concreta con ese valor, en este momento y contra este destino?

La mayoría de los equipos empezó con hábitos sensatos. Sacaron los tokens de los repositorios, los cifraron en reposo, los rotaron después de una confirmación accidental y los inyectaron en un entorno de compilación. Esas prácticas funcionan bien para el despliegue de aplicaciones normales. Un trabajo de compilación suele tener un script fijo, una duración limitada y un conjunto conocido de endpoints. Su entorno puede seguir siendo demasiado amplio, pero una persona escribió los comandos antes de que empezara el trabajo.

Un agente es diferente. Genera comandos, elige herramientas, sigue el texto de incidencias, lee archivos escritos por otras personas y puede revisar su propio plan. Darle `DEPLOY_TOKEN` en una variable de entorno significa que todos los subprocesos que inicie pueden leer el token. También puede hacerlo un comando de shell que muestre el entorno, un depurador, un hook de instalación de paquetes o una herramienta no confiable que el agente elija porque un documento se lo indicó.

El gestor de secretos no ha fallado en esa situación. Hizo exactamente lo que se configuró para hacer: entregó un secreto a una carga de trabajo autorizada. El modelo de autorización era demasiado amplio para un actor que puede elegir su siguiente operación.

Mantén separadas estas dos autorizaciones:

- Permiso para identificar una credencial mediante una referencia estable.
- Permiso para usar esa credencial en una acción saliente descrita.

La primera autorización puede ser segura para un agente. La segunda necesita restricciones que correspondan a la acción. Una solicitud como `POST https://deploy.example.internal/releases` ofrece algo que un revisor puede evaluar. Una solicitud como `read production token` entrega un recurso cuyos usos futuros no pueden evaluarse en el momento de recuperarlo.

Esto también corrige una afirmación común pero poco útil: «el agente ya tiene ejecución de código, así que ocultar el secreto no cambia nada». La ejecución de código en el equipo de un desarrollador ya es bastante peligrosa. Un token bearer copiado de ese equipo crea un segundo problema: puede salir del equipo, sobrevivir al final de la sesión y funcionar desde un ordenador completamente distinto. Mantenerlo fuera del proceso no elimina todo el riesgo, pero sí retira una forma de acceso portátil y duradera que los atacantes buscan.

RFC 6750 lo deja claro para los tokens bearer de OAuth. Su definición dice que cualquier parte que posea un token bearer puede usarlo. El protocolo no pregunta si esa parte es tu agente aprobado, un plugin malicioso o alguien que encontró un archivo de registro. Tratar los tokens bearer como una salida normal de las herramientas ignora su propiedad fundamental.

## El acceso de lectura convierte los errores de instrucciones en filtraciones de credenciales

Un agente con acceso a secretos en texto plano puede filtrar una credencial sin intentar exfiltrarla. El camino peligroso suele parecer normal hasta el último paso.

Imagina un agente al que le piden diagnosticar por qué una API de despliegue rechazó una versión. Lee un documento del repositorio que indica recopilar un paquete de soporte. El script del paquete ejecuta `env`, copia archivos de configuración y archiva el resultado. El agente crea fielmente el archivo y lo adjunta a una incidencia o lo sube a un sistema de chat. El token nunca apareció en el terminal, pero pasó por el entorno, el archivo, la incidencia y todos los sistemas de copias de seguridad o notificaciones vinculados a ella.

Esto no es simplemente inyección de prompts. La inyección es una vía hacia la mala acción, pero una credencial copiada crea su propio radio de impacto después de que desaparezca la instrucción original. Un lector posterior de la incidencia podría descargarla. Un escáner automático podría indexarla. Un destinatario podría reutilizarla mucho después de terminar la ejecución del agente.

El mismo fallo aparece de formas más discretas:

- Un cliente HTTP detallado imprime un encabezado `Authorization` al reintentar.
- Un archivo de historial del shell captura un token pasado en la línea de comandos.
- Un accesorio de prueba registra un encabezado de solicitud y termina confirmado en el repositorio.
- Un proceso hijo hereda una variable de entorno que nunca necesitó.
- Un modelo incluye un secreto en su explicación porque el secreto apareció en la salida de una herramienta.

La respuesta popular es la redacción. Ayuda después de un error, pero no puede demostrar que todas las rutas de salida, formatos de archivo, trazas, subprocesos y servicios remotos trataron correctamente el valor. También falla con formatos de secretos desconocidos y tokens divididos entre varios campos. No conviertas la redacción en la barrera principal alrededor de credenciales que el agente nunca debería haber leído.

Una disposición mejor limita las entradas del agente. El agente envía una intención sin material de credenciales: método HTTP, URL permitida, cuerpo de la solicitud y referencia de la credencial. Un componente de confianza valida la solicitud, añade internamente el material de autenticación, envía la solicitud y devuelve una respuesta con los encabezados sensibles eliminados.

Esa frontera ofrece una respuesta mejor durante la gestión de incidentes. Si un agente se comporta mal, puedes revocar su sesión o rechazar acciones posteriores. Si descubres una instrucción maliciosa después de la ejecución, no tienes que empezar suponiendo que cada transcripción, archivo temporal y artefacto remoto contiene ahora un token de producción.

## La ejecución de acciones es una interfaz distinta de la recuperación de secretos

Una frontera de ejecución debe aceptar una operación, no entregar al agente un valor opaco esperando que lo use con cuidado. Esta es la diferencia que más se confunde, y equivocarse deja la bóveda convertida en una máquina expendedora de credenciales.

Para HTTP, el agente puede expresar una solicitud como esta:

```json
{
  "credential": "release-api",
  "method": "POST",
  "url": "https://deploy.example.internal/releases",
  "headers": {
    "Content-Type": "application/json"
  },
  "body": {
    "version": "2025.03.8",
    "environment": "staging"
  }
}
```

El ejecutor resuelve `release-api` en su bóveda protegida, inyecta el esquema de autenticación correspondiente y realiza la solicitud. El agente podría recibir un resultado con esta forma:

```json
{
  "status": 201,
  "headers": {
    "content-type": "application/json"
  },
  "body": {
    "release_id": "rel_4821",
    "state": "queued"
  }
}
```

La respuesta no debe incluir el encabezado `Authorization` inyectado, el valor copiado de la credencial ni diagnósticos de transporte que lo expongan. Parece obvio, pero el diseño de fronteras falla cuando los desarrolladores tratan el registro de solicitudes y respuestas como una tarea de infraestructura sin riesgos.

Para SSH, el agente debe enviar un host, una cuenta, un comando y quizá una referencia de credencial. El ejecutor usa la clave privada durante el intercambio de autenticación SSH y devuelve la salida estándar, la salida de error y el estado de salida. El agente nunca recibe un bloque PEM ni un socket de agente que pueda reutilizar en otro lugar.

No lo confundas con un proxy general. Un proxy reenvía tráfico arbitrario y puede inspeccionarlo o modificarlo. Un ejecutor de acciones tiene una función más limitada: posee las credenciales, realiza operaciones HTTP y SSH concretas, registra la decisión y devuelve un resultado acotado. Esa limitación es una ventaja. Cada función que acepta otro protocolo o introduce un desvío genérico ofrece al agente más formas de convertir la autoridad en una solicitud imposible de revisar.

La interfaz de solicitudes también necesita disciplina. Una referencia de credencial por sí sola no basta. Si `release-api` puede autenticarse en muchos hosts o aceptar una URL arbitraria, el agente puede dirigir una credencial válida hacia un endpoint controlado por un atacante o hacia un servicio interno menos protegido. Vincula las credenciales al esquema de autenticación y a los destinos previstos. Rechaza trucos de URL, como segmentos inesperados de información de usuario, redirecciones a hosts nuevos o un host que solo se parece al aprobado.

El ejecutor también debe decidir qué devuelve. Una respuesta API completa puede contener datos de usuarios, tokens de acceso creados por un servicio posterior o detalles de configuración que no deberían volver al contexto del modelo. Devolver solo los campos necesarios para la siguiente operación suele hacer que el agente sea más fiable y más seguro.

## SSH necesita control de comandos, no solo custodia de claves privadas

Ocultar una clave privada SSH ayuda, pero no vuelve seguros los comandos remotos arbitrarios. La autenticación informa al servidor de quién se conectó. No limita lo que esa cuenta puede hacer después de iniciar el shell.

RFC 4252 describe la autenticación SSH mediante clave pública como una firma sobre los datos del intercambio. La clave privada permanece privada durante ese intercambio, por eso SSH suele considerarse más seguro que un token API metido en una variable de entorno. Eso es cierto en un sentido concreto: el cliente demuestra que posee la clave en lugar de enviarla por la red. Sin embargo, un proceso que puede pedir a un agente SSH que firme también puede acceder a sistemas que confían en esa clave.

El reenvío del agente SSH merece una explicación directa. Permite que un servidor remoto use tu agente de autenticación local durante la conexión. El servidor remoto no recibe el archivo de clave privada, pero puede pedir firmas a través del socket reenviado. Solo es aceptable cuando confías en esa máquina remota y aceptas que pueda autenticarse como tú mientras exista el canal. No es una frontera adecuada para un agente autónomo que puede elegir dónde conectarse y qué comando de configuración ejecutar.

Una interfaz de acciones SSH más segura nombra explícitamente el destino y el comando. Debe registrar ambos, porque `ssh deploy@host "./deploy staging"` y `ssh deploy@host "cat /etc/shadow"` tienen el mismo evento de autenticación, pero consecuencias muy distintas.

Las restricciones del lado remoto siguen siendo necesarias. Usa cuentas separadas para funciones separadas. Da a una cuenta de despliegue acceso a los directorios de despliegue, no acceso de administrador. Cuando el servidor lo permita, configura comandos forzados o wrappers de comandos restringidos para las credenciales de automatización. Evita una clave personal de administrador compartida para tareas de agentes solo porque ya está presente en un equipo de trabajo.

Una solicitud SSH práctica puede ser tan pequeña como esta:

```json
{
  "credential": "staging-deployer",
  "host": "staging-runner.internal",
  "user": "deploy",
  "command": "./release apply 2025.03.8",
  "timeout_seconds": 120
}
```

Esa solicitud da al revisor algo concreto que aprobar y también algo concreto que auditar después. Si el agente necesita un shell interactivo, detente y pregunta por qué. Los shells interactivos sirven para que las personas reparen sistemas. Son un mal valor predeterminado para un agente, porque convierten una acción limitada en una sesión abierta donde cada comando posterior hereda la misma autoridad.

La verificación del host también importa. El ejecutor debe verificar hosts conocidos en lugar de aceptar cualquier clave presentada porque el modelo recibió la orden de conectarse. Si el agente puede desactivar la verificación del host, un atacante de red puede recibir comandos, observar la salida y quizá capturar los datos que el agente envíe después de iniciar sesión.

## La aprobación debe identificar el proceso y el alcance de la acción

Un botón de aprobación humana sirve de poco si solo indica que «un agente» solicitó acceso. Necesitas saber qué proceso local lo solicitó, qué autoridad firmada lo inició y si la aprobación se aplica a esta ejecución o a todas las futuras.

Las solicitudes por llamada parecen lo más seguro, así que muchos equipos empiezan por ahí. Después el agente realiza una larga secuencia de lecturas inofensivas, comprobaciones de estado y llamadas de seguimiento. La persona que observa recibe una pared de diálogos casi idénticos y empieza a aprobar por inercia. Es una reacción comprensible y destruye el control previsto.

La aprobación por sesión funciona mejor para el trabajo normal cuando vincula una aprobación a la vida de un proceso concreto del agente. La persona aprueba una ejecución determinada después de ver su identidad. El agente puede completar la secuencia esperada hasta salir. Un proceso nuevo obtiene una decisión nueva. Así se limita el efecto de un proceso reiniciado o sustituido que casualmente usa el mismo directorio del proyecto.

Reserva la aprobación por llamada para credenciales cuyo uso tenga consecuencias irreversibles o costosas. Las credenciales de versiones en producción, los tokens para borrar cuentas o una identidad SSH que llegue a sistemas sensibles encajan en esa categoría. Las llamadas de consulta de solo lectura normalmente no.

El alcance de la aprobación debe responder en lenguaje sencillo a cuatro preguntas:

1. ¿Qué autoridad de firma de código o ejecutable inició esta solicitud?
2. ¿Qué referencia de credencial utilizará?
3. ¿Qué destino o host recibirá la acción?
4. ¿La decisión expira cuando termina este proceso o esta llamada necesita su propia confirmación?

Evita un lenguaje de políticas salvo que tengas personal que lo mantenga y pruebas que demuestren sus efectos. Los motores de políticas atraen a los ingenieros porque prometen una respuesta precisa para cada situación. En la práctica, un montón de reglas se convierte en un programa de autorización sin documentar y los equipos conceden una excepción amplia cuando algo deja de funcionar. Un conjunto pequeño y visible de controles es más fácil de revisar y más difícil de debilitar por accidente.

Sallyport usa una secuencia fija de decisiones: una bóveda bloqueada rechaza todas las acciones, un proceso de agente nuevo requiere por defecto autorización de sesión y algunas credenciales pueden exigir aprobación en cada uso. El modelo se mantiene pequeño intencionadamente, porque una frontera de credenciales para agentes debe hacer evidente el estado de aprobación en lugar de obligar a los administradores a depurar una sintaxis de autorización.

## Un registro de auditoría debe resolver la cuestión después de la ejecución

Necesitas dos vistas de la actividad del agente: una para la ejecución y otra para cada llamada con credenciales. Un registro de sesión responde quién ejecutó el agente y cuándo terminó su autoridad. Un registro de acción responde qué destino, método o comando, referencia de credencial, decisión y resultado se produjeron.

Los equipos suelen registrar solo una transcripción del terminal. No basta. Una transcripción registra lo que imprimió el agente, no necesariamente lo que envió el ejecutor. Puede omitir llamadas en segundo plano, contener una salida modificada o revelar secretos si el agente tenía acceso a ellos. A la inversa, un registro de paquetes o solicitudes sin filtrar puede guardar demasiados datos sensibles para conservarlos con seguridad.

Registra el punto de decisión, no cada byte. Para HTTP, captura el método normalizado, el host, la ruta, la referencia de credencial, el estado de respuesta, la hora, la identidad de la sesión y el resultado de la aprobación. Cuando necesites correlación sin conservar datos de clientes, registra un resumen limitado o un digest del cuerpo de la solicitud. Para SSH, captura el host verificado, el usuario remoto, el comando, el estado de salida y los mismos campos de sesión y aprobación.

El registro debe permitir responder: «¿Qué proceso autorizado usó la credencial de despliegue para realizar qué operación y aprobó una persona ese uso?». Si no puede, quizá ayude a depurar, pero servirá de poco después de un incidente.

La evidencia contra manipulaciones aumenta el valor del registro. Un archivo de registro normal en el mismo equipo puede editarlo un proceso con suficiente acceso local. Una cadena hash vincula cada evento con el anterior, de modo que eliminar o modificar un registro anterior rompe la verificación de los posteriores. El cifrado protege el contenido; la cadena aporta pruebas de que la secuencia cambió.

Sallyport proyecta los diarios de sesiones y acciones desde un registro de auditoría cifrado y encadenado mediante hashes, y `sp audit verify` puede comprobar la cadena sin conexión sobre el texto cifrado, sin una clave de la bóveda. Esa separación importa durante una investigación: un revisor puede comprobar la integridad del registro sin obtener acceso a las credenciales o al contenido de las solicitudes que guarda la bóveda.

Una cadena no vuelve fiable por arte de magia un endpoint comprometido. Un atacante que controla la aplicación en ejecución aún puede intentar acciones antes de que respondas, y uno que obtiene el control antes de escribir una entrada puede influir en lo que se registra. La cadena aporta pruebas sólidas sobre el historial almacenado. Combínala con revocación rápida, almacenamiento local protegido y registros del lado remoto si necesitas una visión más completa del incidente.

## El problema empieza cuando el agente obtiene una salida conveniente

Los diseños más peligrosos suelen empezar con una excepción razonable. Alguien dice que la puerta de enlace es demasiado restrictiva para una integración, así que el agente obtiene un comando de shell genérico con un token en el entorno. O una herramienta de despliegue necesita SSH y el equipo activa el reenvío en lugar de definir la acción SSH concreta. O un ingeniero añade un endpoint de depuración que devuelve encabezados porque facilita las pruebas.

Cada excepción resuelve un problema local y vuelve a abrir la recuperación de secretos con otro nombre.

Repasa una configuración conocida. Un agente de programación tiene un token de servicio en su entorno para ejecutar un comando de lanzamiento. El agente lee un comentario de pull request que solicita investigar un lanzamiento fallido. Un script auxiliar del repositorio llama a un comando de diagnóstico. Ese comando exporta variables de entorno a un archivo de soporte. El agente sube el archivo a un gestor de incidencias externo porque el comentario pidió crear una incidencia.

Ningún atacante necesitó conocer de antemano el valor del token. Solo necesitó influir en un texto que el agente trató como instrucciones y dirigirlo a una herramienta que expusiera el estado heredado. Revocar la sesión del agente después de descubrirlo no retira el archivo. Rotar el token pasa a ser obligatorio y el equipo debe identificar todos los lugares por los que viajó el archivo.

Un ejecutor controlado cambia la secuencia. El script auxiliar aún puede ejecutarse y el agente puede consultar el estado del lanzamiento mediante una acción API aprobada. Pero no puede leer el token del entorno porque nunca se colocó allí. Si el script intenta realizar una nueva llamada con credenciales, el ejecutor la registra y aplica la decisión de sesión o por llamada. El archivo de soporte contiene menos información que robar.

No concedas un desvío solo porque un agente afirme necesitar una herramienta para completar una tarea. Pide la operación mínima que necesita la herramienta. Si necesita llamar a un endpoint API, expón esa operación. Si necesita un comando de despliegue, expón ese comando. Si su necesidad es realmente amplia, trátala como autoridad amplia y exige que una persona use un flujo separado y deliberado.

## Construye la frontera alrededor de las acciones importantes

Empieza por las credenciales cuya pérdida obligaría a una rotación urgente o permitiría un cambio importante en producción. No necesitas trasladar todos los tokens de desarrollo el primer día. Una frontera parcial alrededor de las credenciales más peligrosas es mejor que una migración completa que nadie termina.

Primero, haz inventario de cómo adquieren autoridad los agentes hoy. Busca en scripts de inicio, configuración del shell, archivos de transferencia de CI, configuración de herramientas, archivos `.env` locales y wrappers de comandos. Marca cada lugar que entrega a un agente un token, una contraseña, una clave privada, una sesión cloud o un socket de autenticación reenviado. Este inventario suele revelar que el agente tiene más autoridad a través de configuraciones heredadas del desarrollador de la que nadie pretendía.

Después sustituye la entrega en texto plano por solicitudes de acción. Define las referencias de credenciales según su propósito, no según una persona ni una etiqueta de entorno vaga. `staging-deployer` explica más que `shared-key-2`. Crea referencias separadas cuando dos usos necesiten requisitos de aprobación o destinos distintos.

Para cada referencia, decide lo siguiente antes de automatizarla:

- ¿Qué hosts, métodos y rutas HTTP, o qué hosts, usuarios y comandos SSH encajan con su función?
- ¿Un proceso de agente nuevo necesita una aprobación explícita antes de usarla?
- ¿Cada uso necesita confirmación porque la acción es destructiva o difícil de revertir?
- ¿Qué campos del resultado necesita el agente para continuar?
- ¿Qué registros permitirán explicar la acción después sin conservar material secreto?

Prueba las rutas de rechazo con el mismo cuidado que la ruta correcta. Ejecuta un proceso de agente sin aprobación y confirma que no puede actuar. Prueba un nombre de host parecido, una redirección a otro host, un comando fuera de la ruta de despliegue prevista y un intento de imprimir la referencia de credencial como si fuera su valor. Confirma que una sesión revocada no pueda seguir haciendo solicitudes.

Prueba también el lado humano. Si llegan tantas aprobaciones que dejas de leerlas, los alcances son incorrectos. Si un diálogo no puede decirte qué proceso hizo la solicitud, la identidad del proceso es demasiado débil. Si el agente no puede completar el trabajo normal sin pedir repetidamente una salida genérica, la interfaz de acciones necesita otra operación cuidadosamente limitada, no un volcado de secretos.

El criterio de éxito es sencillo: un agente puede completar el trabajo aprobado, pero una transcripción, un subproceso, un plugin o una instrucción manipulada no puede convertir ese trabajo en la posesión de una credencial reutilizable. Avanza hacia ese criterio antes de que el próximo despliegue urgente haga que la excepción conveniente parezca inofensiva.
