fail2ban: protección automatizada contra fuerza bruta

Cuando expones SSH u otro servicio a internet, los logs se llenan de intentos de login fallidos en cuestión de horas. No son humanos tecleando: son bots que prueban combinaciones de usuario/contraseña de forma continua. fail2ban es un demonio que monitorea esos logs y bloquea temporalmente las IPs que muestran ese patrón, interponiendo una barrera automática entre el escáner y tu servicio.

La arquitectura se organiza en tres conceptos: jails (configuraciones por servicio, como “qué hacer con SSH”), filters (expresiones regulares que identifican intentos fallidos en los logs de ese servicio) y actions (qué ejecutar cuando se supera el umbral — típicamente añadir una regla a nftables o iptables). Cuando el filter de un jail detecta suficientes coincidencias en la ventana de tiempo configurada, la action entra en juego y banea la IP.

La regla más importante de configuración: nunca edites /etc/fail2ban/jail.conf. Ese archivo lo gestiona el paquete y se sobreescribe en actualizaciones. Todo tu trabajo va en /etc/fail2ban/jail.local, que existe precisamente para esto: sus valores prevalecen sobre jail.conf sin tocarlo.

¿Cuándo tiene sentido usarlo? Siempre que tengas servicios de autenticación expuestos públicamente. SSH es el caso más obvio, pero también sirve para Postfix, Dovecot, Nginx, o cualquier cosa que genere logs con intentos fallidos. Lo que no hace: te protege contra atacantes distribuidos con miles de IPs rotantes. Contra un bot con una sola IP o un rango pequeño, funciona bien. Contra alguien con una botnet, el impacto es marginal. Eso no lo invalida, pero hay que tenerlo en perspectiva.

El riesgo más inmediato de una mala configuración eres tú mismo. Si defines un maxretry de 3 y fallaste el password tres veces desde tu IP, estás bloqueado. Conocer el comando de desbloqueo antes de necesitarlo no es opcional.

# Instalar fail2ban
apt install fail2ban

# Crear jail.local partiendo del ejemplo incluido en el paquete.
# Si no existe, copiamos la plantilla vacía; si ya existe, no tocamos nada.
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Editar jail.local — solo las secciones que nos interesan
# En producción es más limpio escribir solo las claves que modificas,
# sin copiar todo jail.conf. Aquí lo hacemos con un heredoc para claridad:
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# Nunca banear estas IPs, pase lo que pase.
# Tu red local o tu IP de administración van aquí.
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

# Tiempo de baneo. Acepta sufijos: s, m, h, d.
# Con valor negativo, el baneo es permanente (úsalo con cuidado).
bantime  = 1h

# Ventana de tiempo en la que se cuentan los intentos.
findtime = 10m

# Número de fallos dentro de findtime para activar el baneo.
maxretry = 5

# Backend para leer logs. "systemd" es el correcto en Debian con journald.
backend = systemd

[sshd]
enabled  = true
# El puerto solo es necesario si SSH no corre en 22.
# port     = 2222
EOF

# Habilitar e iniciar el demonio
systemctl enable --now fail2ban

# Verificar que el servicio levantó sin errores
systemctl status fail2ban

# Ver todos los jails activos y su estado general
fail2ban-client status

# Ver el estado específico del jail sshd:
# IPs actualmente baneadas, total de banes, fallos detectados.
fail2ban-client status sshd

# Si te bloqueaste a ti mismo, esto te saca inmediatamente
# sin necesidad de reiniciar el servicio.
fail2ban-client set sshd unbanip 192.168.1.50

# El log de banes — útil para revisar actividad o diagnosticar problemas.
# Cada ban y unban queda registrado aquí con timestamp e IP.
tail -f /var/log/fail2ban.log

backend = systemd es el cambio más importante respecto a configuraciones antiguas que encontrarás en internet. En Debian Bookworm, SSH loguea vía journald, no a /var/log/auth.log de forma garantizada. Con backend = auto (el valor por defecto en algunas versiones) fail2ban puede no leer el journal correctamente y el jail queda sordo. Especificarlo explícitamente elimina la ambigüedad.

El bloque [DEFAULT] afecta a todos los jails que no sobreescriban esas claves. ignoreip es la clave donde tienes que poner tu propia IP o red antes de activar cualquier jail agresivo: un bantime = 1d con maxretry = 3 y sin tu red en ignoreip es una trampa garantizada.

[sshd] solo necesita enabled = true porque el filter y la action para SSH vienen definidos en jail.conf (que hereda jail.local). El filter en cuestión es /etc/fail2ban/filter.d/sshd.conf, que contiene las regex que reconocen líneas como Failed password for invalid user en el journal. No tienes que escribir esas regex: el paquete ya las trae.

fail2ban-client status sshd te devuelve algo como Currently banned: 3 junto con la lista de IPs. Ese comando es tu primera parada cuando sospechas que algo está siendo atacado o cuando un usuario legítimo no puede conectar. El log en /var/log/fail2ban.log completa el cuadro: ahí ves el historial, no solo el estado actual.

La action por defecto en Debian usa nftables a través de la cadena f2b-sshd. Si ejecutas nft list ruleset después de que fail2ban banee una IP, la verás ahí. Eso significa que fail2ban y cualquier configuración manual de nftables comparten el mismo kernel netfilter: no son capas independientes, y una regla nft flush ruleset elimina también los banes activos de fail2ban.

96

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio