Hardening SSH: 5 configuraciones que cierran el 95% de los vectores

Hardening SSH: 5 configuraciones que cierran el 95% de los vectores

Levanta una instancia nueva en AWS, DigitalOcean o cualquier VPS con el puerto 22 expuesto y abre /var/log/auth.log diez minutos después. Verás algo así:

Jun  3 10:04:17 sshd[12884]: Failed password for invalid user admin from 45.142.212.100 port 41832 ssh2
Jun  3 10:04:19 sshd[12886]: Failed password for invalid user root from 45.142.212.100 port 41834 ssh2
Jun  3 10:04:21 sshd[12889]: Failed password for invalid user ubuntu from 185.234.219.45 port 22018 ssh2

Internet escanea el rango completo de IPs todo el tiempo. Scripts automatizados prueban root, admin, ubuntu, pi, y diccionarios de contraseñas comunes las 24 horas del día. La mayoría de los administradores de servidores ignora ese ruido de fondo, hasta el día en que una contraseña débil cede. Este post cubre los cinco cambios de configuración que reducen radicalmente la superficie de ataque del SSH sin complicar la operación del día a día.

Antes de cualquier cambio: crea el par de claves Ed25519

Todo empieza aquí. Desactivar la autenticación por contraseña sin tener una clave SSH configurada te va a dejar fuera del servidor. Hazlo primero, en tu máquina local:

ssh-keygen -t ed25519 -C "tu@servidor"

¿Por qué Ed25519 y no RSA? Ed25519 usa criptografía de curva elíptica: la clave es más pequeña, la operación más rápida, y el nivel de seguridad equivale a un RSA de 3000+ bits. Desde 2020, todas las distribuciones Linux modernas y macOS soportan ed25519 de forma nativa. Si todavía usas RSA 2048, es hora de migrar.

Con el par de claves generado (~/.ssh/id_ed25519 y ~/.ssh/id_ed25519.pub), copia la clave pública al servidor:

ssh-copy-id -i ~/.ssh/id_ed25519.pub usuario@IP_DEL_SERVIDOR

Prueba el acceso con clave antes de cerrar la sesión actual. Abre una nueva terminal y confirma que el inicio de sesión funciona sin pedir contraseña. Solo entonces continúa con el siguiente paso.

Los 5 cambios en sshd_config

El archivo de configuración está en /etc/ssh/sshd_config. Haz un respaldo antes de editar:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

Localiza y ajusta las siguientes directivas. Si la línea está comentada (con # al inicio), descoméntala y edítala:

1. Desactivar el inicio de sesión directo como root

PermitRootLogin no

Root es el primer usuario que cualquier script de fuerza bruta intenta. Sin acceso directo, el atacante necesita comprometer una cuenta común y escalar privilegios: dos pasos donde antes había uno.

2. Desactivar la autenticación por contraseña

PasswordAuthentication no
KbdInteractiveAuthentication no

Este es el cambio de mayor impacto. Con la autenticación por clave obligatoria, el fuerza bruta de contraseñas se vuelve inútil: no hay credencial que adivinar. El atacante necesitaría tu clave privada, que nunca sale de tu máquina. Según la guía de hardening documentada por Byte Guard y confirmada por Hostiserver, este par de configuraciones cierra de una vez el vector de ataque más común.

3. Limitar los intentos de autenticación

MaxAuthTries 3
LoginGraceTime 30

MaxAuthTries 3 corta la conexión después de tres intentos fallidos. LoginGraceTime 30 cierra sesiones que quedan colgadas sin completar la autenticación en 30 segundos, útil contra técnicas de conexión lenta que intentan agotar los slots disponibles.

4. Restringir qué usuarios pueden conectarse vía SSH

AllowUsers tu_usuario

Reemplaza tu_usuario por el nombre real del usuario. Si necesitas más de uno, sepáralos con espacio. Cualquier otro usuario del sistema, incluso con contraseña válida, queda bloqueado en SSH. Esto limita el radio de impacto de una cuenta comprometida en otro servicio.

5. Desactivar funciones que no se usan

X11Forwarding no
AllowTcpForwarding no
PrintMotd no

X11Forwarding abre un canal para redirección gráfica, innecesario en un servidor headless. AllowTcpForwarding no impide que el SSH se use como túnel para tráfico arbitrario, algo que puede explotarse en ataques de pivoting de red.

Validar y aplicar los cambios

Antes de reiniciar el daemon, prueba la sintaxis del archivo:

sudo sshd -t

Si no aparece ninguna salida, la configuración es válida. Solo entonces reinicia:

sudo systemctl reload sshd
# o, en sistemas más antiguos:
sudo service ssh restart

Regla crítica: mantén la sesión actual abierta y prueba el acceso en una segunda terminal antes de cerrar nada. Si algo se traba, la sesión abierta te da la oportunidad de corregirlo.

fail2ban: el portero automático

Incluso con autenticación por clave, siguen llegando solicitudes de conexión maliciosas que consumen recursos. fail2ban monitorea los logs de autenticación y bloquea IPs que disparan demasiados fallos seguidos:

sudo apt install fail2ban -y

Crea el archivo de configuración local (nunca edites jail.conf directamente: se sobrescribe en las actualizaciones):

sudo nano /etc/fail2ban/jail.local

Contenido mínimo funcional:

[sshd]
enabled  = true
port     = ssh
filter   = sshd
maxretry = 3
findtime = 600
bantime  = 3600
logpath  = %(sshd_log)s

Este bloque bloquea durante 1 hora a cualquier IP que falle 3 veces en 10 minutos. Ajusta bantime según tu nivel de paranoia: -1 bloquea de forma permanente. Reinicia el servicio:

sudo systemctl enable fail2ban
sudo systemctl restart fail2ban

Verifica los bloqueos activos con sudo fail2ban-client status sshd.

¿Vale la pena cambiar el puerto por defecto?

Cambiar el puerto 22 por algo por encima de 1024 es "seguridad por oscuridad": no resuelve el problema de fondo, pero elimina prácticamente todo el ruido de bots automatizados que escanean solo el puerto estándar. El costo es tener que especificar el puerto en cada comando SSH (ssh -p 2222 usuario@host) y actualizar las reglas del firewall.

La decisión depende del contexto: en un servidor personal o de homelab, vale la pena por el silencio en los logs. En producción corporativa, donde cambiar el puerto puede romper scripts y pipelines, los cinco pasos anteriores ya son suficientes.

Vale recordar que el hardening de SSH es una capa de un sistema mayor. La protección a nivel de DNS, como se documenta en el post sobre NextDNS y DNS cifrado, bloquea conexiones maliciosas antes de que lleguen a tu servidor. Y para las cuentas que gestionas de forma remota, entender cómo el MFA fatigue compromete el segundo factor ayuda a elegir el método correcto de autenticación más allá del SSH. Si además administras servidores Windows, el post sobre PowerShell para auditar logs de seguridad cubre el equivalente al auth.log en ese entorno.

Checklist rápido antes de terminar

  • Clave Ed25519 copiada y probada en el servidor
  • PermitRootLogin no activo
  • PasswordAuthentication no y KbdInteractiveAuthentication no
  • MaxAuthTries 3 y LoginGraceTime 30
  • AllowUsers con lista explícita de usuarios
  • sshd -t sin errores
  • fail2ban corriendo con el jail de sshd activo
  • Nueva sesión SSH probada antes de cerrar la anterior

Estos cambios no requieren software de pago, suscripción a ningún servicio ni configuración compleja: son directivas nativas de OpenSSH disponibles en cualquier distribución. El costo son 20 minutos de configuración; el beneficio es eliminar toda una categoría de ataques por fuerza bruta y robo de credenciales. Si administras servidores y todavía no aplicaste esto, este es un buen punto de partida.

Comentarios