Proyectos
Seguridad · Defensa en profundidad

La seguridad no es una capa:
son todas a la vez

El reto: un VPS recién creado empieza a recibir ataques automatizados a los minutos de estar en línea. Sobre él debía construirse una plataforma pública. La respuesta no es una medida, sino un ecosistema: capas independientes donde cada una asume que la anterior puede fallar.

Las capas, del perímetro al interior
UFW deny por defecto · 3 puertos fail2ban baneo automático sshd solo clave · sin root PERÍMETRO INTERIOR DEL HOST DOCKER-USER exposición explícita red interna sin salida a Internet auditd · sysctl trazabilidad · kernel unattended- upgrades parches de seguridad continuos

Ninguna capa confía en las demás. Si UFW fallara, los servicios internos siguen sin puertos publicados; si un contenedor se comprometiera, su red no tiene salida a Internet; si alguien tocara la configuración, auditd lo habría registrado. Sobre esta base se apoyan las capas superiores: el pipeline sin SSH expuesto y la firma de imágenes con Cosign.

Las decisiones, y su porqué
01
Cerrar la puerta de entrada, con red de seguridad
ProblemaSSH es el servicio más atacado de cualquier servidor expuesto: a los minutos de arrancar, fail2ban ya había baneado 6 IPs con 47 intentos fallidos.
AlternativasContraseña robusta, o cambiar el puerto SSH. Lo segundo se descartó explícitamente: solo reduce ruido, no riesgo.
DecisiónSolo clave Ed25519, root deshabilitado, un único usuario permitido (AllowUsers) y máximo 3 intentos. El punto de no retorno se cruzó con método: la verificación del acceso por clave se hizo siempre en una segunda sesión, con la original abierta. Incluye neutralizar a cloud-init, que reactivaba la autenticación por contraseña en cada arranque.
02
Recuperar el control que Docker le quita al firewall
ProblemaDocker inserta sus reglas de iptables antes que las de UFW: un puerto publicado por un contenedor queda expuesto a Internet aunque el firewall lo tenga cerrado. Ningún hardening del host lo mitiga.
AlternativasConfiar en no publicar puertos por error, o mantener reglas de iptables a mano en cada despliegue.
Decisiónufw-docker: las reglas se reordenan en la cadena DOCKER-USER (IPv4 e IPv6) y ningún contenedor se expone sin autorización explícita. El modelo resultante: solo el proxy inverso publica 80/443; base de datos y automatización viven en una red interna con internal: true — sin puertos publicados y sin salida a Internet.
03
Adaptar las recetas, no copiarlas
ProblemaLas guías de hardening del kernel recomiendan rp_filter en modo estricto, pero ese modo descarta paquetes legítimos con rutas asimétricas: exactamente lo que generan las redes bridge de Docker.
AlternativasAplicar la guía tal cual y descubrir el problema después, en forma de contenedores sin red.
DecisiónModo loose (RFC 3704): protección anti-spoofing sin romper los contenedores. Junto a él, SYN cookies, rechazo de ICMP redirects y source routing, registro de paquetes anómalos y ASLR completo. Cada parámetro con su porqué, no como bloque copiado.
04
Parchear siempre, reiniciar cuando toque
ProblemaUn servidor sin parches es vulnerable; un servidor que se reinicia solo interrumpe servicios sin previo aviso.
AlternativasActualizarlo todo automáticamente (riesgo de roturas), o parchear a mano (riesgo de olvido).
Decisiónunattended-upgrades limitado exclusivamente a los orígenes de seguridad, sin reinicio automático: el parche se aplica solo, el reinicio se decide. Y trazabilidad con auditd: 12 reglas vigilando identidad, sudoers, configuración SSH, cron y módulos del kernel. Saber qué cambió y cuándo también es seguridad.
05
Proteger también lo que vive en contenedores
ProblemaLas jails clásicas de fail2ban actúan sobre la cadena INPUT, pero el tráfico hacia contenedores no pasa por ahí: un servicio dockerizado queda fuera de su alcance.
AlternativasDejar los servicios en contenedor sin protección frente a fuerza bruta, confiando solo en su autenticación.
DecisiónJails a medida para los servicios de la plataforma con una acción propia que inserta la regla de bloqueo en la posición 1 de DOCKER-USER: el drop ocurre antes de que el paquete llegue al contenedor. El mismo principio del perímetro, extendido a la capa que el perímetro no ve.
El resultado

Un host donde todo lo no autorizado está denegado por defecto: tres puertos abiertos de miles, acceso solo por clave, contenedores que no pueden exponerse por accidente, servicios internos sin salida a Internet, parches de seguridad aplicándose solos y 12 reglas de auditoría vigilando los puntos sensibles. No es una foto: fail2ban banea IPs cada día, y cada medida quedó verificada y documentada antes de apilar la siguiente.

UFWfail2banEd25519ufw-dockersysctlauditdunattended-upgradesDocker networks
Connect → Automate → Augment → Deploy.
La plataforma se construyó sobre esta base, no al revés: primero el suelo, después la casa.