Seguridad en servidores SSH: endurecimiento con claves Ed25519 y fail2ban
Introducci贸n
SSH (Secure Shell) es la puerta de entrada principal a cualquier servidor Linux moderno. Su omnipresencia lo convierte en el vector de ataque m谩s explotado en infraestructuras cloud y on-premise. Un servidor SSH mal configurado es una invitaci贸n abierta a ataques de fuerza bruta, exploits de protocolo y escalada de privilegios. Este art铆culo aborda dos pilares fundamentales para el endurecimiento de SSH: la adopci贸n de claves Ed25519 como est谩ndar criptogr谩fico y la implementaci贸n de fail2ban como sistema de defensa proactivo contra intrusiones automatizadas.
Abordaremos la configuraci贸n desde cero, explicando la l贸gica subyacente de cada decisi贸n t茅cnica, incluyendo la desactivaci贸n de m茅todos obsoletos, la rotaci贸n de claves y la integraci贸n con sistemas de logging centralizado.
Fundamentos de Seguridad en SSH
El problema de la autenticaci贸n por contrase帽a
La autenticaci贸n mediante contrase帽a es inherentemente d茅bil por varias razones:
- Factor humano: contrase帽as d茅biles, reutilizadas o almacenadas incorrectamente.
- Ataques automatizados: bots que prueban combinaciones comunes a raz贸n de miles por minuto.
- Ausencia de trazabilidad: es dif铆cil auditar qui茅n accedi贸 con qu茅 credencial.
- Sin resistencia a fuerza bruta distribuida: m煤ltiples IPs atacando simult谩neamente.
La soluci贸n definitiva es la autenticaci贸n basada en clave p煤blica/privada, combinada con la desactivaci贸n total de la autenticaci贸n por contrase帽a.
Criptograf铆a asim茅trica moderna: RSA vs Ed25519
Durante a帽os, RSA fue el est谩ndar de facto. Sin embargo, presenta limitaciones que lo hacen menos 贸ptimo en entornos modernos:
| Caracter铆stica | RSA (2048/4096 bits) | Ed25519 |
|---|---|---|
| Algoritmo | Factorizaci贸n de primos | Curva el铆ptica (Curve25519) |
| Tama帽o de clave privada | ~1.7 KB (4096 bits) | 64 bytes |
| Velocidad de generaci贸n | Lenta (minutos en sistemas embebidos) | Instant谩nea |
| Resistencia cu谩ntica | Baja (quiebra con Shor) | Mejor (aunque no completamente segura) |
| Compatibilidad | Universal (OpenSSH 2.0+) | OpenSSH 6.5+ |
| Firma | Tama帽o fijo (512 bytes) | Tama帽o fijo (64 bytes) |
Ed25519 ofrece seguridad equivalente a RSA 4096 bits con un rendimiento superior y menor huella de almacenamiento. Adem谩s, su implementaci贸n es resistente a ataques de canal lateral, un factor cr铆tico en entornos cloud compartidos.
Paso 1: Generaci贸n de claves Ed25519
En el cliente (m谩quina local)
# Generar par de claves Ed25519
ssh-keygen -t ed25519 -a 100 -C "admin@servidor-produccion-$(date +%Y%m%d)"
# Opciones explicadas:
# -t ed25519: tipo de clave
# -a 100: n煤mero de rondas KDF (funci贸n de derivaci贸n de clave).
# 100 es un balance entre seguridad y rendimiento.
# -C: comentario descriptivo para identificar la clave
# Verificar la clave generada
ls -la ~/.ssh/id_ed25519*
Nota t茅cnica: El par谩metro
-acontrola las iteraciones del algoritmo bcrypt usado para proteger la clave privada con contrase帽a. Valores m谩s altos (100-1000) aumentan la resistencia contra ataques de fuerza bruta offline, a costa de tiempo de desbloqueo. Para servidores de alta criticidad, considere-a 200.
Configuraci贸n de passphrase obligatoria
# Si olvid贸 establecer passphrase durante la generaci贸n:
ssh-keygen -p -f ~/.ssh/id_ed25519
La passphrase protege la clave privada en reposo. Sin ella, cualquiera con acceso al archivo puede autenticarse. En entornos CI/CD, use agentes SSH con expiraci贸n forzada.
Paso 2: Configuraci贸n del servidor SSH
Copia segura de la clave p煤blica
# M茅todo recomendado: copia manual verificada
cat ~/.ssh/id_ed25519.pub | ssh usuario@servidor "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh"
# Alternativa autom谩tica (solo si conf铆a en la integridad del canal):
ssh-copy-id -i ~/.ssh/id_ed25519.pub usuario@servidor
Hardening de /etc/ssh/sshd_config
A continuaci贸n, la configuraci贸n m铆nima para un servidor SSH endurecido:
# Respaldo de la configuraci贸n original
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d)
# Editar con privilegios
sudo nano /etc/ssh/sshd_config
Contenido cr铆tico a establecer:
# Deshabilitar autenticaci贸n por contrase帽a
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
# Forzar solo claves Ed25519 (deshabilitar RSA, DSA, ECDSA)
HostKeyAlgorithms ssh-ed25519
PubkeyAcceptedAlgorithms ssh-ed25519
KexAlgorithms curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com
# Restricciones de acceso
PermitRootLogin prohibit-password
MaxAuthTries 3
MaxSessions 5
ClientAliveInterval 300
ClientAliveCountMax 2
# Logging avanzado
LogLevel VERBOSE
SyslogFacility AUTH
Explicaci贸n de cada directiva:
PasswordAuthentication no: elimina el vector m谩s com煤n de ataque.UsePAM no: evita vulnerabilidades en m贸dulos PAM (ej: CVE-2024-3094 en xz).HostKeyAlgorithms ssh-ed25519: solo acepta claves de host Ed25519.KexAlgorithms curve25519-sha256@libssh.org: intercambio de claves seguro contra ataques de downgrade.Ciphers chacha20-poly1305@openssh.com: cifrado autenticado con rendimiento superior en CPU sin AES-NI.MACs hmac-sha2-512-etm@openssh.com: MAC Encrypt-then-MAC que previene ataques de padding oracle.PermitRootLogin prohibit-password: permite root solo con clave, nunca con contrase帽a.MaxAuthTries 3: limita intentos de autenticaci贸n antes de desconexi贸n.LogLevel VERBOSE: registra huellas dactilares de claves para auditor铆a forense.
Verificaci贸n de sintaxis y reinicio
# Validar configuraci贸n antes de aplicar
sudo sshd -t
# Si no hay errores, reiniciar servicio
sudo systemctl restart sshd
# Verificar que el servicio est谩 escuchando
sudo ss -tlnp | grep :22
Paso 3: Implementaci贸n de fail2ban
fail2ban es un sistema de prevenci贸n de intrusiones que analiza logs y bloquea IPs maliciosas mediante reglas de iptables/nftables.
Instalaci贸n
# Debian/Ubuntu
sudo apt update && sudo apt install fail2ban -y
# RHEL/CentOS 8+
sudo dnf install epel-release -y
sudo dnf install fail2ban -y
# Verificar instalaci贸n
fail2ban-client --version
Configuraci贸n base
Crear archivo de configuraci贸n local (nunca modificar el archivo original jail.conf):
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Configuraci贸n global optimizada:
[DEFAULT]
# Tiempo de baneo: 1 hora (3600 segundos)
bantime = 3600
# Ventana de tiempo para contar fallos: 10 minutos
findtime = 600
# N煤mero m谩ximo de fallos antes del baneo
maxretry = 5
# Ignorar IPs internas y de confianza
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
# Acci贸n de baneo (usando nftables si est谩 disponible)
banaction = nftables-multiport
banaction_allports = nftables-allports
# Notificaciones por correo (opcional, requiere MTA configurado)
action = %(action_mwl)s
Jail espec铆fico para SSH
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400 # 24 horas para SSH
findtime = 300 # 5 minutos
Importante: En sistemas que usan journald (systemd), la ruta de log puede ser diferente. Use
journalctl -u sshdpara verificar. En ese caso, configure:logpath = %(journalctl)s backend = systemd
Filtros personalizados para ataques avanzados
Crear filtro para detectar escaneo de puertos no est谩ndar:
sudo nano /etc/fail2ban/filter.d/sshd-portscan.conf
Contenido:
[Definition]
failregex = ^%(__prefix_line)sFailed password for .* from <HOST> port \d+ ssh2$
^%(__prefix_line)sConnection closed by authenticating user .* <HOST> port \d+ \[preauth\]$
ignoreregex =
Paso 4: Configuraci贸n avanzada del cliente SSH
Archivo ~/.ssh/config optimizado
# Configuraci贸n global
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
Compression yes
CompressionLevel 6
ControlMaster auto
ControlPath ~/.ssh/controlmasters/%r@%h:%p
ControlPersist 10m
# Host espec铆fico de producci贸n
Host servidor-prod
HostName 203.0.113.50
User admin
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
AddKeysToAgent yes
ForwardAgent no
PermitLocalCommand no
Explicaci贸n:
ControlMaster auto: reutiliza conexiones SSH existentes (ahorra handshakes).ControlPersist 10m: mantiene el socket maestro 10 minutos tras cerrar sesi贸n.ForwardAgent no: previene forwarding de agente (riesgo de seguridad en hosts comprometidos).IdentitiesOnly yes: fuerza usar solo la clave especificada, no todas las del agente.
Agente SSH con timeout forzado
# Iniciar agente con expiraci贸n
eval $(ssh-agent -t 3600) # expira en 1 hora
# Agregar clave con confirmaci贸n requerida
ssh-add -t 3600 -c ~/.ssh/id_ed25519
El flag -c requiere confirmaci贸n del usuario antes de usar la clave, previniendo uso no autorizado por scripts maliciosos.
Paso 5: Monitoreo y respuesta a incidentes
Logs de autenticaci贸n
# Ver intentos de conexi贸n fallidos en tiempo real
sudo journalctl -u sshd -f | grep -E "Failed password|Connection closed"
# Estad铆sticas de ataques por IP
sudo journalctl -u sshd | grep "Failed password" | awk '{print $11}' | sort | uniq -c | sort -nr | head -10
Integraci贸n con sistemas SIEM
Para entornos empresariales, configure fail2ban para enviar alertas a un SIEM via syslog:
sudo nano /etc/fail2ban/action.d/sendmail-siem.conf
[Definition]
actionban = logger -p auth.warning -t fail2ban "Banned IP: <ip> for service <name>"
actionunban = logger -p auth.notice -t fail2ban "Unbanned IP: <ip> for service <name>"
Rotaci贸n y expiraci贸n de claves
Implemente rotaci贸n autom谩tica de claves usando cron:
# Script de rotaci贸n (ejecutar mensualmente)
#!/bin/bash
# /usr/local/bin/rotate-ssh-keys.sh
BACKUP_DIR="/root/ssh-key-backup/$(date +%Y%m)"
mkdir -p "$BACKUP_DIR"
# Backup de claves antiguas
cp /etc/ssh/ssh_host_ed25519_key* "$BACKUP_DIR"
# Generar nuevas claves de host
ssh-keygen -t ed25519 -a 100 -f /etc/ssh/ssh_host_ed25519_key -N ""
# Forzar regeneraci贸n de claves de usuario (requiere script personalizado)
# ...
systemctl restart sshd
Verificaci贸n y pruebas de penetraci贸n
Escaneo de configuraci贸n SSH
# Usar ssh-audit para evaluar la seguridad
pip install ssh-audit
ssh-audit servidor-prod
# Salida esperada:
# [info] CVE-2024-6387: Not vulnerable (OpenSSH 9.8p1)
# [info] Ciphers: chacha20-poly1305@openssh.com (200/100)
# [info] Kex: curve25519-sha256@libssh.org (200/100)
Prueba de fuerza bruta controlada
# Simular ataque con hydra (solo en entorno de pruebas)
hydra -l admin -P rockyou.txt -t 4 ssh://203.0.113.50
# Verificar que fail2ban bloquea tras 3 intentos
sudo fail2ban-client status sshd
# Status for the jail: sshd
# |- Filter
# | |- Currently failed: 0
# | |- Total failed: 3
# |- Actions
# |- Currently banned: 1
# |- Total banned: 1
Consideraciones finales y checklist de endurecimiento
| Componente | Acci贸n | Verificaci贸n |
|---|---|---|
| Claves | Generar Ed25519 con passphrase | ssh-keygen -l -f ~/.ssh/id_ed25519.pub |
| Servidor | Deshabilitar contrase帽as | grep PasswordAuthentication /etc/ssh/sshd_config |
| fail2ban | Jail SSH activo | fail2ban-client status sshd |
| Logs | VERBOSE habilitado | grep LogLevel /etc/ssh/sshd_config |
| Firewall | Puerto 22 restringido a IPs confiables | iptables -L INPUT -n | grep :22 |
| Actualizaciones | OpenSSH >= 9.8 | sshd -V | grep OpenSSH |
| 2FA | Google Authenticator + PAM (opcional) | grep AuthenticationMethods /etc/ssh/sshd_config |
Advertencia cr铆tica: Antes de cerrar su sesi贸n SSH actual, siempre abra una segunda conexi贸n paralela para probar la nueva configuraci贸n. Un error en
sshd_configpuede dejarlo fuera del servidor de forma permanente. Usescreenotmuxpara mantener una sesi贸n de respaldo mientras realiza cambios.
La combinaci贸n de claves Ed25519 con fail2ban no es una soluci贸n completa, sino la base de una estrategia de defensa en profundidad. Complemente con autenticaci贸n multifactor (TOTP v铆a libpam-google-authenticator), restricciones por firewall a nivel de red (whitelist de IPs), y monitoreo continuo de logs. En entornos cr铆ticos, considere soluciones como Teleport o Boundary que abstraen completamente el acceso SSH tradicional.
