# Certificados SSH para agentes de IA y custodia local de credenciales

Los certificados SSH y la custodia local de credenciales se complementan. Un certificado proporciona al servidor SSH una declaración temporal sobre una clave pública. La custodia local mantiene la credencial privada correspondiente fuera del contexto, los archivos, los subprocesos y los registros de un agente de IA. Tratar cualquiera de las dos como sustituto de la otra deja una brecha que aparece en el peor momento posible.

La versión popular de este diseño dice que un certificado de 15 minutos hace que todo sea seguro. No es así. Si el agente puede leer la clave privada, puede seguir usando esa clave hasta que expire el certificado, solicitar otro si puede llegar al sistema de emisión o dejar una copia en un espacio de trabajo que sobreviva a la ejecución. Una validez corta reduce el tiempo durante el que el servidor acepta el certificado. No elimina la capacidad del proceso que contiene el secreto.

Para los agentes que pueden modificar la infraestructura, usa certificados para reducir el tiempo de aceptación y custodia local para evitar que se revele la credencial privada. Después, diseña la renovación, las interrupciones y la revocación como un único sistema operativo. Los detalles importan más que el tiempo de validez del certificado que aparece en un diagrama.

## Un certificado limita la aceptación, no la posesión

Un certificado de usuario de OpenSSH es una clave pública firmada junto con varias restricciones. El servidor SSH verifica la firma de la CA y comprueba campos como el tipo de certificado, el intervalo de validez, la lista de principales, las opciones críticas y las extensiones. El cliente aún debe demostrar que controla la clave privada correspondiente a la clave pública certificada.

Esa diferencia se confunde constantemente. Un certificado es material público. Puedes colocar `id_ed25519-cert.pub` junto a una clave privada, copiarlo a un cliente e inspeccionarlo libremente. El secreto sigue siendo `id_ed25519`. Si un agente recibe ese archivo privado, la corta validez del certificado solo limita durante cuánto tiempo funciona un certificado emitido. El agente sigue teniendo una credencial de firma reutilizable.

OpenSSH documenta el formato de los certificados en PROTOCOL.certkeys y ofrece los controles habituales de creación en el manual de `ssh-keygen`. El comando de firma recibe una clave privada de CA con `-s`, una cadena de identidad con `-I`, las principales permitidas con `-n` y una especificación de validez con `-V`. Son datos de autorización, no metadatos decorativos. El servidor debe estar configurado para confiar en la CA e interpretar las principales antes de que cualquiera de esos valores afecte al acceso.

Considera dos diseños:

- En el primero, un agente recibe `id_ed25519`, un certificado y el endpoint de la CA. El agente puede firmar por sí mismo los desafíos SSH y quizá pueda realizar futuras solicitudes de certificados.
- En el segundo, un ejecutor local guarda `id_ed25519` en un almacenamiento protegido. El agente solicita una acción SSH con nombre y el ejecutor gestiona la autenticación SSH sin devolver material privado.

Ambos diseños pueden usar el mismo certificado. Solo el segundo impide que una inyección de instrucciones en el agente, un complemento comprometido o un subproceso demasiado curioso copie la credencial privada.

Tampoco uses el campo de identidad del certificado como prueba de custodia. El valor de `-I` ayuda a las personas a relacionar los registros de emisión y acceso, pero cualquier solicitante que pueda pedir certificados puede elegir una identidad llamativa. Vincula la emisión a una clave pública conocida y a una sesión de agente conocida. Si tu emisor acepta claves públicas y cadenas de identidad arbitrarias, tu registro de auditoría se convertirá en ficción bajo presión.

## La custodia local cambia el fallo que debes planificar

Guardar una credencial en local convierte un incidente de exfiltración de secretos en un incidente de autorización de acciones. Es un problema mejor, pero sigue siendo un problema. El agente puede solicitar un comando destructivo, dirigirse al host equivocado o usar una sesión aprobada durante más tiempo del que pretendía el operador.

El componente local debe conservar la credencial SSH privada y realizar por sí mismo la operación del protocolo. El agente debe recibir la salida del comando, el estado de salida y una cantidad limitada de información diagnóstica. No debe recibir la clave privada como texto, una ruta a un archivo temporal, una variable de entorno, un socket de agente SSH que pueda reenviar ni un valor supuestamente oculto que otra herramienta pueda resolver.

Un mal compromiso habitual consiste en montar un directorio de secretos en modo de solo lectura dentro del entorno del agente. El modo de solo lectura protege contra modificaciones, no contra lecturas. Otro compromiso problemático guarda la clave privada en un agente SSH y da a cada proceso hijo acceso a `SSH_AUTH_SOCK`. Puede ser aceptable en un shell interactivo muy controlado, pero un agente de programación autónomo inicia herramientas, ejecutores de pruebas, hooks de paquetes y procesos auxiliares. Cada uno amplía el conjunto de procesos que pueden pedirle al agente que firme.

La custodia local también te proporciona un punto útil para el control humano. Una persona puede aprobar la primera acción de un proceso nuevo, exigir aprobación para credenciales sensibles en cada uso o bloquear la bóveda por completo. Esos controles no sustituyen la autorización del servidor. Deciden si un proceso puede intentar una acción.

Mantén este límite estrecho. El componente que guarda la clave privada no debe aceptar texto de shell arbitrario y ejecutarlo a ciegas porque lo proporciona el agente. Debe conocer el host, la cuenta de destino y la solicitud de acción que ejecutará, y debe registrar esos datos antes de la ejecución o junto a ella. Si no puedes reconstruir qué proceso solicitó `ssh deploy@host`, la custodia local se ha convertido en un envoltorio de secretos con una rendición de cuentas deficiente.

La consecuencia práctica es sencilla: la renovación del certificado debe actualizar la autorización pública, mientras la custodia local sigue controlando la firma privada. No reconstruyas la credencial privada cada vez que expire un certificado, salvo que tengas un motivo independiente para rotarla.

## La duración del certificado debe seguir la tolerancia a las interrupciones

Elige la validez según el tiempo que puedas tolerar una credencial ya emitida después de detener el trabajo nuevo. La respuesta cambia entre una ejecución de diagnóstico de solo lectura, un flujo de despliegue y un agente que puede modificar los controles de acceso.

Empieza con una duración que deje margen para el trabajo real. La renovación de certificados falla más de lo que los equipos esperan porque los portátiles entran en suspensión, cambian las rutas de la VPN, la CA deja de estar disponible brevemente, un comando largo mantiene abierta una conexión o el reloj de la máquina se desvía. Una duración muy corta convierte las interrupciones normales en una fuente constante de lógica de reintentos y atajos tentadores.

Para muchas tareas autónomas, un certificado válido entre 15 y 60 minutos es un primer ajuste razonable. Usa el extremo inferior cuando la cuenta pueda afectar a sistemas de producción. Usa una ventana más larga solo cuando el trabajo realmente la necesite y puedas explicar por qué. Un certificado de varias horas para un trabajo de diez minutos suele ser comodidad disfrazada de necesidad operativa.

No confundas la validez del certificado con la duración de la conexión SSH. SSH se autentica cuando establece una conexión. Normalmente, el servidor no expulsa una sesión ya autenticada cuando llega la fecha de expiración del certificado. La multiplexación de conexiones puede hacerlo aún más sorprendente: un comando posterior puede reutilizar una conexión maestra ya autenticada en lugar de realizar una nueva comprobación del certificado.

Ese comportamiento cambia el diseño:

1. Configura la validez del certificado para limitar las nuevas autenticaciones.
2. Limita por separado la duración del comando o de la sesión en el ejecutor local.
3. Evita entregar al agente un socket de control multiplexado reutilizable.
4. Termina las sesiones activas durante una emergencia cuando deba detenerse la propia acción.

La opción `ControlMaster` de `ssh_config` resulta útil para agilizar el uso interactivo, pero debilita las suposiciones sencillas sobre la autenticación de cada comando. Para trabajos autónomos, desactiva la multiplexación en los destinos sensibles o deja que el ejecutor controle y cierre la conexión. No permitas que un agente herede una ruta de control que permanezca autenticada después de que haya terminado su aprobación o su ventana de certificado.

La sincronización horaria también forma parte de esta sección. Un certificado tiene un intervalo de validez absoluto. Si el host emisor y el servidor de destino discrepan mucho en la hora, un certificado recién creado puede parecer expirado o todavía no válido. Supervisa la sincronización horaria en ambos extremos y falla de forma segura cuando el servidor rechace la ventana de validez. No soluciones un fallo del reloj emitiendo un certificado mucho más largo.

## La renovación debe demostrar que el mismo límite de custodia sigue existiendo

Un servicio de renovación debe emitir un certificado nuevo solo después de vincular la solicitud con la credencial que se guarda localmente, la sesión actual del agente y el alcance de autorización solicitado. Aceptar una clave pública en una solicitud HTTP no demuestra quién controla la mitad privada correspondiente.

El flujo más limpio pide al ejecutor local que demuestre durante la renovación que posee su clave pública registrada. El emisor verifica esa prueba, comprueba la sesión activa y la principal solicitada, firma la clave pública y devuelve únicamente el certificado público. El ejecutor adjunta ese certificado a la credencial privada que mantiene internamente para la siguiente conexión SSH.

Un comando de creación de certificados podría tener este aspecto en el emisor:

```
ssh-keygen -s agent_user_ca -I run-4821 -n deploy-prod -V +30m agent-run-4821.pub
```

Este comando firma `agent-run-4821.pub` con la clave privada de la CA. Crea un certificado público asociado, normalmente llamado `agent-run-4821-cert.pub`. La cadena `run-4821` ayuda a relacionar los registros, `deploy-prod` es la principal permitida y `+30m` solicita un intervalo de treinta minutos. El emisor debe generar esa cadena de identidad por sí mismo, en lugar de confiar en una etiqueta proporcionada por el agente.

Inspecciona cada certificado nuevo antes de permitir que la automatización dependa de él:

```
ssh-keygen -L -f agent-run-4821-cert.pub
```

La salida muestra el tipo de certificado, la huella de la CA firmante, la identidad, el número de serie, el intervalo de validez, las principales, las opciones críticas y las extensiones. Incluye esta inspección en las pruebas del emisor. De lo contrario, una principal ausente, un intervalo que comience en el futuro o una extensión inesperada aparecerán como un despliegue fallido y alguien intentará recurrir a una clave de larga duración.

Renueva antes de que el trabajo necesite una conexión SSH nueva, no justo en el segundo de expiración. El ejecutor puede solicitar un reemplazo cerca del final del intervalo mientras el certificado actual aún funciona. También debe negarse a iniciar un comando si queda demasiado poco tiempo de certificado para la duración permitida del comando. Esa comprobación evita que un trabajo empiece una escritura importante justo antes de que falle la siguiente autenticación.

Haz que la renovación sea idempotente en el nivel de la solicitud. Una respuesta perdida puede hacer que un cliente reintente aunque el emisor ya haya creado un certificado válido. Registra un identificador de solicitud, un identificador de sesión, la huella de la clave pública, la principal y la expiración. En un reintento, devuelve el certificado emitido anteriormente cuando los datos coincidan. Si difieren, rechaza la solicitud en lugar de adivinar cuál quería decir el agente.

## Las principales y la política del servidor deciden qué puede hacer el certificado

Un certificado indica quién puede autenticarse. El servidor sigue decidiendo qué cuenta local acepta esa identidad y qué puede hacer dicha cuenta. Si permites que un certificado de agente se autentique como una cuenta de administrador compartida y amplia, una validez corta no salvará una decisión de autorización permisiva.

OpenSSH puede confiar en una CA de usuarios mediante `TrustedUserCAKeys`. Después puedes asignar las principales aceptadas con `AuthorizedPrincipalsFile` o `AuthorizedPrincipalsCommand`. Esta última opción resulta útil cuando un servidor necesita una asignación de cuentas gestionada de forma centralizada, pero añade una dependencia de disponibilidad al inicio de sesión. Un archivo de principales estático es menos flexible y, a menudo, más fácil de entender en una flota pequeña.

Una configuración de servidor restringida podría tener este aspecto:

```
TrustedUserCAKeys /etc/ssh/agent_user_ca.pub
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
RevokedHostKeys /etc/ssh/revoked_agent_credentials.krl
```

Para una cuenta local llamada `deploy`, `/etc/ssh/auth_principals/deploy` podría contener únicamente:

```
deploy-prod
```

Esta estructura significa que el servidor acepta un certificado de la CA indicada solo cuando contiene `deploy-prod` como principal y no ha sido revocado por la KRL configurada. Prueba la versión exacta de OpenSSH instalada en tus servidores. Las directivas de configuración y el comportamiento de los certificados son estables en principio, pero el empaquetado de cada distribución y las versiones antiguas pueden afectar a aquello en lo que puedes confiar.

Las opciones críticas y las extensiones del certificado pueden restringir aún más el uso. OpenSSH admite opciones críticas como `force-command` y `source-address`, y también reconoce extensiones como `permit-pty`, `permit-port-forwarding` y `permit-agent-forwarding`. Úsalas cuando el flujo de destino tenga una forma limitada. Un agente que solo ejecuta un asistente de despliegue no debería recibir por accidente un shell interactivo general.

No añadas la capacidad genérica `permit-pty` a un certificado de agente porque alguien pueda necesitar depuración más adelante. Emite una credencial de diagnóstico separada y aprobada conscientemente cuando haga falta. Las extensiones de conveniencia tienden a permanecer mucho tiempo después de que desaparezca la tarea excepcional que las justificó.

## La revocación de emergencia requiere algo más que esperar a la expiración

La corta validez sirve para la contención rutinaria. Si detienes la emisión y el certificado expira en treinta minutos, las nuevas autenticaciones SSH se detendrán después de esa ventana. Puede bastar si detectaste una tarea errónea antes de que tocara un destino sensible. No basta cuando la credencial privada puede haberse filtrado o el agente ha empezado a realizar acciones dañinas.

El primer movimiento de contención es detener la emisión para la sesión, la credencial o la CA afectada. Después, impide que las credenciales ya emitidas se autentiquen donde la urgencia lo requiera. En OpenSSH, una lista de revocación de claves, o KRL, permite a los servidores rechazar certificados concretos, claves públicas o una CA firmante.

Para añadir un certificado emitido a una KRL, un operador puede usar un comando como este:

```
ssh-keygen -k -f revoked_agent_credentials.krl -s agent_user_ca.pub agent-run-4821-cert.pub
```

El argumento `-s` identifica la CA que firmó el certificado. Distribuye la KRL resultante a los servidores de destino, mantén la ruta coherente con `RevokedHostKeys` y recarga sshd según tu procedimiento operativo. Prueba todo el flujo con antelación: crea un certificado, autentícate correctamente, añádelo a la KRL, distribuye el archivo, recarga sshd y comprueba que una nueva autenticación falla.

Una KRL no es un interruptor central de apagado. Cada servidor SSH debe recibir el archivo y leerlo. Si un host no está disponible, está desconectado o se gestiona bajo un régimen de configuración separado, puede seguir aceptando el certificado hasta que expire. Por eso un intervalo de validez corto sigue siendo útil aunque utilices listas de revocación.

Si sospechas que la propia clave privada de la CA está comprometida, revocar certificados individuales no es una respuesta de la escala adecuada. Elimina o sustituye la confianza en esa CA en los servidores afectados, emite una CA nueva y vuelve a certificar únicamente las credenciales en las que aún confíes. Mantén una CA distinta para el acceso de los agentes, para que esta operación no bloquee el acceso humano de emergencia. Conserva una vía de emergencia probada, pero mantenla fuera del alcance del agente y registra su uso.

Por último, termina las sesiones activas. La distribución de una KRL bloquea las autenticaciones futuras, pero no necesariamente termina una conexión SSH que el servidor ya aceptó. Usa los controles de sesión del host, el supervisor de trabajos o los controles de red para detener el trabajo activo. Después revisa los comandos ya ejecutados, porque revocar una credencial no puede deshacer un despliegue ni recuperar un archivo eliminado.

## El emisor de certificados debe fallar de forma segura cuando hay incertidumbre

El emisor debe rechazar la renovación cuando no pueda verificar la identidad del ejecutor local, el estado de la sesión, la principal solicitada o la autorización necesaria para ese alcance. La presión por mantener la disponibilidad hace que los equipos conviertan estas comprobaciones en advertencias. Esa decisión transforma una interrupción temporal en una emisión de credenciales sin límites.

Planifica los fallos habituales antes del día del despliegue. Si el emisor no está disponible, deja que un certificado existente funcione hasta su expiración normal, pero no lo sustituyas silenciosamente por una clave privada estática. Si la bóveda local está bloqueada, deniega la acción. Si se necesita aprobación humana y nadie responde, expira el trabajo en lugar de permitir que el agente conserve una aprobación indefinidamente.

Un registro de renovación útil incluye la huella de la CA, el número de serie del certificado, la hora de emisión, la hora de expiración, la huella de la clave pública, la principal solicitada, la identidad del proceso del agente, el identificador de sesión, la clase de destino y el resultado de la aprobación. El propio certificado contiene parte de esta información, pero no indica si la solicitud siguió la ruta de control local prevista.

El emisor también debe impedir que el alcance cambie durante la renovación. Una sesión aprobada para `deploy-prod` no debe renovarse como `root-prod`, una principal más amplia, simplemente porque el agente haya revisado su plan. Exige un nuevo límite de autorización para otra cuenta, grupo de destinos o clase de comandos. Aquí es donde los trabajos autónomos de larga duración suelen volverse inseguros: la sesión empieza siendo limitada y después acumula excepciones mediante una lógica de renovación que nadie revisa.

Usa registros separados para la emisión y la ejecución. La emisión demuestra que la CA autorizó un certificado. Los registros del servidor SSH y los registros de actividad del ejecutor demuestran dónde se utilizó una credencial y qué comando se ejecutó. Necesitas ambos cuando un operador pregunte si un certificado se emitió por error o se emitió correctamente pero se utilizó de forma indebida.

## Prueba la revocación como un ejercicio operativo cronometrado

Un manual que dice «revoca el certificado» está incompleto hasta que especifica los sistemas, archivos, permisos de acceso, fallo esperado y persona que puede actuar cuando el emisor no esté disponible. Realiza el ejercicio contra un destino que no sea de producción, con certificados reales y el mismo mecanismo de distribución que utilizas en producción.

Sigue esta secuencia:

1. Emite un certificado con un número de serie conocido y un intervalo corto documentado.
2. Autentícate una vez y registra el evento de aceptación del lado del servidor.
3. Desactiva la renovación para la sesión del agente asociada.
4. Añade el certificado a la KRL, distribúyela y recarga las instancias de sshd de destino.
5. Intenta una conexión SSH nueva y confirma que el servidor la rechaza. Después termina la sesión activa original si existe.

Mide el tiempo real desde la solicitud de contención hasta el rechazo en cada grupo de servidores. No publiques un objetivo que nunca hayas observado. La cifra depende de la rapidez con que tu sistema de configuración entregue la KRL y de la fiabilidad con la que recargue sshd.

Prueba también los casos incómodos. Revoca un certificado cuando no se pueda acceder a uno de los hosts de destino. Revócalo durante una conexión multiplexada existente. Revócalo mientras la máquina local está suspendida y la renovación no puede completarse. Revócalo después de que un operador haya aprobado una sesión, pero antes del primer comando. Cada resultado te indica si tus controles bloquean la emisión, la nueva autenticación o la ejecución activa. Son controles distintos, y llamar revocación a todos ellos crea suposiciones peligrosas.

Conserva las pruebas del ejercicio. Guarda el certificado emitido, la actualización de la KRL, el registro del ejecutor y el registro de rechazo del servidor de destino. Cuando ocurra un incidente real, ese conjunto ofrece a los responsables una ruta de comandos verificada, en lugar de un documento que se haya convertido con el tiempo en una ilusión.

## Mantén conectadas la aprobación, la auditoría y el acceso SSH

La aprobación humana solo sirve cuando se vincula al proceso que la utilizará. Aprobar un proceso en segundo plano sin identificarlo invita a aprobar algo equivocado. El revisor debe ver quién firmó el proceso, qué sesión está iniciando y si la credencial SSH solicitada tiene un alcance normal o sensible.

Sallyport guarda las credenciales SSH en su bóveda local cifrada y ejecuta SSH mediante su asistente integrado, de modo que un agente compatible con MCP no necesita tener la clave privada SSH en su propio entorno. Sus diarios de sesión y actividad pueden relacionar una aprobación humana con el proceso del agente y con los registros de acciones posteriores.

El registro de auditoría necesita pruebas de manipulación además de una consulta cómoda. Sallyport proyecta sus diarios desde un registro de auditoría cifrado y encadenado mediante hashes, y `sp audit verify` permite a un operador verificar esa cadena sin conexión y sin acceso a la bóveda. Ejecuta esta verificación durante la revisión de un incidente y al exportar pruebas. Una lista de actividades legible, por sí sola, no demuestra que nadie haya eliminado un evento incómodo.

No hagas responsable al sistema de auditoría de una política de acceso que no aplica. El servidor SSH debe seguir confiando en la CA correcta, aceptar solo las principales previstas, leer la KRL actual y restringir la cuenta de destino. El ejecutor local debe seguir protegiendo las credenciales privadas y solicitar las aprobaciones que hayas elegido. Los registros proporcionan pruebas y comentarios operativos. No corrigen una cuenta con permisos excesivos.

El mejor punto de partida no es reducir la duración del certificado. Haz un inventario de las acciones del agente que necesitan SSH, asigna a cada una una principal y una cuenta limitadas, coloca la credencial privada bajo custodia local y ensaya el proceso que detiene la emisión, distribuye la revocación y termina las sesiones activas. Cuando eso funcione, elige la duración de certificado más corta que tu sistema de renovación real pueda mantener.
