En el artículo anterior expliqué el script que uso para auditar mis servidores y cómo ejecutarlo. Ahora toca la parte más importante: leer el output sin entrar en pánico ni ignorar lo que de verdad importa.
Porque el output de una auditoría tiene mucho ruido. Cosas que parecen graves y no lo son. Cosas que parecen menores y son urgentes. Y cosas que directamente no aplican a tu caso. Saber distinguirlas es la mitad del trabajo.
Antes de entrar en materia, un contexto personal: no parto de cero en esto de la seguridad en servidores Linux. Hace unos años hice una serie completa sobre hardening en Raspberry Pi — desde actualizar el firmware hasta auditoría con Lynis, pasando por SSH, UFW, rkhunter, fail2ban y copias de seguridad. Sabía lo que tenía que tener. Lo que no esperaba era encontrar que no lo tenía.
Lo primero que miré: usuarios y accesos
Esta sección suele ser la más reveladora. Lo que encontré en el servidor de producción:
▶ Últimos 20 intentos fallidos
root ssh:notty Wed Mar 25 08:03 2.57.122.195
root ssh:notty Wed Mar 25 08:02 2.57.122.195
root ssh:notty Wed Mar 25 08:02 2.57.122.195
...
9113 Failed password
3782 Invalid user
4522 89.185.81.112
4098 2.57.122.177
3295 144.217.76.59Más de 13.000 intentos fallidos de SSH en 25 días. Una sola IP con 4.522 intentos. Y el servidor sin fail2ban. Activo, escuchando, aguantando el chaparrón sin banear a nadie.
Esto no es una alerta menor. Es el problema más urgente del output y lo primero que hay que resolver.
Lo que hay que buscar en esta sección:
- IPs con muchos intentos: más de 100 intentos desde una misma IP en pocos días es un escaneo activo.
- Usuarios inusuales: intentos con usuarios como
oracle,ubnt,solanaocertbotindican diccionarios de credenciales comunes. - Logins exitosos desde IPs desconocidas: si ves un
Acceptedde una IP que no reconoces, para todo lo demás. - Solo una clave SSH por usuario: si
authorized_keystiene más claves de las esperadas, investiga.
Puertos abiertos: lo que escucha en 0.0.0.0
El script filtra específicamente los puertos que escuchan en todas las interfaces. Esto es lo que salió:
tcp LISTEN 0.0.0.0:80 nginx
tcp LISTEN 0.0.0.0:443 nginx
tcp LISTEN 0.0.0.0:22 sshd
tcp LISTEN *:9080 promtail
tcp LISTEN *:46697 promtailLos tres primeros son esperables. Los dos últimos no. Promtail — el agente que envía logs a Loki — estaba escuchando en todas las interfaces en lugar de solo en localhost. No era accesible desde internet porque UFW lo bloqueaba, pero era una configuración incorrecta que conviene corregir.
La regla general es simple: si un servicio no necesita ser accesible desde fuera, no debería escuchar en 0.0.0.0. Debería hacerlo en 127.0.0.1.
Lo que es normal ver en 0.0.0.0:
- Puerto 80 y 443 (Nginx, tráfico web)
- Puerto 22 (SSH)
- Puerto de WireGuard
Lo que no debería estar ahí:
- Puertos de monitorización (Prometheus, Loki, Promtail)
- Paneles de administración
- Bases de datos (MySQL en
127.0.0.1:3306es correcto; en0.0.0.0:3306sería un problema grave)
Servicios: lo que corre sin que lo sepas
Esta sección tiene mucho ruido. La lista de servicios activos puede ser larga e intimidante. El truco es filtrar por lo que no debería estar ahí.
En mi caso encontré dos cosas relevantes:
PHP 8.3 y PHP 8.4 corriendo a la vez. Los tres sitios del servidor ya usaban 8.4. La 8.3 era un residuo de la migración, consumiendo memoria sin hacer nada.
Snapd habilitado en boot. En un servidor de producción sin ningún snap instalado. Seis servicios de systemd arrancando en cada reboot para gestionar paquetes que no existen.
También encontré multipathd activo — un servicio para gestionar múltiples rutas a discos SAN/iSCSI. En un VPS con un único disco virtual no tiene ningún sentido.
Lo que hay que buscar:
- Versiones duplicadas de servicios (dos versiones de PHP, dos de Python...)
- Servicios de gestión de paquetes que no usas (snapd, flatpak)
- Servicios de hardware que no aplican a un VPS (multipathd, open-iscsi)
- Servicios cloud que ya no tienen utilidad una vez el servidor está configurado (cloud-init)
Actualizaciones: el reboot pendiente silencioso
▶ Reboot pendiente
/var/run/reboot-requiredEste fichero existe cuando hay actualizaciones instaladas que requieren reinicio — normalmente el kernel o glibc. El servidor llevaba días con un kernel nuevo instalado pero sin cargar.
No es urgente como el fail2ban, pero es el tipo de cosa que se acumula. Un servidor que lleva semanas sin reiniciar tras un kernel update de seguridad es un riesgo innecesario.
También hay que revisar los paquetes actualizables. Si aparecen paquetes de seguridad sin instalar y unattended-upgrades está habilitado, algo no está funcionando bien.
Logs: el tamaño importa
1.3G /var/log/journal
151M /var/log/btmp
68M /var/log/btmp.1El journal ocupando 1.3 GB en un VPS con 38 GB de disco no es un problema crítico, pero es una señal de que nadie ha configurado límites. El fichero btmp — que registra los intentos fallidos de login — llegaba a 151 MB, consecuencia directa de los 13.000 intentos sin fail2ban baneando a nadie.
Lo que parece grave y no lo es
El script también devuelve cosas que a primera vista asustan pero son completamente normales:
World-writable dirs en /var/lib/containerd/: son capas de overlayfs de contenedores Docker. Así funcionan por diseño.
Ficheros SUID en /var/lib/containerd/: binarios del sistema dentro de la imagen del contenedor. No son SUID en el host, solo dentro del sistema de ficheros del contenedor.
Muchos servicios marcados como UNSAFE por systemd-analyze: Lynis también lo reporta. La mayoría son servicios del sistema que no tienen sandboxing de systemd configurado. Es una mejora avanzada que tiene poco impacto real para la mayoría de casos.
Lynis: la puntuación de partida
Con todo esto sobre la mesa, pasé Lynis para tener un número de referencia:
Hardening index : 68
Tests performed : 269
Warnings : 1
Suggestions : 4668 sobre 100. No es un desastre, pero hay margen. El único warning real era la ausencia de repositorio de seguridad en sources.list — un artefacto de usar los repos de PHP de sury.org. Las 46 sugerencias van desde cosas críticas a recomendaciones que no tienen ningún sentido para un VPS.
En el próximo artículo, qué hice con todo esto: qué arreglé, en qué orden, qué decidí ignorar y por qué. Y cómo quedó la puntuación al final.