Una VPS Linux con SSH accesible desde Internet empieza a recibir tráfico hostil casi inmediatamente.

No hace falta que alguien conozca tu servidor, tu nombre o tu proyecto. Bots distribuidos recorren rangos completos de direcciones IP buscando puertos abiertos y probando combinaciones de usuarios y credenciales comunes.

En una VPS Ubuntu que estaba revisando, un comando muy simple dejó el patrón al descubierto:

sudo journalctl -u ssh --no-pager | grep Inval

El resultado completo era demasiado grande para analizarlo a ojo, así que lo resumimos. Había 9.890 eventos Invalid user conservados en el journal entre el 20 y el 29 de agosto.

Ese dato es una buena excusa para entender tres capas que suelen confundirse:

sshd registra el intento
        ↓
Fail2Ban detecta abuso y bloquea localmente
        ↓
AbuseIPDB puede recibir un reporte de esa IP

No son tres alternativas. Son piezas complementarias.

Qué significa Invalid user

Una línea típica era:

Aug 29 04:43:04 oracle-free-vps sshd[253058]: Invalid user admin from 92.118.39.71 port 52480

sshd recibió una conexión que intentó autenticarse como admin, pero esa cuenta no existía en el sistema.

Eso es importante porque un evento Invalid user no demuestra que hayan entrado al servidor. Demuestra que alguien llegó hasta el servicio SSH e intentó usar un nombre de usuario inexistente.

En los datos revisados, los nombres más probados fueron:

1348 admin
 573 user
 334 test
 292 debian
 205 deploy
 158 oracle
 147 ftpuser
 133 postgres
 124 git
 119 administrator
  99 testuser
  93 guest
  82 pi
  73 mysql

El patrón es muy reconocible: usuarios genéricos asociados con servidores, bases de datos, despliegues y dispositivos Linux.

No parece que el atacante conozca tus cuentas. Está lanzando un diccionario de nombres frecuentes.

Tampoco era una sola IP

Las IP con más eventos fueron:

445 95.173.161.147
248 66.116.205.1
248 45.234.176.26
212 103.159.51.70
209 193.32.162.34
189 92.118.39.49
181 92.118.39.77
157 101.36.104.242
148 64.227.168.220
148 195.178.110.228

Esto también es típico del scanning de Internet actual: no necesariamente existe un único origen que puedas bloquear manualmente y olvidar.

Puedes añadir una IP al firewall, pero mañana aparecerán otras cien.

Necesitas automatizar la respuesta.

Antes de bloquear: busca lo realmente importante

Filtrar por Invalid user es útil para entender el ruido, pero no responde la pregunta más importante: ¿hubo intentos contra usuarios válidos o autenticaciones exitosas?

El siguiente filtro debería ser algo como:

sudo journalctl -u ssh --no-pager \
  | grep -E 'Failed password|Accepted password|Accepted publickey'

Las diferencias importan:

Invalid user
    → intentaron una cuenta que no existe

Failed password
    → hubo una autenticación fallida

Accepted password
    → una contraseña fue aceptada

Accepted publickey
    → una clave pública fue aceptada

Por eso miles de eventos Invalid user pueden ser puro ruido de Internet, mientras que una sola autenticación exitosa desde una IP inesperada merece mucha más atención.

El problema de bloquear IPs a mano

Podríamos hacer algo como:

sudo ufw deny from 95.173.161.147

Pero no escala.

En nuestro pequeño conjunto ya había muchas IP distintas. Además, una IP puede atacar durante unos minutos, desaparecer y ser sustituida por otra.

Aquí entra Fail2Ban.

Qué hace realmente Fail2Ban

Fail2Ban observa logs, identifica patrones de abuso y mantiene contadores por IP.

Conceptualmente:

logs de sshd
    ↓
Fail2Ban
    ↓
¿esta IP superó el número permitido de fallos?
    ↓ sí
firewall
    ↓
bloqueo temporal de la IP

La guía oficial de AbuseIPDB describe Fail2Ban de la misma manera: analiza logs como los de autenticación y, cuando una dirección genera demasiados fallos, actualiza reglas del firewall para rechazar nuevas conexiones durante un tiempo configurable.

En Ubuntu podemos empezar comprobando su estado:

sudo systemctl status fail2ban

Y las jails activas:

sudo fail2ban-client status

Para SSH:

sudo fail2ban-client status sshd

Una jail combina fundamentalmente:

qué logs/patrones observar
cuántos fallos tolerar
qué ventana temporal usar
cuánto tiempo bloquear
qué acción ejecutar al banear

Fail2Ban y AbuseIPDB no hacen lo mismo

Esta separación es crucial.

Fail2Ban hace el enforcement local.

Cuando detecta abuso puede modificar el firewall del servidor y evitar que esa IP siga conectándose durante el bantime.

AbuseIPDB es una base colaborativa de reputación de direcciones IP.

La integración permite que, cuando Fail2Ban banee una IP, ejecute también una acción que la reporte mediante la API de AbuseIPDB.

El flujo completo queda así:

1. Bot intenta entrar por SSH
2. sshd genera eventos
3. Fail2Ban reconoce el patrón
4. Fail2Ban banea la IP localmente
5. La acción abuseipdb reporta esa IP
6. El reporte contribuye a la reputación compartida

AbuseIPDB no sustituye el bloqueo de Fail2Ban en este flujo. Añade inteligencia colaborativa y reporting.

La integración ya viene preparada en Fail2Ban moderno

Según la documentación de AbuseIPDB, el soporte para esta acción está en Fail2Ban desde la versión 0.10.0.

Podemos comprobar la versión instalada:

fail2ban-client -V

Y verificar que exista la acción:

ls -l /etc/fail2ban/action.d/abuseipdb.conf

Además necesitamos una API key de AbuseIPDB.

Es mejor mantener nuestras modificaciones en:

/etc/fail2ban/jail.local

en lugar de editar directamente la configuración distribuida por el paquete.

Activar el reporte para la jail de SSH

La documentación oficial muestra una configuración de este estilo:

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

action = %(action_)s
         %(action_abuseipdb)s[abuseipdb_apikey="TU_API_KEY", abuseipdb_category="18,22"]

Las categorías usadas aquí son:

18 = Brute-Force
22 = SSH

Eso permite que el ban normal siga ocurriendo y, adicionalmente, la dirección sea reportada como abuso relacionado con brute force sobre SSH.

Después de modificar la configuración:

sudo fail2ban-client reload

Y podemos observar su actividad:

sudo tail -f /var/log/fail2ban.log

¿Qué envía la acción a AbuseIPDB?

La acción estándar utiliza la API de reportes de AbuseIPDB y envía, entre otros datos:

IP baneada
categoría del abuso
comentario basado en el evento que disparó el ban

La implementación se encuentra en:

/etc/fail2ban/action.d/abuseipdb.conf

Es importante revisar ese archivo antes de activarlo si no quieres que el fragmento del log aparezca como comentario del reporte.

La propia documentación explica que el comentario predeterminado puede incluir el match del log que provocó el ban.

Cuidado con los límites y los reportes duplicados

La API no debe tratarse como un sumidero infinito de eventos.

AbuseIPDB indica que aplica límites diarios de reportes según el tipo de cuenta y, además, evita que la misma IP sea reportada repetidamente dentro de una ventana de 15 minutos.

Por eso recomienda que el bantime no sea inferior a esa ventana cuando utilices esta integración. Un valor de 900 segundos representa 15 minutos:

bantime = 900

En la práctica yo no escogería los valores de bantime, findtime y maxretry copiando números a ciegas. Primero observaría el patrón real de tráfico y el riesgo de bloquear usuarios legítimos.

Fail2Ban es una capa, no toda la seguridad de SSH

Ver 9.890 intentos hostiles puede llevar a pensar que Fail2Ban resolverá todo.

No.

La defensa debería ser por capas:

Internet
   │
   ▼
reglas de red / firewall cloud
   │
   ▼
firewall del host
   │
   ▼
sshd endurecido
   │
   ▼
Fail2Ban
   │
   ├── bloquea automáticamente
   │
   └── AbuseIPDB reporta reputación
   │
   ▼
logs + auditoría + alertas

Para un servidor administrado mediante claves SSH, medidas especialmente importantes son:

usar autenticación por clave pública
no permitir login directo de root
restringir SSH en la capa de red cuando sea viable
revisar autenticaciones exitosas, no solo fallidas
mantener OpenSSH actualizado

Si puedes restringir el puerto SSH para que solo determinadas redes lleguen a él, eso es mejor que dejar que cada scanner del planeta alcance sshd y confiar después en Fail2Ban.

Cambiar el puerto SSH no es la solución principal

Mover SSH del puerto 22 a otro puerto puede reducir muchísimo el ruido de bots que escanean únicamente puertos comunes.

Pero no convierte el servicio en seguro.

Un scanner que haga descubrimiento de puertos seguirá encontrándolo.

Es una técnica para reducir ruido operativo, no una frontera de seguridad equivalente a:

claves públicas
restricciones de red
firewall
configuración segura de sshd

Un pequeño pipeline de detección útil

Para investigar rápidamente un servidor expuesto podemos empezar así.

Ver intentos contra usuarios inexistentes:

sudo journalctl -u ssh --no-pager | grep 'Invalid user'

Contarlos:

sudo journalctl -u ssh --no-pager \
  | grep 'Invalid user' \
  | wc -l

Encontrar las IP más frecuentes:

sudo journalctl -u ssh --no-pager \
  | grep 'Invalid user' \
  | sed -n 's/.* from \([^ ]*\) port.*/\1/p' \
  | sort \
  | uniq -c \
  | sort -nr \
  | head

Encontrar los usuarios más probados:

sudo journalctl -u ssh --no-pager \
  | grep 'Invalid user' \
  | sed -n 's/.*Invalid user \([^ ]*\) from.*/\1/p' \
  | sort \
  | uniq -c \
  | sort -nr \
  | head

Y revisar autenticaciones relevantes:

sudo journalctl -u ssh --no-pager \
  | grep -E 'Failed password|Accepted password|Accepted publickey'

Después, Fail2Ban puede convertir ese análisis manual en una respuesta automática.

La idea que me llevo

El descubrimiento interesante no son realmente las 9.890 líneas del journal.

Es este cambio de perspectiva:

antes:
veo una IP mala → la bloqueo manualmente

mejor:
observo un comportamiento → detecto el patrón → respondo automáticamente

mejor todavía:
respondo localmente → comparto la señal de abuso

journald nos da evidencia.

Fail2Ban convierte esa evidencia en una acción defensiva.

AbuseIPDB permite convertir el ban local en una señal que también puede servir a otros administradores.

Ese es un ejemplo pequeño pero muy claro de defensa automatizada y colaborativa.

Fuente