Certificados SSH: Una Guía Completa
Tengo rato pensando: "¿Qué más ahbrá en cunato a SSH y sus certificados, llaves y demás cosas?". El openssh tiene más que ofrecer, seguramente, que lo que usamos al día a día. Basta con echarte un clavado en los man pages del mismo y ver que así es.
La neta, son perros para manejar autenticación a escala, con expiración automática y políticas bien cabronas. En Fedora 43, con SELinux cuidándonos la espalda, es aún más seguro.
Esta guía completa es tu mapa (y el mío) para dominar los certificados SSH. Incluye comparaciones profundas, mejores prácticas de seguridad, tips de automatización y ejemplos extensos. Ya sea que estés asegurando un centro de datos o un laboratorio casero, esto te va a subir el nivel en cuanto a SSH se refiere.
Nota
Esta guía asume OpenSSH 7.0+ para soporte completo de certificados. Checa tu versión con ssh -V. Para producción, usa módulos de seguridad de hardware (HSM) para las llaves de CA.
Paralelos con SSH Estándar
SSH estándar con llaves de usuario:
- Flujo de trabajo: Los usuarios generan pares de llaves; los admins agregan manualmente las públicas a ~/.ssh/authorized_keys en cada servidor.
- Pros: Elimina contraseñas; criptografía fuerte; funciona offline.
- Contras: Pesadilla de escalabilidad; agregar/quitar usuarios requiere tocar cada servidor; no hay expiración automática ni restricciones; llaves comprometidas quedan hasta que se limpien manualmente; trazabilidad de auditoría limitada a logs.
SSH estándar con contraseñas:
- Flujo de trabajo: Los usuarios se autentican con contraseñas almacenadas en servidores (a menudo hasheadas).
- Pros: Configuración cero para usuarios; simple de implementar.
- Contras: Susceptible a ataques de fuerza bruta; las contraseñas débiles son comunes; no hay auditoría de logins exitosos; las contraseñas se pueden pezcar o reusar; los cambios de contraseña centralizados son propensos a errores.
Certificados SSH:
- Flujo de trabajo: CA firma llaves en credenciales portátiles y es rica en políticas.
- Mejor que llaves de usuario: Emisión/revocación centralizada; los certificados expiran automáticamente; opciones para restricciones de comando/IP; auditoría más fácil vía IDs de llaves y seriales.
- Mejor que contraseñas: Criptográficamente fuerte; sin secretos compartidos; soporta multi-factor (ej. con FIDO); amigable a la auditoría.
- Peor que ambos: Complejidad inicial de configuración de CA; llave privada de CA es un punto único de fallo (si se compromete, todos los certificados son inválidos; a rótarla inmediatamente); requiere soporte de OpenSSH; no es compatible con clientes/servidores SSH viejos.
En resumen, los certificados brillan para organizaciones que necesitan autenticación escalable y manejado con políticas. Para uso personal o despliegues pequeños, las llaves tradicionales suelen bastar.
Cómo Funcionan los Certificados SSH
Un certificado SSH es una extensión firmada por una llave pública, que contiene:
- Llave pública: La llave del usuario/host siendo certificada.
- ID de llave: Un identificador legible a humanos (ej. "juan@empresa").
- Principals: Usuarios permitidos (para certificados de usuario) o hostnames (para certificados de host).
- Opciones: Permisos/restricciones (por ejemplo. "no-port-forwarding").
- Período de validez: Fechas de inicio/fin para una expiración automática.
- Número serial: ID único para revocación.
- Firma de CA: Prueba autenticidad.
Los servidores checan la llave pública de la CA para verificar firmas, eliminando el almacenamiento por usuario de llaves. Los certificados son portátiles y auto-contenidos.
Prerrequisitos
- OpenSSH 7.0+ (los certificados fueron introducidos en la v5.4, pero lo acabaron hasta la v7.0). En Fedora 43, viene instalado por defecto (openssh-10.0p1-5.fc43.x86_64 al momento).
- Acceso a una máquina segura para operaciones de CA (idealmente offline).
- Conocimiento básico de generación de llaves SSH.
Consejo
En Fedora, SELinux puede prevenir el acceso de archivos de CA o certificados. Siempre checa contextos con ls -Z y ajústalo si es necesario.
Generando una llave de CA
La llave de CA es la base; su parte privada firma todos los certificados, así que protéjala fiéramente.
Elige un tipo de llave fuerte (ed25519 recomendado por velocidad/seguridad):
ssh-keygen -t ed25519 -f ca_key -C "SSH CA para ejemplo.tld"
Esto crea ca_key (privada; nunca la compartas) y ca_key.pub (pública; distribúyela entre los servidores y clients).
Para RSA (si ed25519 no está soportado):
ssh-keygen -t rsa -b 8192 -f ca_key -C "SSH CA para ejemplo.tld"
Importante
Respalda la llave privada de forma segura.
Creando Certificados de Usuario
Los certificados de usuario permiten a usuarios autenticarse en servidores sin agregar llaves individualmente. Vamos paso a paso, empezando con lo básico y agregando funcionalidad para hacerlo más seguro y flexible. Así es más fácil entender qué hace cada opción.
Paso 1: Certificado Básico
Primero, genera la llave del usuario si no tienes una:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "juan@ejemplo.tld"
Ahora, firma la llave pública con la CA para crear un certificado básico. La opción -s especifica la llave privada de la CA, -I es la identidad (un ID legible para identificar el cert), y -z es un número de serie único para evitar colisiones.
ssh-keygen -s ca_key -I "juan@ejemplo.tld" -z 1 ~/.ssh/id_ed25519.pub
Esto crea ~/.ssh/id_ed25519-cert.pub, un certificado válido para cualquier usuario en cualquier host que confíe en la CA. Básico pero funcional.
Opciones adicionales
Limitar Principals
Para más seguridad, limita el certificado a usuarios específicos con -n (principals). Esto evita que el certificado se use para logins no autorizados.
ssh-keygen -s ca_key -I "juan@ejemplo.tld" -n juan,respaldo -z 2 ~/.ssh/id_ed25519.pub
Ahora, solo "juan" o "respaldo" pueden usar este certificado para autenticarse. Útil para equipos compartidos.
Opción 2: Agregar Restricciones
Agrega opciones con -O para limitar qué puede hacer el usuario. Por ejemplo, no-port-forwarding bloquea túneles, no-agent-forwarding previene reenvío del agente SSH.
ssh-keygen -s ca_key -I "juan@ejemplo.tld" -n juan,respaldo -O no-port-forwarding -O no-agent-forwarding -z 3 ~/.ssh/id_ed25519.pub
Esto hace el certificado más seguro, previniendo abusos como port forwarding no autorizado.
Determinar Validez
Determina un período de validez con -V para que el certificado expire automáticamente. Usa formatos como +30d (30 días desde ahora) o fechas absolutas.
ssh-keygen -s ca_key -I "juan@ejemplo.tld" -n juan,respaldo -O no-port-forwarding -O no-agent-forwarding -V +30d -z 4 ~/.ssh/id_ed25519.pub
Ahora el certificado dura solo 30 días, forzando renovación periódica para mantener la seguridad.
Forzar un Comando
Para automatización (como backups), usa -O force-command para limitar el certificado a un comando específico. Ideal para scripts que no necesitan un shell completo.
ssh-keygen -s ca_key -I "respaldo@ejemplo.tld" -n respaldo -O force-command="/usr/bin/rsync --server --daemon" -V +1d -z 5 ~/.ssh/id_ed25519.pub
Este certificado solo permite rsync, nada más. Cambié el ID a "respaldo" para diferenciarlo.
Llaves basadas en hardware
Para llaves basadas en hardware, usa tokens PKCS#11 con -D (ruta a la lib):
ssh-keygen -s ca_key.pub -D /usr/lib/opensc-pkcs11.so -I "juan@ejemplo.tld" -z 6 ~/.ssh/id_ed25519.pub
O, para poner la CA en memoria con un ssh-agent, agrega la llave y usa -U:
ssh-add ca_key
ssh-keygen -Us ca_key.pub -I "juan@ejemplo.tld" -z 7 ~/.ssh/id_ed25519.pub
Estos son para despliegues más avanzados; no siempre necesarios.
Creando Certificados de Host
Los certificados de host prueban identidad de servidor a clients, previniendo ataques MitM.
Pasos (corre en cada host):
Genera llaves de host (si no están presentes; especifica tipo para evitar clutter):
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
Nota
Seguramente, esto lo hace tu distribución. En Fedora 43, lo hace un servicio llamado sshd-keygen, el cual corre siempre al iniciar y genera la llave de host si esta no existe. Te genera 3, de hecho.
Firma básica:
ssh-keygen -s ca_key -I "web01.ejemplo.tld" -h -z 1001 /etc/ssh/ssh_host_ed25519_key.pub
Output: /etc/ssh/ssh_host_ed25519_key-cert.pub.
Limita a los principals (hostnames e IPs para que sea más robusto):
ssh-keygen -s ca_key -I "web01.ejemplo.tld" -h -n web01.ejemplo.tld,web01,10.0.0.5 -z 1002 ~/.ssh/ssh_host_ed25519_key.pub
Determina la validez:
ssh-keygen -s ca_key -I "web01.ejemplo.tld" -h -V 20240101:20241231 -z 1003 /etc/ssh/ssh_host_ed25519_key.pub
Revocando Certificados
Usa "Key Revocation Lists (KRLs)" para invalidar certificados comprometidos. Siempre usa seriales únicos (-z) para una revocación efectiva.
Crea KRL (por archivo de certificado):
ssh-keygen -k -f revoked.krl ~/.ssh/id_ed25519-cert.pub
Actualiza KRL (agrega otro con el certificado):
ssh-keygen -k -u -f revoked.krl another-cert.pub
Revoca por Serial (no necesitas el certificado):
ssh-keygen -k -u -f revoked.krl -s ca_key -z 10
Distribuye KRL a servidores (ej. via config):
En /etc/ssh/sshd_config:
RevokedKeys /path/to/revoked.krl
Checa la revocación:
# Exit != 0 si fue revocado ssh-keygen -Q -f revoked.krl ~/.ssh/id_ed25519-cert.pub
Configurando Confianza
La confianza se configura para que servidores y clientes reconozcan la CA y verifiquen certificados. Sin esto, los certificados son papel mojado; el servdor rechaza logins porque no confía en la firma de la CA. La neta, es como darle una carta de recomendación a alguien que no conoce al firmante. Vamos por partes, compa, para que quede clarito.
Certificados de usuario (de lado del servidor)
Aquí, lo que te conviene es usar el método centralizado. Ya tienes a tus usuarios considerados en el certificado y solo hay que repartir la llave pública de la CA en todos los nodos. Esto es ideal para empresas o clusters grandes, porque evitas tocar archivos de cada usuario.
Pongo los otros métodos para que estés enterado nomás, por si los necesitas en setups pequeños.
Método Centralizado: Usa TrustedUserCAKeys en /etc/ssh/sshd_config para manejo centralizado. Esta directiva le dice a SSH que confíe en la CA para firmar certificados de usuario, sin necesidad de authorized_keys individuales.
TrustedUserCAKeys /etc/ssh/ca.pub
Luego pon la pubkey de CA en /etc/ssh/ca.pub. Distribúyela a todos los servers (ej. con scp o Ansible). Esto evita tocar archivos de usuario y simplifica revocaciones.
Método por usuario: Agrega a ~/.ssh/authorized_keys (útil para servers personales, pero no escala). La línea "cert-authority" indica que cualquier cert firmado por esa CA es válido para ese usuario.
echo "cert-authority $(cat ca_key.pub)" >> ~/.ssh/authorized_keys
Identidades Desacopladas: Usa AuthorizedPrincipalsFile en sshd_config para mapear principals de certificado a usuarios locales (ej. mapea "juan@corp" a "centos"). Los principals son como IDs en el cert que dicen quién eres, sin depender del username del sistema.
AuthorizedPrincipalsFile /etc/ssh/principals/%u
Crea /etc/ssh/principals/centos con:
juan@empresa pancho@empresa
Nota
Asegúrate que el dueño del archivo sea root:root con permisos 600 para prevenir escalamiento de privilegios. En Fedora, SELinux puede requerir contextos correctos (ej. restorecon -Rv /etc/ssh/principals). Esto permite cuentas compartidas sin authorized_keys per-user, pero checa que los principals matchen exactamente.
Para Certificados de Host (de lado del servidor)
Los certificados del host prueban la identidad del server al cliente. Configúralos agregando el path del certificado a sshd_config. SSH lo presentará automáticamente durante conexiones para evitar ataques MitM.
Agrega el path del certificado a /etc/ssh/sshd_config:
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
De lado del cliente:
El cliente también necesita confiar en la CA para verificar certificados.
Para los certificados del host: Agrega la CA a ~/.ssh/known_hosts o /etc/ssh/ssh_known_hosts. El patrón "@cert-authority" con wildcard (*.ejemplo.tld) confía en cualquier host en ese dominio si está firmado por la CA, previniendo spoofing.
echo "@cert-authority *.ejemplo.tld $(cat ca_key.pub)" >> ~/.ssh/known_hosts
Para certificados de usuario: SSH carga automáticamente los certificados si están nombrados de manera adecuada: id_ed25519-cert.pub al lado de la llave privada. Si usas ssh-agent, agrégalo con ssh-add para que esté disponible.
Reinicia servicios SSH después de hacer cambios: systemctl reload sshd. Prueba con ssh -v user@host para ver si la confianza funciona.
Ejemplos
Ejemplo 1: Certificado de Usuario Básico
Escenario: Acceso estándar de usuario.
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 ssh-keygen -s ca_key -I "pancho@empresa" -z 10 ~/.ssh/id_ed25519.pub # Distribuye ca_key.pub a servidores # Login: ssh pancho@servidor
Ejemplo 2: Usuario de Backup Restringido
Escenario: Rsync automatizado con límites de IP/comando. (Nota: source-address puede ser frágil en entornos cloud dinámicos.)
ssh-keygen -s ca_key -I "respaldo@servidor" -n respaldo -O force-command="/usr/bin/rsync --server" -O source-address="10.0.0.0/8" -V +1d -z 11 ~/.ssh/id_ed25519.pub
Ejemplo 3: Certificado de Host para Cluster
Escenario: Nodos de cluster seguros. (Flujo seguro: Trae llaves a máquina CA, firma localmente, despliega certificados.)
for host in node1 node2; do # Copia la llave de host a la máquina CA segura scp $host:/etc/ssh/ssh_host_ed25519_key.pub /tmp/$host.pub # Firma localmente con CA ssh-keygen -s ca_key -I "$host.cluster" -h -z 1004 /tmp/$host.pub # Despliega certificado de vuelta scp /tmp/$host-cert.pub $host:/etc/ssh/ssh_host_ed25519_key-cert.pub done # Los clientes agregan @cert-authority a known_hosts
Ejemplo 4: Certificado de Usuario FIDO
Escenario: Llaves por hardware.
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk ssh-keygen -s ca_key -I "juan@fido" -z 12 ~/.ssh/id_ecdsa_sk.pub
Ejemplo 5: Certificado con Extensiones
Escenario: Opciones custom.
ssh-keygen -s ca_key -I "dev@team" -O critical:source-address="192.168.1.0/24" -O extension:permit-pty -z 13 ~/.ssh/id_ed25519.pub
Ejemplo 6: Inspeccionando Certificados
Ver detalles:
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
Ejemplo 7: Revocando un Certificado
Agrega a KRL y despliega:
ssh-keygen -k -u -f revoked.krl ~/.ssh/id_ed25519-cert.pub scp revoked.krl server:/etc/ssh/
Mejores Prácticas y Consideraciones de Seguridad
Seguridad de la llave privada del CA: Guarda la llave privada del CA en algún lugar seguro. Nunca las uses en servidores de producción. Rota las CAs anualmente o en caso de compromiso; usa una CA dual: Agrega ambas partes públicas de las llaves de la CA vieja y nueva a TrustedUserCAKeys durante transición para evitar lockouts.
Períodos de Validez: Usa ciclos de vida cortos (días/semanas) para certificados de usuario y más largos para los hosts (meses/años). Automatiza la renovación.
Auditoría: Log uso de certificados via sshd; monitorea anomalías.
Integración: Automatiza con Ansible o Chafánsible la distribución de certificados. Un rol de ejemplo con Ansible:
- name: Despliega llave pública del CA copy: content: "{{ ca_pub_key }}" dest: /etc/ssh/ca.pub notify: reload sshd
Evita errores comunes: No firmes certificados con opciones débiles; prueba la revocación; usa ed25519.
Automatización y Escalado
Para despliegues grandes, evita exponer llaves privadas del CA. Usa herramientas seguras:
Firmado manual con script (solo en máquina CA segura):
#!/usr/bin/bash # ssh-signer.bash - Corre en la máquina con el CA user=$1 key=$2 serial=$( date +%s%N ) # Serial único basado en timestamp ssh-keygen -s ca_key -I "$user" -V +7d -O no-port-forwarding -z "$serial" "$key"
Certificados de Host en bola: Para inicializar, usa OpenTofu para injectar la llave pública del CA. Para sconfigurarlo manualmente:
serial=$( date +%s%N ) # Serial único basado en timestamp for host in $(cat hosts.txt); do scp $host:/etc/ssh/ssh_host_ed25519_key.pub /tmp/$host.pub ssh-keygen -s ca_key -I "$host" -h -z $serial /tmp/$host.pub scp /tmp/$host-cert.pub $host:/etc/ssh/ssh_host_ed25519_key-cert.pub done
Monitoreo: Usa ssh-audit o scripts custom para verificar certificados.
Conclusión
Los certificados SSH lo transforman de un protocolo simple en un sistema de autenticación robusto. Centralizando confianza y habilitando políticas, se ofrece escalabilidad y seguridad sin par. Empieza en chiquito, prueba con un usuario/host; luego escala. Recuerda, la CA es tu joya de la corona; protéjala.
RTFM!
- man ssh-keygen
- man sshd_config
- docs oficiales de OpenSSH: https://www.openssh.org/manual.html
- RFC 4251: https://datatracker.ietf.org/doc/html/rfc4251
Contribuye mejoras en:
https://github.com/openssh/openssh-portable
¡Chido, ahora ve y securiza tus despliegues!