Restringir intentos de contraseña en Linux para blindar SSH y servicios

  • Analiza los logs de autenticación y ajusta sshd_config para limitar usuarios, puertos, protocolos e intentos y así reducir la superficie de ataque.
  • Despliega Fail2ban para vigilar servicios clave (SSH, web, bases de datos) y bloquear automáticamente IPs con muchos fallos.
  • Adopta claves SSH en lugar de contraseñas y desactiva PasswordAuthentication para inutilizar de raíz los ataques de fuerza bruta.
  • Refuerza con firewall, TCP Wrappers y, si es necesario, 2FA, combinando varias capas de defensa para proteger tus servidores Linux expuestos.

Restringir intentos de contraseña en Linux para proteger SSH y servicios

Si administras un servidor Linux expuesto a Internet, tarde o temprano verás en los logs miles de intentos de acceso por SSH desde direcciones IP aleatorias. No es que te hayan cogido manía: son bots automatizados que van recorriendo rangos de IP buscando puertas mal protegidas.

En un servidor pequeño, esos intentos pueden traducirse en picos de uso de CPU, degradación del rendimiento e incluso caídas puntuales de servicios. La buena noticia es que Linux ofrece un arsenal de herramientas para limitar los intentos de contraseña, bloquear IPs agresivas y reforzar SSH hasta dejarlo muy difícil para un atacante.

Detectar ataques de fuerza bruta SSH y su impacto en el servidor

Antes de ponernos a configurar nada, conviene entender cómo detectar que estamos sufriendo un ataque de fuerza bruta contra SSH u otros servicios, y qué efectos tiene sobre la máquina.

Un síntoma muy típico es ver un aumento brusco del uso de CPU sin que cambie el tráfico legítimo ni la carga de la base de datos. Por ejemplo, puedes tener un pico de CPU durante unos minutos mientras la memoria y el disco siguen prácticamente planos, lo que suele apuntar a procesos intensivos en cómputo (como muchos intentos de autenticación) y no tanto a consultas pesadas.

Para analizar qué estaba pasando en un intervalo concreto, es muy útil tirar de journalctl, la herramienta de systemd para leer logs de sistema, servicios, kernel y autenticación. Un ejemplo clásico de consulta sería:

journalctl --since "2025-11-16 13:10" --until "2025-11-16 13:16"

Con ese tipo de consulta podrás revisar con detalle qué mensajes registró el sistema durante la ventana en la que se disparó la CPU: servicios que se reinician, fallos de autenticación, errores de kernel, etc.

En muchos casos te encontrarás con líneas repetidas relacionadas con SSH, del tipo «Failed password for» que evidencian intentos fallidos de login. Eso es prácticamente sinónimo de bots probando credenciales a lo bruto.

Cuantificar los intentos fallidos en /var/log/auth.log

En sistemas Debian/Ubuntu, el archivo clave para seguirle la pista a todo lo que huela a autenticación es /var/log/auth.log. Ahí se registran logins exitosos, intentos fallidos, eventos de PAM, bloqueos de cuentas, etc.

Si quieres saber cuántas veces se ha registrado el patrón «Failed password» en el log actual, puedes usar:

sudo grep 'Failed password' /var/log/auth.log | wc -l

El resultado puede ser sorprendente: no es raro ver miles de intentos fallidos acumulados en cuestión de horas. Y recuerda que ese es sólo el fichero actual.

Como los logs se rotan, es importante revisar también los archivos anteriores. Puedes ver qué intervalo temporal cubre el log actual con algo como:

head -n 1 /var/log/auth.log
tail -n 1 /var/log/auth.log

Así sabrás la fecha del primer y último registro presentes en auth.log. El resto de intentos anteriores estarán en auth.log.1 y en los archivos comprimidos auth.log.N.gz.

Para revisar los logs antiguos comprimidos y contar intentos de contraseña fallida, puedes tirar de:

zgrep 'Failed password' /var/log/auth.log.*.gz | wc -l

Si sumas lo que veas en auth.log, auth.log.1 y auth.log.*.gz te harás una buena idea del histórico de ataques de fuerza bruta registrados, teniendo en cuenta que los más viejos ya pueden haber desaparecido por la rotación.

Cómo funciona la rotación de logs de autenticación

La forma y frecuencia con la que rotan los logs depende de la configuración de logrotate. En Ubuntu, la rotación de auth.log suele definirse en /etc/logrotate.d/rsyslog, donde es habitual encontrarse algo tipo:

weekly
rotate 4
compress

Eso quiere decir que se rota el log cada semana, se guardan cuatro copias antiguas y las viejas se comprimen en .gz. Un cron diario se encarga de ejecutar logrotate y aplicar estas reglas.

Por tanto, cuando hagas tus cuentas de intentos de fuerza bruta, asume que solo estás viendo el histórico de varias semanas. Lo que haya sucedido más atrás en el tiempo ya no estará en el sistema.

Identificar usuarios e IPs atacantes

Más allá del conteo total, conviene saber qué usuarios se están intentando explotar y desde qué direcciones IP llegan los ataques. Con un poco de awk sobre auth.log lo tienes a mano.

Para ver qué nombres de usuario se están probando en los intentos fallidos:

sudo grep 'Failed password' /var/log/auth.log \
  | awk '{print $(NF-5)}' \
  | sort | uniq -c

Y para ver las IPs con más actividad sospechosa:

sudo grep 'Failed password' /var/log/auth.log \
  | awk '{print $(NF-3)}' \
  | sort | uniq -c | head

Con esto podrás detectar rápidamente si están atacando cuentas reales de tu sistema o usuarios genéricos como root, admin, test, usuario, etc., y qué IPs son las que deberías bloquear con más urgencia.

¿Es tan grave que haya miles de intentos?

Hay que asumir que, si tu servidor es accesible desde Internet y tiene SSH escuchando en el puerto 22 o en cualquier otro, va a recibir este tipo de tráfico las 24 horas del día. Es normal que veas miles de intentos fallidos a poco que el servidor lleve tiempo encendido.

La gravedad real depende de tu configuración:

Configuración Riesgo aproximado
Contraseñas débiles + SSH abierto a Internet Riesgo muy alto de compromiso
Contraseñas robustas Riesgo moderado, pero consumo de recursos
Fail2ban bien configurado Riesgo bajo y ataques muy mitigados
Solo acceso con claves SSH Riesgo muy cercano a cero por fuerza bruta

En otras palabras: los ataques automatizados son el pan de cada día, pero si tu configuración es laxa, basta que falle una única contraseña para que pierdas el servidor completo. Por eso es tan importante limitar intentos, bloquear IPs y, en la medida de lo posible, quitar del medio las contraseñas.

Refuerzo básico de SSH: opciones críticas en sshd_config

Restringir intentos de contraseña en Linux para proteger SSH y servicios

La primera línea de defensa está en el propio daemon SSH (sshd) y su fichero de configuración /etc/ssh/sshd_config (y los ficheros .d asociados). Unas pocas directivas bien ajustadas reducen muchísimo la superficie de ataque.

Ten en cuenta que en distribuciones modernas como Ubuntu 22.04 y posteriores, sshd lee primero /etc/ssh/sshd_config y luego los archivos en /etc/ssh/sshd_config.d/*.conf en orden alfabético. Lo que aparezca después puede sobrescribir parámetros definidos antes, así que hay que vigilar muy bien qué tocas.

Desactivar accesos sin contraseña y sesiones innecesarias

Aunque en la mayoría de distribuciones modernas ya viene bien configurado, no está de más confirmar que no se permiten inicios de sesión sin contraseña definida. La directiva clave es:

PermitEmptyPasswords no

Lo normal es que esté comentada o puesta explícitamente a «no». Asegúrate también de tener desactivadas características que no vayas a usar, como el reenviado de X11 (X11Forwarding) si no haces sesiones gráficas remotas:

X11Forwarding no

En cuanto a protocolos, si por lo que sea administras un sistema muy viejo, revisa que sólo se permita SSH protocolo 2:

Protocol 2

Cambiar el puerto por defecto y limitar en qué interfaz escucha

Otro truco sencillo, aunque no definitivo, es mover SSH del puerto 22 a uno no estándar. Esto no te protege de un atacante serio, pero filtra una cantidad apreciable de ruido automatizado que solo escanea el 22.

Port 2222
ListenAddress 192.168.56.8

Además de cambiar el puerto, puedes especificar una dirección concreta en la que escuchará SSH, por ejemplo la IP interna si lo quieres confinar a una red concreta. Eso sí, si tu distribución usa el socket ssh.socket de systemd, quizá tengas que desactivar el socket y volver al servicio clásico ssh.service para que respete la configuración de puerto:

sudo systemctl disable ssh.socket
sudo systemctl daemon-reload
sudo systemctl enable ssh.service
sudo systemctl start ssh.service

Siempre que cambies el puerto, prueba la conexión desde otra terminal antes de cerrar la sesión principal, para no quedarte tirado sin acceso remoto.

Bloquear o limitar el acceso de root

El usuario root es un caramelo para los atacantes, así que tiene sentido impedir que se conecte por SSH, incluso con claves. Controlas este comportamiento con la directiva:

PermitRootLogin no

En muchas instalaciones modernas viene en modo «prohibit-password», lo que impide login con contraseña pero deja la puerta abierta a certificados. Si quieres ir a lo seguro, déjalo en «no» y utiliza una cuenta normal con sudo para administración.

Definir quién puede acceder: AllowUsers y AllowGroups

Por defecto, cualquier usuario con shell válida y contraseña definida puede intentar conectarse por SSH. Eso no suele ser lo ideal en servidores de producción, donde quizá sólo dos o tres cuentas deberían tener acceso.

Para acotar los usuarios permitidos tienes las directivas AllowUsers y AllowGroups. Por ejemplo:

AllowUsers harry hermione
AllowGroups gryffindor

La lista se separa por espacios y la semántica es de «lista blanca»: solo las cuentas y grupos listados podrán autenticarse. Ten en cuenta además que AllowUsers tiene prioridad sobre AllowGroups, así que no abuses de mezclar ambas salvo que tengas claro el orden de evaluación.

Una buena práctica es trabajar principalmente con grupos tipo sshusers o admins y añadir ahí a las cuentas autorizadas, en lugar de ir manteniendo una lista de usuarios uno a uno en el fichero.

Limitar intentos de autenticación y tiempo de inactividad

Otra capa de protección está en reducir cuántos intentos fallidos se permiten en una sola conexión y cuánto tiempo puede quedar una sesión inactiva. Para lo primero puedes usar:

MaxAuthTries 3

Con esto, el servidor cerrará la conexión tras tres intentos incorrectos, lo que hace menos efectivo cualquier ataque que pruebe muchas contraseñas contra la misma sesión SSH.

En cuanto al tiempo de inactividad, SSH permite cortar conexiones que se quedan abiertas sin actividad más allá de un umbral definido mediante ClientAliveInterval (en segundos):

ClientAliveInterval 180

Pasados tres minutos sin tráfico, el servidor enviará mensajes keepalive y, si el cliente no responde, la sesión se cerrará automáticamente. Es una forma de reducir riesgos por terminales olvidados abiertos.

Restringir acceso por dirección IP: TCP Wrappers y Match

En algunos escenarios te puede interesar que sólo ciertas IP o rangos puedan acceder por SSH. Tienes varias formas de hacerlo: desde el propio firewall (iptables/nftables), pasando por TCP Wrappers, hasta los bloques Match del sshd_config.

Con TCP Wrappers, todavía usados en muchas distribuciones, se controlan accesos con /etc/hosts.allow y /etc/hosts.deny. El flujo es: primero se evalúa hosts.allow y luego hosts.deny. Un ejemplo restrictivo sería:

# /etc/hosts.deny
ALL: ALL
# /etc/hosts.allow
sshd: 192.168.1.89 192.168.1.55
sshd: ALL: DENY

Con esa configuración, sólo dos hosts concretos podrán conectarse por SSH, y el resto quedarán denegados. Es muy efectivo en entornos cerrados, aunque menos flexible que un buen firewall moderno.

Otra opción, más propia de SSH, es usar bloques Match dentro de sshd_config para aplicar reglas según dirección o usuario. Imagina que quieres que un usuario «git» pueda entrar desde cualquier sitio pero que tu usuario administrador «greg» sólo pueda hacerlo desde la LAN 192.168.1.0/24. Podrías combinar AllowUsers con reglas Match Address, aunque debes ser muy cuidadoso para no cerrarte el acceso a ti mismo.

Fail2ban: bloqueos automáticos frente a fuerza bruta

Aunque fortalezcas SSH, los bots seguirán probando credenciales y provocando consumo de CPU y ruido en los logs. Para mitigar esto es donde entra en juego Fail2ban, un sistema de prevención de intrusiones basado en logs que bloquea automáticamente las IP con demasiados fallos.

Fail2ban está escrito en Python y se apoya en «prisiones» o jails, cada una asociada a un servicio y a uno o varios archivos de log. Cuando detecta un patrón de error repetido (fallos de contraseña, accesos prohibidos, etc.), lanza acciones, normalmente reglas de firewall para bloquear al origen.

Instalar Fail2ban en distribuciones Linux comunes

La instalación básica es bastante directa usando el gestor de paquetes de tu distribución. En Ubuntu o Debian bastaría con:

sudo apt update
sudo apt install fail2ban

En sistemas basados en RHEL (RHEL, CentOS, AlmaLinux, Rocky, etc.) la orden típica sería con dnf o yum, según versión:

sudo dnf install fail2ban

El paquete suele incluir un servicio systemd que se inicia automáticamente, aunque conviene comprobar que Fail2ban arranca al boot y está activo:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo systemctl status fail2ban

Estructura de configuración: jail.conf, jail.local y jail.d

La configuración vive en /etc/fail2ban/. El archivo principal es jail.conf, pero no se recomienda editarlo directamente porque se sobrescribe en actualizaciones. En su lugar, deberías:

  • Crear o editar /etc/fail2ban/jail.local para sobreescribir valores por defecto.
  • O bien añadir ficheros específicos en /etc/fail2ban/jail.d/*.conf.

Fail2ban carga la configuración en este orden:

/etc/fail2ban/jail.conf
/etc/fail2ban/jail.d/*.conf
/etc/fail2ban/jail.local

Todo lo que definas en jail.local prevalece sobre lo anterior, de manera que puedes personalizar sin tocar los archivos del paquete.

Parámetros globales importantes: bantime, maxretry, ignoreip

Dentro de jail.conf (o jail.local) verás una sección [DEFAULT] con parámetros globales que afectan a todas las jails salvo que se sobreescriban. Los más importantes son:

  • bantime: tiempo durante el cual una IP quedará bloqueada (en segundos) tras superar el número de fallos permitidos.
  • maxretry: número máximo de intentos fallidos antes de aplicar el ban.
  • findtime: ventana de tiempo en la que se cuentan esos intentos (ej. 10m para diez minutos).
  • ignoreip: lista de IPs o rangos que Fail2ban nunca debe bloquear (por ejemplo, tu propia IP pública o tu red de administración).

Por ejemplo, podrías tener algo tal que así en [DEFAULT]:

[DEFAULT]
bantime  = 600
findtime = 600
maxretry = 5
ignoreip = 127.0.0.1/8 192.168.1.0/24

Con esa configuración, cualquier IP que falle cinco veces en diez minutos quedará bloqueada diez minutos, salvo que forme parte de los rangos ignorados.

Configurar la jail sshd para frenar ataques a SSH

La jail más típica es la de SSH. En muchas distribuciones viene ya preparada en jail.conf, sólo hay que activarla o afinar sus valores en jail.local. Un ejemplo sencillo:

[sshd]
enabled  = true
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3
bantime  = 600
findtime = 10m

En este caso, tres intentos fallidos registrados en auth.log dentro de diez minutos provocarán un bloqueo de diez minutos de la IP atacante. Fail2ban inyecta las reglas en el firewall (iptables, nftables o UFW, según sistema) para que las conexiones de esa IP ni siquiera lleguen a sshd.

Para aplicar cualquier cambio de configuración recuerda reiniciar el servicio:

sudo systemctl restart fail2ban

Ver el estado de las prisiones y las IPs bloqueadas

Fail2ban incluye una utilidad de control muy práctica, fail2ban-client, con la que puedes ver qué prisiones están activas y qué IPs se han bloqueado. Por ejemplo:

sudo fail2ban-client status

Mostraría algo similar a:

Status
|- Number of jail: 1
`- Jail list: sshd

Para ver información detallada de la jail sshd:

sudo fail2ban-client status sshd

La salida incluye, entre otros campos, el número de IPs actualmente baneadas y el total histórico de direcciones que han sido bloqueadas al menos una vez, más la lista de IPs en curso.

Con estos datos puedes hacerte una idea de cuánto tráfico malicioso está recibiendo tu servidor y cuán efectiva está siendo la configuración actual.

Bloqueos permanentes y bantime incremental

Si quieres ser especialmente duro con los reincidentes, Fail2ban ofrece dos estrategias interesantes: ban permanente y ban incremental.

Para que cualquier IP que supere el umbral de fallos quede expulsada de forma indefinida, basta con poner:

bantime = -1

Con ese ajuste, las IP sancionadas no se desbloquean jamás de forma automática; sólo podrás retirarlas tú manualmente si lo necesitas.

Más flexible es el mecanismo incremental, en el que cada reincidencia incrementa el tiempo de ban según un factor:

bantime           = 10m
bantime.increment = true
bantime.rndtime   = 0
bantime.factor    = 4
bantime.maxtime   = -1

Con estos valores, la progresión sería algo así:

  • 1er bloqueo: 10 minutos
  • 2º bloqueo: 40 minutos
  • 3er bloqueo: 160 minutos (~2 horas y 40)
  • 4º bloqueo: alrededor de 10,6 horas
  • 5º bloqueo: unas 42 horas

Como bantime.maxtime está a -1, la duración puede seguir creciendo sin tope, dejando fuera de juego para siempre a los atacantes realmente pesados.

Usar Fail2ban más allá de SSH: Apache, WordPress, MySQL, tiendas online…

Una vez que le coges el truco a Fail2ban, lo lógico es estirarlo para proteger otros servicios sensibles además de SSH: paneles de administración web, CMS, bases de datos, etc.

Por ejemplo, para una tienda online (Magento, PrestaShop, WooCommerce…) tiene mucho sentido crear una jail que vigile los registros de acceso de Apache o Nginx en busca de muchos códigos 401/403 en /admin o /login. Una configuración mínima basada en Apache podría ser:

[apache-auth]
enabled  = true
filter   = apache-auth
logpath  = /var/log/apache2/access.log
maxretry = 5
bantime  = 3600

En entornos WordPress, una combinación frecuente es monitorizar /wp-login.php y /xmlrpc.php, que son las puertas clásicas para ataques de fuerza bruta y de bots. El filtro podría ir en /etc/fail2ban/filter.d/wordpress.conf:

[Definition]
failregex = .*"POST /wp-login.php HTTP.*" 403
ignoreregex =

Y la jail correspondiente en jail.local:

[wordpress]
enabled  = true
filter   = wordpress
logpath  = /var/log/apache2/access.log
maxretry = 3
bantime  = 3600

Igual idea para bases de datos expuestas (algo que en general conviene evitar): si quieres proteger MySQL de accesos fallidos continuos, puedes crear un filtro para los mensajes «Access denied for user» en el log de errores:

[Definition]
failregex = ^<HOST>.*Access denied for user.*$
ignoreregex =

Y luego la jail:

[mysqld-auth]
enabled  = true
filter   = mysql
logpath  = /var/log/mysql/error.log
maxretry = 5
bantime  = 1800

En servidores de hosting con paneles tipo cPanel o Plesk, Fail2ban también se integra bien: puede monitorizar servicios de correo, Apache, FTP, e incluso el propio panel de control, bloqueando IPs que se pasen de frenada con los intentos de login.

Autenticación con claves SSH: el fin de los ataques de contraseña

Todo lo anterior ayuda, pero el salto de calidad real llega cuando decides dejar de usar contraseñas para SSH y pasarte a claves públicas/privadas. En ese momento, los ataques de fuerza bruta por contraseña dejan de tener sentido.

La idea es sencilla: cada usuario legítimo tiene un par de claves, una clave privada que se queda en su dispositivo y una clave pública que se copia al servidor en el archivo ~/.ssh/authorized_keys del usuario correspondiente.

Cuando el cliente se conecta, no envía la clave privada; envía la clave pública y luego firma un desafío del servidor con la privada. El servidor comprueba esa firma con la pública, y sólo si coincide permite el acceso.

Por qué las claves SSH anulan la fuerza bruta de contraseñas

En un esquema de contraseña clásica, el atacante simplemente tiene que ir probando cadenas de texto hasta que una coincida con la almacenada (o su hash). Aunque una buena contraseña tiene muchas combinaciones posibles, estamos hablando de órdenes de magnitud como 10¹⁰ posibilidades para contraseñas medias.

Una clave SSH típica de 256 bits (como las de Ed25519) se mueve en espacios de búsqueda del orden de 10⁶¹⁷ combinaciones. En la práctica, para un atacante es matemáticamente inviable adivinar una clave privada por fuerza bruta con ordenadores actuales.

Pero es que además el servidor ni siquiera se pone a calcular nada si la clave pública presentada no está en authorized_keys. En ese caso descarta la conexión casi de inmediato, sin invocar PAM ni procesos de autenticación tradicionales, con lo que el consumo de CPU durante un ataque masivo es mínimo.

Generar y comprobar claves SSH en el cliente

Antes de tocar el servidor, comprueba si tu máquina ya tiene un par de claves SSH generado. Basta listar el contenido de ~/.ssh:

ls -l ~/.ssh

Si ves archivos tipo id_ed25519 e id_ed25519.pub o id_rsa e id_rsa.pub, ya tienes un par válido. Ed25519 es más moderno y ligero, así que suele ser la mejor opción hoy en día.

Si no tienes claves, genera unas nuevas con:

ssh-keygen -t ed25519 -C "tu_usuario@tu_equipo"

El comando creará dos archivos:

  • id_ed25519: la clave privada, que nunca debes compartir.
  • id_ed25519.pub: la clave pública, que sí puedes copiar a los servidores.

Puedes ver el contenido de la clave pública con:

cat ~/.ssh/id_ed25519.pub

Copiar la clave pública al servidor y probar acceso

En el servidor, asegúrate de que existe el directorio ~/.ssh para el usuario con el que vayas a entrar (por ejemplo, git o tu usuario administrador) y que tiene permisos 700:

mkdir -p ~/.ssh
chmod 700 ~/.ssh

Después añade el contenido de tu id_ed25519.pub del cliente a ~/.ssh/authorized_keys (creando el archivo si no existe) y dale permisos 600:

echo "TU_PUBLIC_KEY" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Recuerda reemplazar TU_PUBLIC_KEY por la línea completa que has visto con cat en tu máquina. A partir de ahí puedes probar la conexión indicando la clave explícitamente si quieres:

ssh -i ~/.ssh/id_ed25519 usuario@IP_DEL_SERVIDOR

Si todo está bien, el servidor no te pedirá contraseña y saltarás directamente a la shell. En ese punto ya estás listo para plantearte desactivar la autenticación por contraseña.

Desactivar completamente PasswordAuthentication en el servidor

Una vez verificado que puedes acceder con tu clave desde al menos un equipo (idealmente dos, por si pierdes uno), es buena idea desactivar el login por contraseña para SSH. Así cortas de raíz todo intento de fuerza bruta clásico.

Antes de tocar la configuración, conviene ver qué archivos están definiendo PasswordAuthentication, porque en muchas instalaciones modernas hay ficheros .d que sobrescriben el valor del sshd_config principal:

sudo grep -R "PasswordAuthentication" /etc/ssh/

Es frecuente encontrar algo como:

/etc/ssh/sshd_config.d/50-cloud-init.conf:PasswordAuthentication yes
/etc/ssh/sshd_config:PasswordAuthentication no

En ese caso, la configuración efectiva será «yes» porque el archivo 50-cloud-init.conf se carga después y sobrescribe el valor. Puedes comprobar el resultado final que está aplicando sshd con:

sudo sshd -T | grep passwordauthentication

Para desactivar las contraseñas de verdad, edita el archivo responsable (por ejemplo /etc/ssh/sshd_config.d/50-cloud-init.conf) y deja:

PasswordAuthentication no

Después reinicia el servicio SSH:

sudo systemctl restart ssh

Y vuelve a verificar con:

sudo sshd -T | grep passwordauthentication

Si devuelve «no», los intentos de login con contraseña serán rechazados de inmediato. Programas como PuTTY mostrarán un error al no poder ofrecer credenciales de tipo password, pero tus clientes con claves seguirán funcionando sin problema.

Combinando claves SSH con Fail2ban y otras medidas

Cuando quitas PasswordAuthentication de la ecuación, el valor de Fail2ban para SSH se vuelve más auxiliar que crítico, ya que los bots no tienen ni siquiera campo en el que introducir la contraseña. Aun así, es recomendable mantener la jail de sshd activa porque sirve como capa adicional ante intentos raros de otros tipos o mal uso de claves.

Si a este combo de solo claves SSH + Fail2ban + bloqueo de root + listas AllowUsers/AllowGroups bien afinadas le sumas un firewall restrictivo (iptables/nftables, UFW, firewalld) y, si procede, listas de control de acceso con TCP Wrappers, habrás llevado la probabilidad de intrusión por fuerza bruta a un nivel ínfimo.

En entornos aún más sensibles, puedes ir un paso más allá e introducir autenticación de doble factor (2FA) para SSH, usando módulos como Google Authenticator o similares vía PAM, o incluso restringir quién puede llegar al puerto de SSH mediante VPNs dedicadas.

Con todos estos elementos bien integrados —detección de intentos en logs, configuración cuidadosa de sshd, uso extensivo de Fail2ban, claves SSH en lugar de contraseñas y, cuando haga falta, controles por IP— un servidor Linux puede soportar sin despeinarse los ataques de fuerza bruta continuos a SSH y otros servicios expuestos, manteniendo al mismo tiempo un acceso cómodo y seguro para los administradores.