Ir al contenido principal
Infraestructura & Seguridad · 8 min

Endurecimiento de servidores Linux en producción: seguridad en profundidad con CrowdSec, redes privadas y contenedores no-root

Guía práctica de hardening para servidores dedicados y VPS empresariales: configuración de kernel sysctl, cierre de puertos públicos con red privada y mitigación de amenazas automatizada.

Pablo Fesa
Pablo Fesa Software Architect & Tech Lead

Muchos equipos de desarrollo asumen que la seguridad en la nube se reduce a configurar un grupo de seguridad en AWS o confiar en el firewall por defecto de su proveedor de VPS.

La realidad en internet es implacable: en cuanto levantas una máquina con una IP pública, los escaneos automatizados de puertos, ataques de fuerza bruta contra SSH y pruebas de vulnerabilidades en servicios web comienzan en cuestión de minutos. Si mantienes puertos de administración abiertos o ejecutas contenedores con privilegios de root, tu infraestructura está a un exploit de distancia de un compromiso total.

En este artículo resumo las medidas fundamentales de seguridad en profundidad que aplicamos en cada servidor dedicado y entorno de producción que gestionamos.

Principio 1: Cero puertos de administración expuestos a internet

El error más común es mantener el puerto 22 (SSH) o paneles de gestión (Portainer, bases de datos, métricas) escuchando en 0.0.0.0.

La regla de oro es sencilla: ningún servicio interno debe tener una interfaz pública.

Para lograrlo sin complicar el día a día del equipo:

  1. Malla privada con Tailscale: el acceso SSH y los paneles internos solo escuchan en la interfaz privada virtual. Si un atacante escanea la IP pública del servidor, esos puertos simplemente no existen para él.
  2. Autenticación exclusivamente por clave SSH: contraseñas desactivadas en sshd_config, autenticación root directa deshabilitada y timeouts agresivos de desconexión por inactividad.
# /etc/ssh/sshd_config.d/hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

Principio 2: Parámetros del kernel (sysctl) para mitigar ataques de red

El stack de red por defecto de la mayoría de distribuciones Linux está pensado para compatibilidad genérica, no para resistir ataques dirigidos. Mediante /etc/sysctl.d/99-security.conf endurecemos el comportamiento del kernel frente a spoofing, ataques SYN flood y redirecciones maliciosas:

# Ignorar peticiones ICMP broadcast
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Protección contra ataques SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2

# Deshabilitar aceptación y reenvío de paquetes ICMP redirect
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Verificación estricta de ruta inversa (previene IP spoofing)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Deshabilitar source routing
net.ipv4.conf.all.accept_source_route = 0

Principio 3: Defensa colaborativa activa con CrowdSec

Fail2ban ha sido el estándar durante años para bloquear IPs tras varios intentos fallidos. Sin embargo, su enfoque es puramente reactivo y aislado: cada máquina aprende de sus propios ataques.

CrowdSec moderniza este concepto añadiendo inteligencia colectiva:

  • Analiza registros de Nginx, SSH y aplicaciones en tiempo real mediante escenarios declarativos en YAML.
  • Cuando una IP maliciosa intenta escanear directorios sensibles o forzar credenciales, CrowdSec la bloquea en el firewall (nftables o iptables) a nivel de kernel con un coste de CPU insignificante.
  • Las IPs bloqueadas se cruzan con una lista de reputación global compartida por miles de servidores en todo el mundo. Tu máquina bloquea atacantes conocidos antes de que lleguen a tocar tus servicios.

Principio 4: Contenedores sin privilegios de root (Rootless)

El comando docker run por defecto ejecuta los procesos internos del contenedor con el UID 0 (root). Si una vulnerabilidad de escape de contenedor (como una brecha en el kernel o en runc) tiene éxito, el atacante obtiene control total sobre el sistema operativo anfitrión.

Para mitigar este riesgo:

  1. Espacios de nombres de usuario (userns): los procesos dentro del contenedor corren como un usuario sin privilegios en el host (UID 10001), de modo que un escape no concede permisos administrativos en la máquina.
  2. Sistemas de ficheros en sólo lectura (read-only): montamos el contenedor con read_only: true y utilizamos volúmenes temporales en memoria (tmpfs) únicamente para las rutas que requieren escritura transitoria (/tmp, /run).
  3. Eliminación de capacidades de Linux (drop all capabilities): retiramos todas las capacidades del kernel y solo habilitamos explícitamente las estrictamente necesarias (como NET_BIND_SERVICE si el contenedor debe escuchar en puertos privilegiados).
# docker-compose.yml endurecido
services:
  api:
    image: fesa-api:production
    read_only: true
    user: "10001:10001"
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    tmpfs:
      - /tmp:rw,noexec,nosuid

Conclusión

La seguridad en infraestructura no consiste en instalar herramientas complejas y caras. Consiste en reducir la superficie de ataque al mínimo estricto:

  • Si no está expuesto, no se puede escanear.
  • Si el kernel verifica rutas, no se puede suplantar.
  • Si el contenedor no tiene privilegios de root, un exploit no puede tomar el control del servidor.

Aplicar estos fundamentos desde la instalación inicial te ahorra incidentes de seguridad, fugas de datos y noches en vela apagando fuegos en producción.

Temas: #Linux #Seguridad #Tailscale #CrowdSec #DevOps
Sigue leyendo

Artículos Relacionados

¿Necesitas diseñar sistemas resistentes sin sobrecostes de infraestructura?

Hablemos 15 minutos en una sesión de diagnóstico técnico con Pablo para auditar tus cuellos de botella y definir la arquitectura adecuada.