Cómo configurar fail2ban para SSH

Instala fail2ban, crea /etc/fail2ban/jail.local con una jail [sshd] activada y backend = systemd, reinícialo y comprueba con fail2ban-client status sshd. Bloquea direcciones tras accesos fallidos repetidos. Reduce el ruido y frena los intentos de adivinar, pero desactivar el acceso por contraseña te protege mucho más.

Actualizada el . Ejecutado con fail2ban 1.1.0 en un contenedor Debian 13 desechable arrancado con systemd y usando nftables, con OpenSSH 10.0, y accesos fallidos reales desde un segundo contenedor. El archivo de la jail predeterminada también se leyó en Ubuntu 24.04.

Qué hace

fail2ban lee los registros. Cuando una dirección falla al iniciar sesión maxretry veces dentro de findtime, añade una regla de cortafuegos que bloquea esa dirección durante bantime. Nada más. No inspecciona el tráfico SSH y no convierte en fuerte una contraseña débil.

Instalar

sudo apt install fail2ban python3-systemd

python3-systemd le permite leer el journal de systemd. En los sistemas de la familia Red Hat el paquete está en EPEL. En Debian 13 y Ubuntu 24.04 el paquete ya activa la jail sshd, con el backend systemd y nftables, mediante /etc/fail2ban/jail.d/defaults-debian.conf.

Configurar: jail.local

No edites jail.conf, porque las actualizaciones pueden reemplazarlo. Pon tus ajustes en /etc/fail2ban/jail.local:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
bantime  = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true
backend = systemd
AjusteSignificadoValor por defecto del paquete
bantimeCuánto dura un bloqueo10m
findtimeLa ventana en la que se suman los fallos10m
maxretryFallos permitidos en esa ventana5
ignoreipDirecciones que nunca se bloqueanninguna
backendDe dónde vienen los registrosauto

Añade tu propia dirección fija a ignoreip, para que unos pocos errores al teclear no te dejen fuera. Si tu dirección cambia, asegúrate de tener una consola a la que recurrir.

Usa backend = systemd donde SSH registra en el journal, como en el Debian actual, que puede no tener ningún /var/log/auth.log. En un sistema que escribe ese archivo, puedes usar backend = auto y logpath.

Si sshd escucha en otro puerto, añade port = 2222 a la jail. La regla que vimos coincidía solo con el puerto indicado en el ajuste de la jail (tcp dport 22), así que un bloqueo en el puerto equivocado no bloquea nada.

Prueba el archivo y luego reinicia:

sudo fail2ban-client -t
sudo systemctl restart fail2ban

Comprueba que funciona de verdad

sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	4
|  `- Journal matches:	_SYSTEMD_UNIT=ssh.service + _COMM=sshd
`- Actions
   |- Currently banned:	1
   |- Total banned:	1
   `- Banned IP list:	203.0.113.20

Haz una prueba real. Desde otra dirección, que no sea el propio servidor ni una de ignoreip, falla un acceso con contraseña y ejecuta el comando otra vez. Total failed debe subir. Si se queda en 0, la jail no está leyendo los registros correctos y el resto no sirve de nada. Compara la coincidencia del journal con el nombre de tu unidad, ssh.service o sshd.service, y comprueba con journalctl -u ssh -n 20.

Una vez bloqueado, el cliente ve esto:

ssh: connect to host 203.0.113.10 port 22: Connection refused

La regla del cortafuegos se puede ver con sudo nft list ruleset:

table inet f2b-table {
	set addr-set-sshd {
		type ipv4_addr
		elements = { 203.0.113.20 }
	}
	chain f2b-chain {
		type filter hook input priority filter - 1; policy accept;
		tcp dport 22 ip saddr @addr-set-sshd reject with icmp port-unreachable
	}
}

Comandos del día a día

ObjetivoComando
Listar las jailssudo fail2ban-client status
Desbloquear una direcciónsudo fail2ban-client set sshd unbanip 203.0.113.20
Desbloquear todosudo fail2ban-client unban --all
Bloquear a manosudo fail2ban-client set sshd banip 203.0.113.20
Ver los bloqueos y cuándo terminansudo fail2ban-client get sshd banip --with-time
Ignorar una dirección ahorasudo fail2ban-client set sshd addignoreip 203.0.113.10
Leer los ajustes en usosudo fail2ban-client get sshd bantime
Leer su registrosudo tail /var/log/fail2ban.log

El cambio de addignoreip dura solo hasta la siguiente recarga. Añádelo a jail.local para conservarlo.

Qué cuenta como fallo

Probamos el modo por defecto en OpenSSH 10.0 con estos resultados:

  • Una contraseña incorrecta contó, igual que una contraseña incorrecta para un usuario que no existe.
  • Una desconexión por Too many authentication failures contó como una.
  • Las conexiones que ofrecían una clave incorrecta y luego se rendían no contaron. Aparecen en el registro como Connection closed by authenticating user.

Con mode = aggressive en la jail [sshd], las conexiones con clave incorrecta también se contaron. Detecta más, y también facilita bloquear a alguien con un cliente mal configurado, así que mantén ignoreip al día.

Frente a qué no protege

  • Una clave robada o una contraseña filtrada. Un acceso correcto no es un fallo, así que no hay bloqueo.
  • Intentos lentos o distribuidos. Muchas direcciones que hacen uno o dos intentos cada una se quedan por debajo del límite.
  • Una debilidad en el propio sshd. Reacciona a líneas de registro, una vez ocurrido el hecho.
  • Otros servicios, salvo que tengan sus propias jails.

También puede perjudicarte: todos los que están detrás de un NAT de oficina comparten una dirección, así que los errores de una persona pueden dejar fuera a toda la oficina.

Si una clave se filtra, hay que saber dónde está instalada y quitar la clave SSH de cada servidor.

Lo que importa más

Si el servidor solo acepta claves, adivinar contraseñas no tiene nada que adivinar, sea cual sea el número de intentos. Así que haz esto primero:

  1. Usa una clave y desactiva el acceso por contraseña.
  2. Limita quién puede llegar al puerto 22 con un cortafuegos o una VPN, si puedes.
  3. Revisa el resto de tus ajustes de sshd.

Después de eso, fail2ban es un extra útil que mantiene los registros más tranquilos. Además, OpenSSH 9.8 y posteriores tienen su propio PerSourcePenalties, activado por defecto, que rechaza durante un tiempo corto las direcciones que se portan mal. Es mucho más corto que un bloqueo típico de fail2ban, así que ambos funcionan bien juntos.

Preguntas

¿Cómo desbloqueo una IP en fail2ban?

Ejecuta sudo fail2ban-client set sshd unbanip seguido de la dirección. sudo fail2ban-client unban --all quita todos los bloqueos de todas las jails.

¿Cómo compruebo que fail2ban funciona?

Ejecuta sudo fail2ban-client status sshd, falla un inicio de sesión desde otra dirección y vuelve a ejecutarlo. Total failed debe subir. Si se queda en 0, la jail no está leyendo los logs de SSH.

¿Por qué un cliente bloqueado ve Connection refused?

Con la acción nftables por defecto en Debian, una dirección bloqueada recibe un rechazo, así que ssh imprime Connection refused en lugar de un tiempo de espera agotado. Una acción que descarte paquetes se vería como un timeout.

¿Cuentan como fallos las claves incorrectas?

No en el modo por defecto. En nuestra prueba, cinco conexiones con una clave incorrecta no sumaron nada al contador. mode = aggressive en la jail sí las contó.

Fuentes

Más en Proteger un servidor

Todas las guías