
🌐 También en: English · Deutsch · Français
Un blog y dos servidores Nextcloud para asociaciones locales: en ninguno de ellos hay nada que merezca un ataque dirigido, y justo por eso los atacan. No alguien que quiera mis datos, sino escáneres que prueban cada dirección IP de internet, cada hora, siempre con el mismo puñado de trucos. La mayoría se rinde ante la primera puerta cerrada. La pregunta es qué pasa con los que no se rinden.
La respuesta tiene nombre: Defense in Depth, la defensa en profundidad. Ninguna medida tiene que ser perfecta, porque detrás de cada capa hay otra. Este artículo reúne todas las capas que tienen ya mis servidores y luego hace algo un poco incómodo: le pedí a mi coadministrador de IA (Claude) que leyera todo lo que he publicado sobre esta instalación y que pensara como un atacante. ¿Por dónde empezaría?
🧅 Por qué un solo muro no basta
Toda medida de seguridad puede fallar. Una regla del cortafuegos recibe una errata. Un servicio que debería bloquear a los atacantes se para sin avisar: el mío lo hizo durante dos días y nadie se dio cuenta. Un plugin trae una vulnerabilidad un martes y el arreglo llega el jueves. Si una de estas cosas es lo único que hay entre internet y tus datos, estás a un mal día de una intrusión.
La defensa en profundidad le da la vuelta: da por hecho que cada capa fallará en algún momento y asegúrate de que la siguiente aguante igualmente. Tiene además una segunda ventaja, menos evidente: un atacante que atraviesa una capa tiene que hacer ruido para atravesar la siguiente, y el ruido se puede detectar.
🛡️ Las capas
1. El borde de la red
El cortafuegos (nftables) descarta todo lo que no está permitido expresamente: el tráfico web en 80/443 y SSH en un puerto no estándar. La monitorización, las bases de datos y los puertos internos solo responden en localhost o dentro del clúster. Además, SSH solo acepta conexiones nuevas desde rangos de IP de mi propio país: eso no detiene a nadie decidido (un servidor alquilado en el país adecuado es barato), pero elimina alrededor del 98 % del ruido de fondo, de modo que los intentos restantes llaman de verdad la atención.
2. SSH
Solo claves, nada de contraseñas, fijado en un fragmento de configuración que se ordena antes de todo lo que añade una imagen de nube, después de pillar la imagen de un proveedor reactivando en silencio el acceso por contraseña. Además, sshd se ejecuta en un sandbox de systemd que hereda cada sesión: no se pueden cargar módulos del kernel ni cambiar parámetros del kernel. Root puede hacerlo igualmente a propósito con systemd-run, así que es un obstáculo y no un muro, pero la secuencia clásica de «entrar y cargar un módulo rootkit» falla, y la carga de módulos queda registrada en el log de auditoría de todos modos.
3. Bloqueo automático
fail2ban lee el log de SSH y el log de acceso del servidor web y bloquea las direcciones que adivinan contraseñas, buscan archivos conocidos o machacan las páginas de inicio de sesión. Los reincidentes quedan bloqueados mucho más tiempo. Los bloqueos van directamente al cortafuegos, y un vigilante reinicia fail2ban si alguna vez vuelve a caerse.
4. El servidor web
Solo TLS, con cabeceras de seguridad estrictas. Las URL de inicio de sesión tienen límite de peticiones. Las rutas que encantan a los atacantes (archivos de configuración, .env, .git, el XML-RPC de WordPress) se bloquean antes de llegar siquiera a PHP, y WordPress ya no revela sus nombres de usuario a través de la API REST.
5. Contenedores
Las aplicaciones se ejecutan en Kubernetes (K3s). Las NetworkPolicies deciden qué pod puede hablar con cuál: un WordPress comprometido no puede conectarse sin más a lo que quiera. Una política de admisión solo permite imágenes de contenedor de registros aprobados, los tokens de las cuentas de servicio no se montan donde no hacen falta y SELinux está en modo «enforcing», así que un contenedor solo puede escribir en los directorios etiquetados expresamente para él.
6. Las propias aplicaciones
WordPress actualiza el núcleo, los plugins, los temas y las traducciones cada noche, con una copia de la base de datos antes y una comprobación después de que el sitio sigue respondiendo. Los plugins y temas sin usar se eliminan, no solo se desactivan, porque el código desactivado sigue siendo accesible. Nextcloud impone una política de contraseñas y frena los intentos de fuerza bruta; las cuentas de administración usan autenticación en dos pasos.
7. Detección
La prevención acaba fallando; la detección es cómo te enteras. AIDE comprueba cada noche si han cambiado archivos del sistema, rkhunter busca rootkits, ClamAV analiza los archivos subidos, auditd vigila los archivos de identidad, sudo y los secretos del clúster, y un vigilante (Monit) me envía un correo cuando un servicio, el cortafuegos, un certificado o la copia de seguridad no están en el estado esperado. Mientras todo va bien, todos guardan silencio, así que cada correo significa algo.
8. Recuperación
La última capa es la que esperas no necesitar nunca. Las copias de seguridad las recoge una máquina en mi casa, no las envían los servidores (un servidor comprometido no tiene credenciales para llegar a ellas), y se guardan con 30 días de historial, de modo que incluso algo que pasó desapercibido una semana se puede revertir.
9. El proceso
Todo lo anterior lo configura Ansible desde un repositorio Git, lo que convierte al repositorio en parte de la superficie de ataque. Los secretos solo viven en un vault cifrado que nunca toca Git. Cada commit pasa por un linter y un escáner de secretos. Las versiones están fijadas, las actualizaciones llegan como pull requests revisadas y cada cambio se ejecuta primero como simulacro contra los servidores reales antes de ejecutarse de verdad.
🕵️ Pensar como un atacante
Ahora viene la parte incómoda. Mi código de Ansible es público, y también lo son varios artículos sobre cómo están construidos estos servidores. Así que le pregunté a Claude: tú conoces todo esto, ¿por dónde empezarías?
La respuesta no fue «el cortafuegos» ni «SSH». Fue mucho más prosaica:
- Las aplicaciones. Un plugin o una app con una vulnerabilidad recién descubierta es, con diferencia, la vía de entrada más probable. Las actualizaciones nocturnas acortan esa ventana; no pueden cerrarla.
- Las personas. Uno de los servidores Nextcloud tiene más de cien cuentas. Una contraseña reutilizada o un correo de phishing convincente supera todas las capas técnicas anteriores, sin necesidad de ningún exploit.
- La cadena de suministro. Quien controle mi cuenta de Git o mi equipo de administración no necesita atacar los servidores: yo mismo desplegaría su código.
- Las cosas olvidadas. Cuentas que ya nadie usa, enlaces compartidos sin fecha de caducidad, ajustes antiguos que siguen dormidos en una base de datos.
La lección: una vez que lo técnico básico está en su sitio, los puntos débiles se trasladan a donde están las personas y los procesos.
🔑 Diseño público, claves secretas
Queda la pregunta evidente: ¿no es una imprudencia publicar todo esto? Los criptógrafos la respondieron en 1883. El principio de Kerckhoffs dice que un sistema debe seguir siendo seguro aunque todo sobre él sea público, excepto la clave. Así funciona todo el cifrado que usas hoy: los algoritmos están publicados, estudiados y atacados por expertos de todo el mundo, y siguen siendo seguros porque la clave sigue siendo secreta.
Mis servidores siguen la misma idea. Saber que SSH solo acepta claves, en qué puerto, desde qué país y tras qué reglas del cortafuegos no acerca a nadie ni un paso sin la clave privada. Saber que la configuración está en un vault de Ansible no sirve de nada sin la contraseña del vault. Saber que los administradores usan autenticación en dos pasos no sirve sin el móvil. El diseño es público; las claves nunca salen de donde deben estar.
Lo contrario, una seguridad que solo funciona mientras nadie sepa cómo funciona, es frágil: un documento filtrado, alguien de dentro con curiosidad, y desaparece. Ocultar detalles puede seguir costándole tiempo a un atacante, pero solo como capa adicional, nunca como base. Lo único que no debe publicarse es la lista de agujeros que todavía no están cerrados.
Y una cosa más, para quien lea esto con malas intenciones: no todas las capas están descritas en este artículo. Algunas de las protecciones y trampas de estos servidores se han dejado fuera a propósito: solo las descubrirás cuando las actives.
🔧 Lo que cambié después de esa conversación
- Autenticación en dos pasos para todas las cuentas de administración en los dos servidores Nextcloud y en el blog, con los códigos de respaldo impresos y sabiendo que el acceso por SSH siempre permite desactivarla si se pierde un móvil.
- Una política de contraseñas en los dos servidores Nextcloud: al menos 12 caracteres, nada de contraseñas muy comunes y ninguna contraseña que aparezca en filtraciones de datos conocidas. Esta última comprobación usa k-anonimato: solo los cinco primeros caracteres del hash de la contraseña salen del servidor.
- Cuentas inactivas desactivadas: todas las que llevaban más de un año sin iniciar sesión, más las que nunca la iniciaron; treinta en total, entre ellas un segundo administrador sin uso. Sus datos se conservan; las cuentas se pueden reactivar en segundos.
- Los enlaces públicos de subida caducan en lugar de quedarse abiertos para siempre.
- Tres sitios donde una contraseña podría haber acabado en un log (solo con un diff o un mensaje de error, pero aun así) ahora están ocultos.
Y un error, confesado. Activar la política de contraseñas en el Nextcloud más grande despertó un ajuste heredado del servidor antiguo: las contraseñas caducan a los 300 días. Durante unos minutos, todas las contraseñas más antiguas se consideraron caducadas, incluida la mía. Ahora el ajuste está fijado de forma explícita, y he aprendido a leer la configuración existente de una app antes de activarla.
🤝 La capa organizativa
No todo se resuelve con un archivo de configuración:
- Informar a los usuarios. Una nota breve sobre gestores de contraseñas, autenticación en dos pasos y phishing («Nextcloud nunca te pedirá la contraseña por correo») protege más que cualquier ajuste del servidor.
- Planificar mi propia ausencia. ¿Quién puede sustituirme si yo no puedo? ¿Dónde se guardan los códigos de recuperación y la contraseña del vault: en papel, en un sobre cerrado, no solo en mi cabeza?
- Revisar con regularidad. Un repaso mensual breve: nuevas cuentas de administración, enlaces compartidos abiertos, cualquier cosa rara en los logs de auditoría y de bloqueos.
🎯 Conclusión
Ninguna de estas capas impresiona por sí sola, y todas se pueden esquivar de alguna forma. Juntas convierten «un error y se acabó» en «varios errores, y cada uno se detecta». Esa es toda la idea de la defensa en profundidad, y la mirada del atacante me enseñó que las próximas capas no son más reglas de cortafuegos, sino cuentas, costumbres y los equipos desde los que administro.





