5 puntos por GN⁺ 2025-08-20 | 1 comentarios | Compartir por WhatsApp
  • systemd ofrece potentes funciones de gestión de servicios, pero su configuración predeterminada está optimizada para la usabilidad más que para la seguridad, por lo que es necesario aplicar opciones adicionales de hardening
  • Con el comando systemd-analyze security se puede analizar el indicador de exposición de seguridad de todos los servicios o de un servicio específico, y así definir prioridades
  • Existen diversas opciones de seguridad que pueden aplicarse a nivel de unidad de servicio, y pueden modificarse de forma individual mediante /etc/systemd/system/ServiceName.service.d/override.conf y similares
  • Entre las opciones principales están ProtectSystem, PrivateTmp, NoNewPrivileges, SystemCallFilter, MemoryDenyWriteExecute, entre otras que limitan los privilegios del proceso y el acceso a recursos
  • Más que buscar una seguridad perfecta, conviene priorizar el hardening de los servicios expuestos al exterior para reducir riesgos; esto también puede ser muy útil en entornos de self-hosting

Resumen de systemd

  • systemd ofrece un enfoque muy maduro y robusto para la gestión de servicios
  • Sin embargo, prioriza la facilidad de uso inmediata por encima de la seguridad, por lo que la configuración predeterminada es flexible
  • Este documento presenta varias opciones de refuerzo de seguridad que pueden aplicarse a unidades de servicio de systemd y a podman quadlet para reducir la posibilidad de compromiso y minimizar el impacto si ocurre una intrusión
  • No es una guía para aplicar todo de forma masiva a todos los servicios; cada servicio requiere pruebas individuales, revisión de logs y ajustes según sus características y funciones necesarias
  • La responsabilidad de la seguridad de la infraestructura recae por completo en el operador, y este documento es solo una herramienta de referencia

Análisis de seguridad de systemd

  • Con el comando systemd-analyze security se puede revisar el estado de seguridad de todos los servicios o analizar la configuración detallada de un servicio específico (por ejemplo, sshd.service)
    • La salida incluye si cada verificación se cumple, el nombre de la función, la descripción y la puntuación de Exposure; cuanto mayor sea Exposure, mayor será el riesgo
  • Las opciones de seguridad pueden agregarse en la sección [Service] (systemd) o en la sección [Container] (podman quadlet)
  • Se recomienda crear un archivo override con systemctl edit ServiceName.service; si algo falla, hay que revisar los permisos necesarios y ajustarlos

Opciones de seguridad para servicios

  • systemd ofrece varias palabras clave de opciones de seguridad, que pueden consultarse con man systemd.exec 5, man capabilities 7, etc.
  • Opciones representativas relacionadas con seguridad
    • ProtectSystem → opción para restringir el sistema de archivos a solo lectura
    • ProtectHome → opción para bloquear el acceso a /home, /root, /run/user
    • PrivateDevices → opción para bloquear el acceso a dispositivos físicos y permitir solo dispositivos virtuales como /dev/null
    • ProtectKernelTunables, ProtectKernelModules, ProtectKernelLogs → opciones para bloquear el acceso a recursos del kernel
    • NoNewPrivileges → opción para impedir la obtención de nuevos privilegios mediante setuid/setgid, etc.
    • MemoryDenyWriteExecute → bloquea el uso simultáneo de memoria escribible y ejecutable; puede causar problemas en algunos lenguajes con JIT
    • SystemCallFilter → opción para limitar las system calls permitidas; en caso de violación puede terminar el proceso o devolver EPERM

Explicación de cada opción

  • ProtectSystem: con strict, monta todo el sistema de archivos como solo lectura; /dev, /proc, /sys requieren opciones de protección aparte
  • ReadWritePaths: vuelve a permitir escritura solo en rutas específicas
  • ProtectHome: bloquea el acceso a /home, /root, /run/user
  • PrivateDevices: desactiva el acceso a dispositivos físicos y permite solo pseudo-dispositivos como /dev/null
  • ProtectKernelTunables: deja /proc y /sys en modo solo lectura
  • ProtectControlGroups: permite solo acceso de lectura a cgroups
  • ProtectKernelModules: prohíbe la carga explícita de módulos del kernel
  • ProtectKernelLogs: restringe el acceso al búfer de logs del kernel
  • ProtectProc: con invisible, oculta en /proc/ los procesos que pertenecen a otros usuarios
  • ProcSubset: bloquea en /proc el contenido distinto de ciertos elementos relacionados con PID
  • NoNewPrivileges: bloquea nuevas elevaciones de privilegios mediante setuid, setgid y filesystem capabilities
  • ProtectClock: bloquea la escritura al reloj del sistema/hardware
  • SystemCallArchitectures: con native, permite solo syscalls nativas como x86-64
  • RestrictNamespaces: limita namespaces orientados a contenedores
  • RestrictSUIDSGID: bloquea la configuración de los bits setuid y setgid en archivos
  • LockPersonality: evita cambios del dominio de ejecución (solo necesario en aplicaciones antiguas, etc.)
  • RestrictRealtime: limita la planificación en tiempo real (solo necesaria en algunos servicios de propósito especial)
  • RestrictAddressFamilies: limita las familias de direcciones de socket permitidas (por ejemplo, AF_INET, AF_INET6, AF_UNIX, etc.)
  • MemoryDenyWriteExecute: bloquea la creación adicional de regiones de memoria escribibles y ejecutables a la vez (precaución con servicios que usan JIT)
  • ProtectHostname: prohíbe el uso de las syscalls sethostname y setdomainname
  • SystemCallFilter: define syscalls permitidas o bloqueadas por servicio, con filtrado detallado
    • Se pueden ajustar grupos, syscalls individuales y el modo de permitir/bloquear
    • También permite devolver códigos de error como EPERM en lugar de terminar el proceso
    • La lista completa puede verse con systemd-analyze syscall-filter o man systemd.exec(5)
    • Con el prefijo ~ se puede negar una lista completa (por ejemplo, CapabilityBoundingSet=~CAP_SETUID)

Proceso de ajuste de restricciones de SystemCallFilter

  • Con auditd se puede revisar en los logs qué syscall fue bloqueada cuando falla un servicio
    • Ejecutar sudo ausearch -i -m SECCOMP -ts recent y revisar el valor de syscall
    • Luego se puede agregar esa syscall o el grupo relacionado a SystemCallFilter para resolver el problema de forma gradual

Prioridades para aplicar hardening y consejos operativos

  • No es necesario aplicar todo a todos los servicios
  • El modelo de amenazas y la gestión del riesgo son la clave; en especial, los servicios expuestos al exterior (httpd, nginx, ssh, etc.) deben considerarse de forma prioritaria
  • También es efectivo aplicarlo de forma preventiva a comandos personalizados, unidades timer (reemplazo moderno de cron), etc.
  • Cuanto más simple sea el servicio, mayor suele ser la posibilidad de hacer ajustes finos

Lista de verificación: combinación recomendada de opciones de seguridad (prioridad inicial de aplicación)

  • ProtectSystem=strict
  • PrivateTmp=yes
  • ProtectHome=yes o ProtectHome=tmpfs
  • ProtectClock=yes, ProtectKernelLogs=yes, ProtectKernelModules=yes
  • RestrictSUIDGUID=yes
  • UMask=0077
  • LockPersonality=yes
  • RestrictRealtime=yes
  • MemoryDenyWriteExecute=yes
  • DynamicUser=yes o definir User como un usuario específico distinto de root
  • En general, esta combinación puede usarse en servicios sin causar casi ningún problema
  • Si además se quiere aplicar filtrado de syscalls (SystemCallFilter), se requiere una prueba detallada

Ejemplo de configuración de Traefik

  • Es un caso de uso de un servicio Traefik basado en contenedores ejecutado con systemd quadlet y con varias opciones de seguridad aplicadas
    • Se aplican opciones como ProtectSystem=full, ProtectHome=yes, SystemCallFilter=@system-service @mount @privileged, etc.
    • Con CapabilityBoundingSet=~CAP_SETUID CAP_SETPCAP se eliminan ciertos privilegios
    • También se aplican restricciones de acceso de red como RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK

Conclusión

  • Las opciones de hardening de systemd son una herramienta práctica que vale la pena tener en la caja de herramientas de cualquier administrador de sistemas tipo Unix
  • No deben verse como una medida de seguridad perfecta, sino como una herramienta para reducir riesgos, y no es necesario aplicar configuraciones de seguridad indiscriminadamente a todos los servicios
  • En especial, pueden ayudar mucho a elevar el nivel de seguridad si las aprovechan administradores de entornos de self-hosting
  • Se recomienda priorizar la “practicidad por encima de la perfección” y aplicarlas хотя sea de forma parcial dentro del alcance que se ajuste al trabajo y al entorno

1 comentarios

 
GN⁺ 2025-08-20
Opiniones de Hacker News
  • Me parece interesante que se pueda implementar el hardening automatizado de servicios de systemd mediante perfilado con strace
    https://github.com/desbma/shh

    • Encontré un buen método: en el ejemplo no usaron ProtectSystem=, pero si haces algo como
      TemporaryFileSystem=/:ro, BindReadOnly=/usr/bin/binary /lib /lib64 /usr/lib usr/lib64
      puedes incluir solo el binario que quieres y las rutas que quieres permitir en modo lectura
      ProtectSystem= actualmente no es compatible con este comportamiento
      Para más detalles, ver aquí

    • Creo que este enfoque puede ser problemático para servicios que necesitan acciones adicionales cuando ocurre un error, como enviar un correo electrónico

  • En comparación con el post sobre hardening de systemd que salió ayer, este es mucho más realista y tiene muchos consejos buenos que se pueden aplicar de inmediato
    Ayer intenté dar ejemplos más prácticos en los comentarios del otro post, pero el de hoy organiza muy bien contenido realmente útil y muestra formas de reforzar rápida y fácilmente el aislamiento y la seguridad con systemd
    Me parece un gran artículo
    Dejo también el de ayer como referencia
    https://us.jlcarveth.dev/post/hardening-systemd.md
    https://news.ycombinator.com/item?id=44928504

    • Ojalá arreglen el problema del certificado del sitio
      En algunos navegadores ni siquiera se puede acceder por errores del certificado
  • Gracias por compartirlo
    Si usas systemd-analyze con la bandera --user, puedes revisar la seguridad de las unidades de usuario de systemd (systemd-analyze --user security)
    Empecé a usar más systemd al migrar contenedores a Podman, y esta herramienta será de mucha ayuda para mejorar la seguridad de servicios systemd/unidades de contenedores

  • Los scripts init antiguos eran todos diferentes, así que este tipo de hardening consistente era imposible

    • Claro, este tipo de hardening también se puede hacer con scripts init tradicionales, pero systemd ayuda a usar buenas funciones del kernel de una forma estándar, consistente y sencilla
      Yo llegué relativamente tarde a Linux, así que me cuesta imaginar un sistema sin systemd, y los sistemas sin systemd me parecían muy incómodos de manejar
      Hace poco descubrí la herramienta unshare, con la que pude experimentar cosas como volver a montar todo /nix en RW sin afectar a otros procesos
      systemd puede ser algo tosco en usabilidad, pero sinceramente para mí la única alternativa sería Windows
  • Me pregunto por qué las distribuciones de Linux no activan por defecto más de estos interruptores de seguridad
    Pienso si hay alguna desventaja en hacer un hardening conservador
    Para muchos usuarios puede haber demasiadas opciones y demasiada complejidad

    • Si cambias la configuración de manera demasiado agresiva, puedes romper ajustes existentes sin querer
      Por ejemplo, si hicieras hardening de NetworkManager, tendrías que verificar uno por uno que funcionen conexiones tanto IPv4 como IPv6, que los modos dns=systemd-resolved y dns=default operen bien, la integración con ModemManager y redes celulares, plugins de openvpn o cisco anyconnect, hooks de NetworkManager-dispatcher y muchas otras cosas
      Además, también está el problema de cuántos mantenedores de distribuciones pueden estar seguros de hasta qué punto pueden cambiar los interruptores de los paquetes que administran sin romper más del 0.01% de los entornos de usuario
      Si la distribución mantiene estas banderas, cada release upstream trae además problemas de compatibilidad; y si la configuración la hace upstream, por compatibilidad hacia atrás no les queda otra que usarlas con mucha más cautela

    • Esta pregunta es parecida a “¿por qué las distribuciones no usan MAC (como SELinux, etc.) más agresivamente por defecto?”
      También sería bueno restringir más cosas como sshd, pero

      1. el costo inicial de desarrollo para aplicarlo
      2. el costo de manejar reportes de bugs en toda clase de entornos de usuario
      3. el costo continuo de mantenimiento conforme cambian la distribución y upstream
        por todo eso la carga es grande para las distribuciones principales
        Con SELinux y AppArmor pasa lo mismo: muchos mantenedores consideran que el retorno de la inversión es bajo
    • Otra gran razón es que no tienen la capacidad ni los recursos para hacer pruebas de integración exhaustivas, parámetro por parámetro, del funcionamiento normal de servicios críticos del sistema
      Conversación relacionada
      https://news.ycombinator.com/item?id=29995566
      Los resultados de systemd-analyze security difieren según la distribución
      desbma/shh genera automáticamente reglas por unidad como SyscallFilter a partir de lo recopilado con strace, similar a audit2allow de SELinux
      Pero instalar strace en producción puede ser discutible
      https://github.com/desbma/shh

    • Yo tampoco lo tengo del todo claro, pero algunas configuraciones son relativamente nuevas, así que muchos usuarios quizá ni las conozcan bien
      No todos son expertos en systemd, y activar ciertos ajustes también puede implicar el riesgo de que no funcionen bien en versiones anteriores de systemd
      Hay varias funciones como SELinux y AppArmor, pero muchas distribuciones, desarrolladores y usuarios no sienten que sean estrictamente necesarias, así que es difícil aplicarlas automáticamente

  • Hay tantas opciones para hardening que estaría bien tener un repositorio con ejemplos generales de hardening por tipo de servicio
    A menudo los usuarios aprovechan scripts de hardening que otros aplican de forma común, pero luego uno descubre que, de manera inesperada, hay que dar permisos más amplios para que no fallen casos excepcionales

    • Al empaquetar en distribuciones con poco soporte upstream, como nixpkgs, lo más útil es ver cómo empaquetan y hacen hardening en distribuciones principales
      Esos métodos de hardening suelen estar bastante bien probados, así que si te interesan ejemplos para postgresql y otros, conviene empezar por los paquetes de Debian, Ubuntu o RHEL
  • Una de las excelentes funciones de seguridad que ofrece systemd es la gestión de credenciales
    Esto permite pasar credenciales a las aplicaciones de una manera más segura que guardarlas en variables de entorno o en el sistema de archivos
    En entornos sin Vault y similares, por ejemplo en proyectos personales, siempre prefiero este método
    Incluso hice yo mismo un paquete de Go que se integra con esta función
    credentials en systemd
    paquete credential-go

    • Me suena a esa cultura de nodejs o npm de hacer un paquete hasta para dos líneas de código
      En realidad sería algo como

      dir, err := os.Getenv("CREDENTIALS_DIRECTORY")
      cred, err := os.ReadFile(filepath.Join(dir, "name"))
      

      Ni siquiera es más complejo que left-pad
      Según entiendo, en la comunidad de Go antes se valoraba reducir dependencias y evitar abstracciones innecesarias (como llamadas a funciones)
      Este tipo de cosas simples normalmente cada quien las escribía al vuelo

    • Me pregunto cómo este método de entrega de credenciales evita que los procesos hijos creados por fork hereden las credenciales

  • Es un artículo realmente útil
    También me gusta que incluya una lista de opciones de systemd y consejos del tipo “consulta el man y buena suerte”
    systemd es realmente excelente y quiero desplegarlo activamente en mis servidores

  • Un detalle menor, pero la forma correcta de escribir systemd en el título es systemd
    No SystemD, system D ni system d, sino systemd
    La razón es que viene de system daemon, y siguiendo la tradición de Unix/Linux se usa un nombre que termina en d minúscula

    • Qué dato tan interesante
      Yo normalmente veía mucho systemD, así que me pregunto por qué esa forma se volvió tan común
  • El consejo para depurar problemas de syscalls en systemd es realmente muy útil