Saltar al contenido
Categoria: Hardening10 min de lectura

Hardening de Linux Server: CIS Benchmark Aplicado sin Romper Produccion

Por Lucas Andrade ·

Como aplicar el CIS Benchmark en Debian y Ubuntu de produccion validando cada control, midiendo el impacto y manteniendo el SLA sin pasar la noche en rollback.

Hardening de Linux Server: CIS Benchmark Aplicado sin Romper Produccion
En este artículo

Aplicar el CIS Benchmark completo de golpe en un servidor Debian 12 que atiende 40 mil requests por minuto es la forma mas rapida de convertir un viernes en un incidente sev 1. En el equipo Basilisk vimos a mas de una empresa correr el playbook ansible-lockdown crudo en produccion y descubrir a las 3 de la madrugada que el control 5.2.16 desactivo el login del usuario que orquestaba el backup de Postgres. Hardening serio no es copiar 380 controles del PDF: es elegir los 60 que valen el riesgo, probar en staging con la misma carga y tener telemetria para saber en cuantos minutos revertis si algo se rompe en cliente. Este post es el runbook que usamos en engagements reales.

Por que <em>todo de golpe</em> fracasa#

Un PDF de CIS Benchmark lista Level 1 (conservador) y Level 2 (agresivo) por separado, pero la mayoria de los equipos aplana ambos en una sola lista de tareas y los aplica en una unica corrida de gestion de configuracion. El problema no es ningun control individual, es la combinatoria: 380 cambios simultaneos significan que cuando aparece una regresion ya no podes bisecar. Sabes que algo se rompio, pero no cual de las 380 lineas. Asi terminas a las 3 de la manana corriendo git revert sobre todo el playbook en vez de aplicar un fix quirurgico.

La segunda trampa es la falacia de idempotencia. Muchas remediations de CIS no son realmente idempotentes cuando el estado inicial difiere de lo que asume la tarea. Un task que reescribe /etc/pam.d/common-auth asume un stack default especifico. Si el host ya tiene un modulo SSSD o Kerberos, la linea nueva cae en el orden equivocado y bloqueas todo login federado. El arreglo es siempre el mismo: batches chicos, validacion entre cada batch, y un camino de rollback documentado antes de escribir la primera linea.

Los cuatro buckets#

El punto de partida correcto es separar los controles en cuatro buckets antes de tocar el servidor. Bucket 1: kernel y boot (sysctl, GRUB, modulos), bajo riesgo de romper la app, ganancia alta. Bucket 2: red y firewall (nftables, IPv6, ICMP), riesgo medio si no mapeaste todos los puertos. Bucket 3: autenticacion, PAM y SSH, donde vive la mayoria de los incidentes post-hardening. Bucket 4: auditd, syslog e integridad con AIDE, riesgo operativo casi nulo.

El orden es deliberadamente contraintuitivo: empeza por el 4, despues el 1, despues el 2, y deja SSH y PAM para el final. Arrancas donde nada puede romperse (auditoria), juntas telemetria del comportamiento normal, despues endureces el kernel, despues la red, y solo tocas la capa de auth cuando verificaste un segundo canal de acceso (consola, gestion out-of-band, una segunda clave SSH en un puerto separado). Si estas rehaciendo SSH, lee Hardening de SSH 2026: Algoritmos, Certificados y Bastion Hosts antes de tocar sshd_config porque los algoritmos cambiaron en 2026.

Inventariar el estado actual con OpenSCAP#

Para inventariar el estado actual usa openscap-scanner con el profile xccdf_org.ssgproject.content_profile_cis_level2_server del proyecto ComplianceAsCode. Una invocacion real es oscap xccdf eval --profile cis_level2_server --results scan.xml --report scan.html /usr/share/xml/scap/ssg/content/ssg-ubuntu2404-ds.xml. En un Ubuntu 24.04 limpio vas a ver entre 110 y 140 controles en fail, eso es esperado y no motivo de panico.

Exporta el HTML, importalo en Jira como una epica por bucket y estima esfuerzo en puntos de riesgo, no en horas. El truco es nunca aplicar una remediation sin leer el rationale: la mitad de las recomendaciones de CIS Level 2 rompen workloads modernos. Desactivar usb-storage tiene sentido en un bastion, no en un host que escribe dumps en un pendrive cifrado para air gap regulatorio. Trata el scan como documento vivo: corrilo despues de cada batch y segui el progreso como curva, no como foto fija.

Capa de kernel y sysctl#

La capa de kernel da una ganancia enorme con poco riesgo si sabes que estas tuneando. kernel.kptr_restrict=2, kernel.dmesg_restrict=1, kernel.yama.ptrace_scope=2 y fs.protected_hardlinks=1 son gratis contra fugas locales de informacion y races de symlink. Suma net.ipv4.conf.all.rp_filter=1, net.ipv4.tcp_syncookies=1 y kernel.randomize_va_space=2, y pone todo en un /etc/sysctl.d/60-cis.conf versionado en vez del sysctl.conf principal para que un upgrade de paquete no pise tus cambios.

En cambio kernel.unprivileged_userns_clone=0 rompe Docker rootless, Podman, Bubblewrap y cualquier sandbox de aplicacion, asi que si corres contenedores o usas las tecnicas de Sandbox de Aplicaciones en Linux con Bubblewrap, Firejail y Flatpak dejalo en 1 y documenta el desvio formalmente. En el boot agrega GRUB con password (CIS 1.4.x), Secure Boot con modulos firmados y blacklist de modulos de filesystem no usados (cramfs, udf, usb-storage). Para servicios con alto perfil de ataque considera SELinux enforcing con politica targeted custom, como detallamos en SELinux sin Miedo: Politicas Personalizadas para Servicios Criticos con ejemplo para un Nginx expuesto a internet.

Red y firewall con nftables#

Antes de escribir una sola regla de firewall, mapea cada puerto en escucha con ss -tulpen y reconcilialo contra el servicio esperado. Un ruleset nftables alineado a CIS trabaja con default drop en input y forward mas una allowlist explicita. El auto-bloqueo mas comun ocurre cuando olvidas el trafico de loopback: sin iif lo accept, los sockets locales, los health checks y el loopback de la base colapsan, y la app tira timeouts opacos.

IPv6 es la trampa silenciosa. Muchos equipos endurecen IPv4 prolijo y dejan todo el stack IPv6 abierto, asumiendo que no esta ruteado. O deshabilitas IPv6 de forma consistente (net.ipv6.conf.all.disable_ipv6=1 mas el bootloader) o espejas cada regla IPv4 en la familia inet de nftables. La cobertura a medias es peor que ninguna porque genera falsa sensacion de seguridad. Testea cada cambio de regla con una segunda sesion abierta como salvavidas.

Auditd sin la inundacion de logs#

Auditd casi siempre se vuelve cuello de botella si copias el ruleset CIS sin pensar. Las reglas default generan entre 8 y 15 mil eventos por minuto en un host promedio, llenan /var/log en 6 horas y hacen que journald empiece a descartar. La receta que usamos en Basilisk es recortar las reglas de execve para usuarios de servicio conocidos (postgres, nginx, app) y dejar monitoreo agresivo solo para uid 0, sudo y shells interactivas.

Configura -b 8192 para el backlog, --backlog_wait_time 0 contra stalls del kernel, y reenvialo con audisp-remote o un plugin de auditd a un pipeline Sigma como mostramos en Threat Hunting con Sigma y Elastic: Del Indicador a la Regla de Deteccion. Si no, estas generando ruido caro sin ninguna deteccion accionable del otro lado. Pone -e 2 (reglas inmutables) recien al final, porque bloquea todo cambio de regla hasta el proximo reboot.

Un punto que se pasa por alto: auditd y el logging completo de execve cuestan CPU medible en servicios con muchos syscalls. En un reverse proxy que hace decenas de connect y openat por request, un ruleset demasiado amplio puede sumar 5 a 10 por ciento de latencia p95. Medilo explicitamente en el test de carga de staging y trata las reglas de audit como parte del presupuesto de performance, no como agregado gratis. La metrica correcta no es la cantidad de reglas, es eventos por segundo en operacion normal.

Validacion bajo carga real#

La validacion es la parte que nadie hace bien. Levanta un ambiente espejo en LXD o Proxmox con el mismo kernel, la misma glibc y las mismas versiones de servicios, y corre un perfil de carga con k6 o wrk replicando 30 minutos de trafico real capturado por tcpdump. Aplica los controles en lotes de 10, corre la prueba, compara p95 de latencia y tasa de error. Si la regresion supera el 3% aislas por biseccion cual control es el culpable.

Tambien corre atomic-red-team con tecnicas mapeadas a MITRE ATT&CK para confirmar que el hardening realmente reduce superficie: la logica es la misma de Adversary Emulation con Caldera y MITRE ATT&CK en Laboratorio Corporativo, pero enfocada en post-explotacion sobre el host endurecido. Si una tecnica sigue teniendo exito despues del hardening, tenes una brecha medible en vez de una suposicion.

Cripto de disco y acceso fisico#

Para servidores que tocan datos sensibles o que no podes acceder fisicamente, complementa el hardening con cifrado de disco resistente a coercion y backup verificado siguiendo lo que discutimos en Cripto de Disco y Backups: VeraCrypt, LUKS y Estrategia 3-2-1 Resiliente. LUKS2 con Argon2id, clave en TPM2 sellada con PCR0+PCR7 y snapshot cifrado en storage offsite resuelven el caso de robo fisico del datacenter.

Combinado con Secure Boot, modulos firmados y GRUB con password (controles CIS 1.4.x), elevas el costo de un ataque presencial a algo que solo vale la pena contra blancos muy especificos. Una advertencia: una clave sellada en TPM sin passphrase de recuperacion probada es una bomba de tiempo. El dia que un update de firmware cambia los valores PCR, la maquina no bootea, y sin passphrase guardada el disco es basura de datos.

Checklist practico#

Antes de declarar un host endurecido como terminado: (1) score de OpenSCAP documentado antes y despues; (2) un segundo camino de acceso (consola/OOB) verificado antes de tocar SSH; (3) todos los cambios sysctl versionados en /etc/sysctl.d/; (4) nftables con iif lo accept y comportamiento IPv6 testeado; (5) auditd bajo 3000 eventos por minuto en reposo; (6) test de carga en staging con menos de 3% de regresion p95; (7) una corrida de atomic-red-team que prueba las tecnicas cerradas; (8) un camino de rollback documentado y ensayado una vez.

FAQ: Level 1 o Level 2?#

Para servidores expuestos a internet sin mandato estricto de compliance, Level 1 completo mas controles seleccionados de Level 2 de los buckets 1 y 4 es el mejor punto costo-beneficio. Level 2 completo tiene sentido para workloads regulados (PCI-DSS, exigencias de gobierno), pero solo con un registro de excepciones documentado para los controles que rompen tu workload especifico. Level 2 a ciegas en un host de contenedores es una caida con certificado adjunto.

FAQ: cada cuanto re-escanear? En cada release mayor del SO (point release Debian, upgrade LTS) y al menos trimestral como scan automatico por cron cuyo resultado fluye a los mismos dashboards que tus metricas. El drift es inevitable porque los upgrades de paquete resetean defaults de sysctl y los servicios nuevos abren puertos nuevos.

FAQ: Ansible, script Bash o baking de imagen? Para una flota, una golden image endurecida (Packer mas la lista de controles revisada, desplegada de forma inmutable) es mas robusta que una corrida de Ansible contra hosts vivos, porque el drift practicamente desaparece. Ansible sigue sirviendo para el primer ciclo iterativo y para hosts que no podes reconstruir. Un script Bash puro sin idempotencia es la peor opcion: no se puede repetir limpio ni revertir confiable. Elijas lo que elijas, la lista de controles debe estar versionada y revisable, no enterrada en una wiki de runbook.

Takeaway practico: arma una planilla con cada control CIS aplicado, la version del paquete al momento, el resultado de openscap pre y post, y el delta de latencia medido en staging. Corre esa planilla en cada release mayor del SO porque los sysctl cambian de default y auditd suma campos nuevos. Hardening no es proyecto, es proceso: si en 6 meses no podes probar via scan automatizado que los 60 controles siguen activos en el host, no tenes hardening, tenes fe.

Related posts

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly