# Credenciales SSH separadas para acceder a producción de forma más segura

Una sola credencial SSH que permite llegar a desarrollo, staging y producción convierte una pequeña comodidad en una autoridad remota muy amplia. También vuelve poco honestas las aprobaciones: alguien puede aprobar una tarea de staging que parece inofensiva, aunque esa misma credencial pueda abrir una sesión de producción unos minutos después.

Separa las credenciales SSH por clase de sistema y por nivel de riesgo. Después, haz visible la separación en la configuración del cliente, aplícala en los servidores y prueba las rutas denegadas con la misma seriedad que las permitidas. He visto equipos llamar a esto control de acceso cuando solo habían dado tres nombres a una clave en `~/.ssh/config`; eso no es un límite.

## Una credencial crea un único dominio de fallo

Una credencial compartida entre varias clases de entorno concede a cada usuario la combinación de privilegios de esas clases. Si la estación de trabajo de un ingeniero, una tarea automatizada o una ruta de aprobación puede usarla, el compromiso de una sola de esas vías llega al entorno más elevado que acepte la clave pública.

La defensa habitual es que las mismas personas administran todos los entornos. Eso no toca el punto central. Las personas pueden coincidir, pero las situaciones no. El trabajo de desarrollo suele incluir scripts no revisados, datos de prueba, máquinas temporales y experimentación amplia. El trabajo de producción debería admitir menos procesos, exigir una revisión más cuidadosa y dejar un registro claro de quién se conectó y por qué.

Por eso una sola credencial con alias de host distintos tampoco sirve de nada. Estas entradas parecen ordenadas:

```sshconfig
Host dev-db
  HostName dev-db.internal

Host prod-db
  HostName prod-db.internal
```

Pero si ambos hosts aceptan la misma clave pública SSH, cualquiera de los dos alias puede autenticarse con la misma clave privada. Un error tipográfico en una variable de automatización o un comando copiado puede cruzar el límite sin ninguna decisión de autorización nueva.

Las credenciales separadas cambian el resultado. Una credencial de desarrollo robada debería fallar en staging y producción. Un proceso aprobado para usar una credencial de staging no debería tener material privado ni capacidad de firma que le permita autenticarse en producción. Son controles diferentes. El primero limita el alcance de una intrusión. El segundo impide que un proceso legítimo, pero demasiado amplio, haga algo indebido.

No confundas esto con rotar contraseñas. La rotación sustituye una credencial con el tiempo. La segregación decide dónde puede funcionar una credencial. Necesitas ambas, pero la rotación no puede reparar una credencial que se aceptaba deliberadamente en todas partes.

## Los nombres de los entornos no bastan como límites

Desarrollo, staging y producción son etiquetas útiles solo cuando corresponden a decisiones de confianza diferentes. Un host llamado `staging` puede contener datos parecidos a los de producción, enviar correos reales, guardar un secreto de firma o conectarse a un endpoint de pagos activo. Del mismo modo, un host de monitorización de producción puede necesitar menos autoridad que un administrador de bases de datos de staging.

Clasifica el acceso SSH por el efecto de una sesión, no por el prefijo del nombre del host. Normalmente empiezo con cuatro preguntas:

- ¿Puede esta cuenta leer datos de clientes o datos regulados?
- ¿Puede modificar un servicio activo, un despliegue, un firewall o un registro DNS?
- ¿Puede recuperar otra credencial o suplantar a otro servicio?
- ¿Puede moverse lateralmente hacia sistemas con más autoridad?

Si la respuesta cambia entre hosts, el alcance de la credencial también debería cambiar. Esto suele producir grupos más útiles que el modelo conocido de tres entornos: desarrollo de aplicaciones, sistemas de prueba con datos sensibles, hosts de lanzamiento, diagnóstico de producción en modo solo lectura y administración de producción.

Una cuenta Unix separada también suele formar parte del diseño. Una cuenta llamada `deploy` puede ser propietaria del directorio de lanzamientos y aceptar un comando restringido. Una cuenta llamada `ops-read` puede consultar registros sin editar unidades de servicio. Una cuenta llamada `admin` puede realizar tareas de mantenimiento con un nivel de aprobación superior. Las cuentas separadas dan al servidor un lugar donde aplicar permisos y dan a los registros un sujeto claro.

No dejes que los nombres de cuenta distintos te hagan aceptar una credencial compartida. Si la misma clave pública aparece bajo `dev`, `deploy` y `admin` en máquinas diferentes, la clave privada sigue siendo una credencial que cruza entornos. Las cuentas separadas y las credenciales separadas resuelven partes distintas del problema.

## Da a cada persona y proceso su propia identidad

Cada operador humano y cada proceso de automatización necesita una identidad SSH distinta dentro de la clase de entorno que tiene permitida. Una clave privada compartida por todo el equipo ralentiza la respuesta ante incidentes, porque revocar el acceso de una persona implica sustituirla para todos. También vuelve casi inútiles los registros cuando varias personas se autentican con la misma cuenta y la misma clave pública.

Para un operador humano, crea claves privadas distintas para los ámbitos permitidos. Usa nombres que indiquen el ámbito, no nombres vagos como `id_ed25519_new` o `server-key-final`.

```sh
mkdir -p ~/.ssh/identities
chmod 700 ~/.ssh/identities

ssh-keygen -t ed25519 \\
  -f ~/.ssh/identities/id_ed25519_dev_alex \\
  -C dev-alex

ssh-keygen -t ed25519 \\
  -f ~/.ssh/identities/id_ed25519_stage_alex \\
  -C stage-alex

ssh-keygen -t ed25519 \\
  -f ~/.ssh/identities/id_ed25519_prod_alex \\
  -C prod-alex
```

El comentario ayuda a las personas a revisar una lista de claves públicas, pero no impone nada. El servidor decide el acceso a partir de la clave pública, la cuenta y las reglas de autorización. Trata los comentarios como etiquetas para los operadores, no como metadatos de seguridad.

La automatización merece la misma disciplina. Un trabajo de lanzamiento debería usar una credencial emitida para ese trabajo y ese entorno, no la identidad de producción de un ingeniero copiada en un almacén de secretos. Si varios trabajos necesitan acceso, dales identidades separadas salvo que tengan el mismo responsable, el mismo conjunto de destinos y la misma autoridad de comandos. Una credencial debería responder a una pregunta sencilla durante una revisión posterior a un incidente: ¿qué proceso la usó?

Las credenciales respaldadas por hardware pueden dificultar el robo de un archivo de clave privada, pero no reparan un diseño de autorización demasiado amplio. Una credencial respaldada por hardware que todos los entornos aceptan sigue concediendo acceso a todos ellos. Define primero el alcance y después elige cómo proteger cada clave privada.

## La configuración del cliente debe impedir que las identidades se mezclen

OpenSSH probará las identidades de la configuración y, salvo que lo limites, las identidades ofrecidas por un agente SSH. Ese comportamiento resulta cómodo hasta que un agente contiene una identidad de producción y una conexión destinada a staging funciona con ella.

El manual de `ssh_config` de OpenSSH describe `IdentitiesOnly` como un control que limita las identidades usadas para la autenticación mediante clave pública a los archivos de identidad y certificados configurados, incluso cuando un agente contiene otras identidades. Actívalo para cada alias de host con alcance definido. Da a cada alias un único archivo de identidad explícito y no dependas del orden en que el agente decida ofrecer las claves.

```sshconfig
Host dev-*
  User devops
  IdentityFile ~/.ssh/identities/id_ed25519_dev_alex
  IdentitiesOnly yes
  ForwardAgent no

Host stage-*
  User release
  IdentityFile ~/.ssh/identities/id_ed25519_stage_alex
  IdentitiesOnly yes
  ForwardAgent no

Host prod-*
  User admin
  IdentityFile ~/.ssh/identities/id_ed25519_prod_alex
  IdentitiesOnly yes
  ForwardAgent no
```

Usa alias que hagan difícil pasar por alto el entorno en el historial de la terminal. Por ejemplo, `prod-api-01` es mejor que `api-01` cuando desarrollo y producción tienen hosts de API con nombres parecidos. No ocultes el destino detrás de un alias genérico como `server`.

Comprueba la configuración final que usará OpenSSH. Esto detecta colisiones entre comodines, archivos incluidos y ajustes globales olvidados.

```sh
ssh -G prod-api-01 | grep -E '^(hostname|user|identityfile|identitiesonly|forwardagent) '
```

La salida debería tener este aspecto:

```text
hostname prod-api-01.internal
user admin
identitiesonly yes
forwardagent no
identityfile ~/.ssh/identities/id_ed25519_prod_alex
```

La ruta puede expandirse de otra manera en tu máquina. Lo importante es que el alias de producción resuelva únicamente a la identidad de producción y que `identitiesonly` indique `yes`.

Un fallo frecuente aparece después de que alguien ejecuta `ssh-add` por comodidad. El agente ahora contiene varias identidades. Sin `IdentitiesOnly yes`, el cliente las prueba contra un host hasta que una funciona. Los servidores suelen limitar los intentos de autenticación, así que esto puede causar fallos confusos. Peor aún, una credencial amplia puede hacer que la conexión funcione silenciosamente y el operador quizá nunca se dé cuenta de que usó el alcance equivocado.

## La autorización del servidor debe reflejar la separación

Las claves privadas separadas solo funcionan cuando cada servidor acepta la clave pública correspondiente y rechaza las demás. Coloca la clave pública de desarrollo en los hosts de desarrollo, la de staging en los hosts de staging y la de producción solo donde se pretenda permitir el acceso a producción.

La regla parece obvia, pero el patrón incorrecto es común durante una configuración urgente: alguien copia un archivo `authorized_keys` completo a un host nuevo. Ese archivo suele contener años de identidades obsoletas, antiguos contratistas, claves de despliegue y una clave de administrador general. El nuevo host de producción hereda decisiones de acceso que nadie revisó.

Construye la lista de autorizaciones de cada cuenta a partir de su función. Para una cuenta de despliegue, usa restricciones de OpenSSH adecuadas para una transferencia no interactiva o una operación de lanzamiento. El manual `authorized_keys` de OpenSSH documenta la opción `restrict`, que desactiva el reenvío de puertos, el reenvío del agente, el reenvío X11 y la asignación de PTY, salvo que otra opción los permita. Una entrada de despliegue restringida puede tener este aspecto:

```text
restrict,from="198.51.100.0/24" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... prod-release-job
```

Sustituye la red de ejemplo por un rango de direcciones que controles realmente. No añadas `from=` solo porque parezca estricto. Si el trabajo se origina desde direcciones cambiantes o desde un conjunto de runners alojados, una restricción de origen incorrecta provoca una interrupción y anima a alguien a eliminar todas las restricciones bajo presión.

Usa comandos forzados únicamente para automatizaciones definidas de forma muy precisa. Un comando forzado puede impedir que una credencial de despliegue obtenga un shell, pero también se convierte en un contrato de mantenimiento. El comando debe validar sus entradas, elegir las rutas de forma segura y registrar la solicitud. No apliques un comando forzado a una cuenta de administrador y supongas que la cuenta es segura; tarde o temprano alguien necesitará un shell y buscará una forma de evitarlo.

Para la administración humana de producción, una cuenta separada junto con una clave pública separada suele ser más clara que unas opciones elaboradas en `authorized_keys`. Restringe la cuenta mediante los permisos normales del host, registra su actividad de sudo cuando corresponda y elimina la clave pública cuando la persona ya no necesite acceso.

## Los certificados SSH solo ayudan cuando sus afirmaciones son limitadas

Los certificados de OpenSSH pueden facilitar la emisión y la revocación operativa de accesos de corta duración. Una autoridad certificadora firma la clave pública de un usuario y los servidores confían en la autoridad en lugar de almacenar cada clave pública individual. Esto puede reducir el trabajo necesario para actualizar grandes flotas.

No eliminan la necesidad de separar las autoridades. Un certificado con un principal de producción no debería conceder también acceso a desarrollo y staging solo porque un operador trabaje en los tres entornos. Emite certificados distintos, usa principales diferentes o emplea autoridades certificadoras separadas cuando los límites administrativos y de riesgo lo justifiquen.

El protocolo de certificados de OpenSSH distingue entre certificados de usuario, principales, intervalos de validez y opciones críticas. Esta estructura solo resulta útil si el servidor comprueba los principales y mantienes limitadas las reglas de emisión. Un certificado válido para cualquier cuenta en cualquier host simplemente convierte una clave privada en una identidad de acceso ampliamente confiable con fecha de caducidad.

Los periodos de validez cortos ayudan con dispositivos perdidos y empleados que abandonan la organización, pero no sustituyen la revocación durante un incidente activo. Aún necesitas una forma de detener rápidamente la aceptación de una identidad comprometida o retirar su autorización. Planifica ese mecanismo antes de emitir certificados y pruébalo en un host real.

Los certificados tampoco resuelven el uso indebido del agente. Si un proceso automatizado puede obtener un certificado de producción cada vez que lo solicita, ese servicio de emisión es el límite de producción. Protégelo con el mismo cuidado que dedicarías a una clave privada de producción.

## El reenvío del agente cruza un límite que no puedes ver

El reenvío del agente SSH permite que un host remoto pida a tu agente local que firme desafíos de autenticación para otros hosts. La máquina remota no recibe la clave privada, pero un proceso que se ejecute con la cuenta remota puede usar el agente reenviado mientras la sesión permanezca abierta.

Esto hace que el reenvío sea especialmente peligroso en una sesión de producción que llega primero a un host de salto. Si el host de salto está comprometido o un proceso no confiable se ejecuta con esa cuenta, puede solicitar firmas de todas las identidades que ofrezca el agente reenviado. El resultado puede ser un acceso lateral que tu plan de conexión original nunca contempló.

Mantén este valor predeterminado en la configuración del cliente:

```sshconfig
Host *
  ForwardAgent no
```

Después, crea una única excepción explícita solo cuando un flujo de trabajo mantenido la necesite. Antes de añadirla, pregúntate si `ProxyJump`, una credencial dedicada para el bastión o una operación realizada localmente eliminarían la necesidad. `ProxyJump` transporta la conexión SSH a través de un host intermedio; no expone tu agente local a ese host de la misma manera.

No aceptes la afirmación de que el reenvío es seguro porque la clave privada permanece en el portátil. Un oráculo de firma puede bastar para autenticarse en otro lugar. La diferencia importa durante un compromiso: proteger un archivo no equivale a limitar qué puede usar la credencial.

## El alcance de la aprobación debe coincidir con el de la credencial

Una aprobación que autoriza a un proceso nuevo a usar una credencial SSH debería identificar el entorno de la credencial y el proceso que la solicitó. Un aviso que solo diga `ssh command requested` obliga a una persona a deducir demasiado a partir de muy poca información.

Aquí es donde los equipos suelen confundir dos controles. El alcance de la credencial responde dónde puede autenticarse una identidad. El alcance de la aprobación responde qué proceso en ejecución puede usar esa identidad. Necesitas ambos. Las credenciales de producción separadas impiden que un proceso de desarrollo llegue por accidente a producción; la aprobación del proceso impide que un proceso local desconocido use una credencial de producción disponible.

La aprobación por comando parece más segura y muchas personas la piden después de un incidente incómodo. Normalmente falla durante el mantenimiento habitual, porque los avisos repetidos acostumbran a los operadores a aprobar sin leer. Reserva la confirmación de cada uso para credenciales cuyo uso requiera una decisión humana, como una identidad administrativa de producción de alto impacto. Para el trabajo normal, usa una autorización de sesión que termine cuando el proceso salga y mantén limitado el alcance de la credencial en el servidor.

Sallyport mantiene las credenciales SSH en su almacén cifrado y puede exigir autorización para un proceso de agente nuevo o aprobación en cada uso de una credencial seleccionada. Esto no sustituye la autorización separada del servidor, pero hace explícito el límite del proceso sin entregar la credencial al agente.

Un agente de programación de IA merece una separación más estricta que una terminal interactiva, porque puede ejecutar muchos comandos rápidamente y seguir una instrucción incorrecta. Dale acceso de desarrollo de forma predeterminada. Si necesita staging, usa una identidad exclusiva de staging y una ejecución aprobada por separado. Trata el acceso a producción como una operación distinta, con un destino identificado y un propósito limitado.

## El fallo suele empezar con una excepción inofensiva

Imagina un equipo con una sola clave SSH `ops` aceptada por hosts de desarrollo, staging y producción. Un ingeniero carga esa clave en un agente SSH para una ventana de mantenimiento de producción. Más tarde, un asistente local de compilación abre una conexión SSH a un host de staging para recopilar registros.

El asistente no tiene un ajuste `IdentityFile` explícito y `IdentitiesOnly` está ausente. OpenSSH prueba las identidades del agente. La clave compartida `ops` funciona porque staging la acepta. El asistente ahora tiene una sesión de staging autenticada con una identidad que también funciona en producción.

Después llega un segundo error. El host de staging tiene activado el reenvío del agente porque alguien necesitó una conexión puntual el mes pasado. Un proceso de ese host puede solicitar firmas a través del agente reenviado. Llega a un host de producción con la misma identidad `ops`. El ingeniero original aprobó una sesión de mantenimiento de producción, pero un asistente no relacionado y un host de staging heredaron su autoridad.

En esta secuencia no hace falta que se filtre ninguna clave privada. El diseño permitía una identidad amplia, el cliente la seleccionó de forma oportunista y el reenvío amplió su alcance. Los registros pueden mostrar una autenticación válida durante todo el recorrido, por lo que los equipos lo etiquetan erróneamente como un error del usuario en lugar de corregir el modelo de acceso.

Un diseño separado rompe la cadena en varios puntos. El asistente usa solo una credencial de staging. Producción rechaza esa credencial. El reenvío del agente permanece desactivado. La identidad de producción solo está disponible para un proceso de producción aprobado explícitamente. Cualquiera de estos controles ayuda; juntos hacen que la conexión incorrecta falle pronto.

## La rotación y la revocación de emergencia necesitan un orden practicado

La rotación funciona cuando añades un reemplazo antes de retirar la identidad antigua, verificas la ruta exacta y después revocas la anterior. Las rotaciones de producción fallan cuando alguien prueba solo desde su portátil, mientras que el desplegador real se conecta desde otra cuenta, red o runner de automatización.

Para una rotación normal, sigue este orden:

1. Crea una credencial de reemplazo con el mismo alcance limitado que la antigua.
2. Añade su clave pública o la autorización de su certificado a la cuenta y los hosts previstos.
3. Prueba el comando real desde la ruta real del proceso, incluido cualquier host de salto.
4. Elimina la autorización antigua y confirma que la credencial anterior ahora falla.
5. Registra la huella digital del reemplazo, su responsable, alcance y fecha de retirada en el registro de acceso.

Mantén una ruta de emergencia, pero no la conviertas en una segunda credencial de administrador permanente copiada en todas las estaciones de trabajo. Guárdala por separado, limita quién puede activarla y pruébala en condiciones controladas. Un proceso de emergencia que nadie ha practicado se convierte en un ejercicio de adivinación durante una interrupción.

La revocación de emergencia es diferente. Si una credencial de producción puede haberse expuesto, elimina inmediatamente su clave pública o deja de aceptar su certificado y después reemplázala. No esperes a la ventana de rotación programada, porque un atacante no respetará tu calendario. El coste es una posible interrupción operativa, por eso las credenciales limitadas son tan útiles: revocar una identidad de despliegue de producción no debería detener el trabajo de desarrollo.

## Prueba el acceso denegado y revisa las pruebas

La separación del acceso solo está completa cuando la credencial incorrecta falla de una manera que puedes explicar. Después de cada cambio importante, realiza una prueba negativa intencionada: usa la identidad de desarrollo contra un host de producción y verifica que la autenticación mediante clave pública falla. Después prueba la credencial esperada e inspecciona el nombre de la cuenta y el destino en el registro de conexión.

Usa la salida detallada del cliente durante las pruebas, no como una práctica permanente:

```sh
ssh -vvv -o IdentitiesOnly=yes \\
  -i ~/.ssh/identities/id_ed25519_dev_alex \\
  admin@prod-api-01.internal
```

Deberías ver que el cliente ofrece la clave pública de desarrollo y que el servidor la rechaza. No pegues esta salida en tickets sin revisarla antes; los registros detallados de SSH pueden revelar nombres de host, nombres de usuario y datos de autenticación.

Los registros del servidor deberían permitirte responder quién se autenticó, qué cuenta utilizó, qué huella de clave pública aceptó el servidor y desde dónde se originó la conexión. Si varias personas o procesos comparten una identidad, el registro no podrá recuperar después esa atribución perdida.

Revisa la deriva de los límites: una clave de desarrollo añadida a una cuenta de producción, una credencial de despliegue antigua que todavía se acepta, una clave de producción cargada en un agente de uso general o una regla de cliente con comodines que anule `IdentitiesOnly`. Estos cambios suelen llegar como soluciones temporales. El acceso SSH temporal tiende a sobrevivir mucho después de que desaparezca la emergencia que lo creó.

Empieza inventariando todas las claves públicas aceptadas en los hosts de producción y etiqueta cada una según su responsable, proceso, propósito y alcance. Cualquier entrada que no pueda superar esa descripción en cuatro partes no debería seguir autorizada.
