...

Capacidades de Linux: distribuir los derechos de root de forma segura y granular

Con Linux Capabilities, divido los derechos de root en privilegios pequeños y claramente definidos, lo que reduce drásticamente el riesgo. De este modo, controlo de forma específica qué procesos pueden realizar acciones especiales y limito la superficie de ataque de cada aplicación.

Puntos centrales

  • De grano fino En lugar de ser todopoderoso: dividir los derechos de root en privilegios más específicos.
  • Capacidades de los archivos En lugar de Set-UID: vincular los permisos necesarios directamente a los archivos binarios.
  • Conjuntos de capacidades Configurar de forma específica los parámetros «steueren»: «Permitted», «Effective», «Inheritable» y «Bounding».
  • Separación de privilegios: Separar estrictamente los servicios, las herramientas y las tareas.
  • Defensa en profundidad: Completar las capacidades con sudo, roles y protocolos.

¿Por qué separar los derechos de root?

Una cuenta de root permite Acceso total en el ámbito de los archivos y los procesos, pero precisamente eso da pie a errores con graves consecuencias. Basta un comando erróneo o un exploit para que se bloquee toda la instalación. Por eso limito las acciones de gran alcance a lo estrictamente necesario, reduciendo así la magnitud de los daños y el tiempo de recuperación. El principio de los derechos mínimos mantiene los servicios reducidos y controlables. Desactivo el inicio de sesión directo como root, apuesto por los roles y genero registros exhaustivos.

Explicación breve de las capacidades de Linux

Las capacidades de Linux desglosan los poderes clásicos del usuario «root» en derechos claramente definidos Privilegios. Cada proceso recibe únicamente los componentes que realmente necesita para su tarea, como la asignación de puertos por debajo de 1024 o el envío de señales especiales. De este modo, evito el antiguo enfoque de «todo o nada». El núcleo gestiona estos componentes por cada proceso y los aplica de forma estricta. De este modo, el control sigue siendo minucioso y trazable.

Desde el punto de vista técnico, relaciono las habilidades con Procesos (a través de sus conjuntos de capacidades) o a Archivos (como atributos extendidos capacidad de seguridad en los binarios ELF). En el execve()-Al iniciarse, el núcleo fusiona las capacidades de los archivos con los conjuntos de privilegios de los procesos: en términos sencillos, las capacidades permitidas del atributo del archivo, junto con los derechos heredables del proceso que realiza la llamada, se combinan para formar el nuevo conjunto «Permitted» y, si así se ha indicado, se activan al mismo tiempo en el conjunto «Effective». Esto evita los rodeos de Set-UID y mantiene los privilegios visibles y verificables.

Comprender los conjuntos de capacidades en el contexto de los procesos

Cada proceso cuenta con varios conjuntos de derechos que yo gestiono de forma específica control. El «Permitted-Set» define lo que un proceso puede tener en principio. El «Effective-Set» establece lo que está activo en cada momento. El «Inheritable-Set» regula qué privilegios pueden transmitirse a los procesos hijos. El «Bounding-Set» establece un límite máximo estricto e impide que los procesos lo superen.

Ambient Capabilities y Securebits

Además de los sets ya conocidos, está el Conjunto de música ambiental, que en el execve() no caduca automáticamente. Lo utilizo cuando un proceso sin privilegios necesita, de forma específica, derechos mínimos en varios exec-que se mantengan a pesar de los saltos (por ejemplo, al ejecutar programas auxiliares externos). Los derechos «ambient» solo se tienen en cuenta en los derechos efectivos si el propio archivo ejecutado no establece capacidades de archivo; de este modo, evito una escalada no deseada.

Con los Securebits controlo los detalles de las transiciones, por ejemplo, si un proceso puede conservar las capacidades que tenía antes tras el cambio de UID (keepcaps) o si, en general, no puede obtener nuevos privilegios (no_new_privs). En la práctica, configuro Securebits de forma estricta y renuncio a la comodidad para romper las cadenas de exploits.

Capacidades de archivo en lugar de Set-UID

Sustituyo los binarios con Set-UID por capacidades de archivo para reducir el riesgo de bajar. En lugar de otorgar privilegios de root a un programa, solo le asigno los derechos necesarios. Un cambio típico es el siguiente: setcap 'cap_net_bind_service=+ep' /usr/bin/meinserver. Con getcap -r / Compruebo qué archivos contienen las competencias. Esto reduce notablemente las vías de escalación.

Es importante que las capacidades de los archivos solo se apliquen a Archivos binarios ELF funcionan. Los scripts de intérprete (por ejemplo, Python, Bash) no los heredan de forma fiable. En esos casos, encapsulo la acción privilegiada en una pequeña utilidad sometida a comprobación estática o utilizo la activación por socket, para que mi servicio ni siquiera tenga que establecer la conexión por sí mismo. Además, presto atención a los permisos de los archivos: las capacidades otorgan derechos especiales frente al núcleo, pero sustituyen ninguno las ACL habituales o los permisos POSIX.

Al copiar o empaquetar, las habilidades se pierden rápidamente: cp sin compatibilidad con XATTR, configurado incorrectamente umask o eliminar un artefacto de compilación de un sistema de archivos sin atributos extendidos capacidad de seguridad De forma implícita. Por eso trabajo de manera reproducible y utilizo: cp --preserve=xattr ..., tar --xattrs, rsync -X. En las compilaciones de paquetes, configuro explícitamente las capacidades de los archivos en el script de instalación, pruebo la instalación en una máquina virtual limpia y compruebo getcap en el CI.

Separación de privilegios con escenarios realistas

Un servidor web necesita acceso a los puertos 80 y 443, pero no a los módulos del núcleo ni a los reinicios del sistema, por lo que configuro CAP_NET_BIND_SERVICE y nada más. Un agente de copia de seguridad puede leer y escribir archivos, pero no modificar la configuración de red. Una herramienta de supervisión tiene acceso de lectura a los indicadores clave, pero carece de derechos de modificación. Estas restricciones limitan los ataques al ámbito local, en lugar de permitir que afecten a todo el sistema. Es precisamente esta separación la que permite que los servicios sean manejables y mantiene a raya las configuraciones erróneas.

Combinar con «sudo» y los roles

Las capacidades no sustituyen a una Estructura de funciones, las complementan. Concedo los permisos de sudo con mucha cautela, utilizo rutas completas de comandos y evito reglas generales como „ALL=(ALL) ALL“. Registro cada concesión de permisos. Los grupos agrupan responsabilidades, mientras que las capacidades establecen límites técnicos en los procesos. De este modo se crean competencias claras sin privilegios excesivos.

Errores habituales y buenas prácticas

  • No se utiliza CAP_SYS_ADMIN como abreviatura: Este derecho es un cajón de sastre. Lo sustituyo por alternativas más específicas (p. ej.,. CAP_SYS_CHROOT, CAP_SYS_TIME, CAP_SYS_NICE) o prescinde de ello por completo.
  • Los permisos de los archivos se mantienen estrictos: Las capacidades no anulan el DAC de forma general. Sin CAP_DAC_OVERRIDE El núcleo sigue respetando los bits de propietario y de modo. Por lo tanto, sigo concediendo los derechos de lectura de forma mínima.
  • Endurecimiento por vía: Si asigno capacidades de archivo a un binario, evito la suplantación de PATH (rutas absolutas en sudoers, derechos de escritura restringidos en los directorios de la ruta de búsqueda).
  • Publica pronto y con frecuencia: Es posible que los procesos se inicien con más permisos de los necesarios. Retiro los permisos innecesarios inmediatamente después de realizar el paso delicado (prctl()/libcap) y establezco no_new_privs, siempre que sea posible.
  • Limitar la herencia: Mantengo reducidos los conjuntos «Inheritable» y «Ambient». Los procesos hijos no deben abrir nuevas puertas.
  • Comprobar el proceso de compilación y despliegue: Confirmo que capacidad de seguridad se conserve y que ningún paso de preparación (capas de contenedores, NFS, escáner de artefactos) elimine los XATTR.

Resumen de las capacidades y los riesgos más importantes

Antes de asignar privilegios, defino claramente los que son necesarios y evalúo su riesgo. La siguiente tabla muestra ejemplos típicos con sus efectos y su clasificación. Siempre tengo en cuenta alternativas para evitar conceder derechos excesivos. Precisamente CAP_SYS_ADMIN Los concedo con mucha moderación. Siempre que es posible, sustituyo los privilegios de amplio alcance por variantes específicas y más limitadas.

Capacidad Propósito Riesgo Ejemplo
CAP_NET_BIND_SERVICE Enlazar a puertos < 1024 Bajo a medio Servidor web en los puertos 80 y 443
CAP_SYS_BOOT Reiniciar el sistema Alta Reinicio programado
CAP_SYS_MODULE Cargar/eliminar módulos del núcleo Muy alta Gestión de controladores
CAP_SYS_ADMIN Operaciones administrativas versátiles Muy alta Diversas tareas de mantenimiento
CAP_SETUID / CAP_SETGID Cambiar el UID/GID Media a alta Cambio de turnos en el servicio

Más allá de la tabla, ahora mismo estoy evaluando CAP_SYS_PTRACE (Depuración de procesos), CAP_NET_ADMIN (parametrización de la red) y CAP_DAC_OVERRIDE (Eludir las restricciones de acceso a los archivos) es algo muy delicado. A menudo existen patrones que permiten evitar estos derechos: puntos finales de métricas específicos en lugar de «process snooping», activación de sockets o reenvíos de puertos en lugar de derechos «bind», y derechos de archivo bien definidos en lugar de una elusión generalizada del DAC.

Endurecimiento en contenedores y alojamiento web

En entornos multitenant, considero que las competencias son radicalmente pequeño y evito la herencia en los procesos hijos. Los contenedores se benefician notablemente en cuanto el conjunto delimitador (bounding set) queda bien ajustado. Combino esto con espacios aislados para el sistema de archivos y los procesos. Para tener una visión general de los enfoques de aislamiento, me resulta útil esta introducción a Aislamiento de procesos. De este modo, los servicios permanecen independientes, incluso si una aplicación falla.

En la práctica, configuro los contenedores de forma predeterminada en „eliminar todo, añadir de forma selectiva“: --cap-drop=ALL --cap-add=NET_BIND_SERVICE para servicios web, sin derechos de montaje, sin SYS_ADMIN. En entornos orquestados, mantengo el perfil de forma centralizada y lo compruebo en las políticas. Importante: no me baso en las capacidades de los archivos de la imagen, sino que asigno derechos en tiempo de ejecución en el orquestador, de forma reproducible y auditable.

Interacción con SELinux y AppArmor

Las capacidades controlan lo que un proceso puede hacer, mientras que los perfiles MAC determinan a qué tiene acceso, y ambos se complementan bien. Establezco las capacidades de forma restrictiva y dejo que SELinux o AppArmor limiten el acceso a los archivos y sockets. De este modo se crea una protección por capas que plantea varios obstáculos a los exploits. Aquí encuentro una comparación rápida: SELinux frente a AppArmor. De este modo, un servicio comprometido queda aislado y puede causar menos daños.

Práctica: proceder paso a paso

Voy a empezar por hacer un inventario de todos los servicios y sus Requisitos. A continuación, elimino los binarios Set-UID innecesarios o los sustituyo por capacidades de archivo específicas. Configuro «sudo» de forma restrictiva y documento cada entrada. Asigno tareas a roles y grupos, y mantengo los permisos al mínimo. A continuación, realizo pruebas bajo carga y compruebo las entradas de los registros en busca de rechazos inesperados.

Una breve lista de comprobación me ayuda con el cambio:

  • Establecer por escrito los requisitos de cada servicio (solo lo que sea realmente necesario).
  • Hacer un inventario de los derechos especiales existentes (find / -perm -4000, getcap -r /).
  • Sustitución selectiva: eliminar el Set-UID, establecer las capacidades de los archivos y retirar los permisos lo antes posible.
  • Cerrar herencias: optimizar el conjunto delimitador, minimizar «Inheritable» y «Ambient».
  • Proteger los perfiles de systemd y de contenedores (CapacidadBoundingSet=, NoNewPrivileges=yes).
  • Realizar pruebas bajo carga, revisar los registros y las entradas de auditoría, y documentar las excepciones.

Supervisión, espacios de nombres y auditorías continuas

Superviso los archivos de registro, las alertas y las llamadas al sistema para que cualquier acción no deseada se detecte de inmediato destacar. Valido periódicamente los cambios en las capacidades, las reglas de sudo y los roles. Cuando resulta conveniente, aíslo adicionalmente las cargas de trabajo mediante mecanismos de aislamiento del núcleo. Este resumen ofrece un buen punto de partida para Espacios de nombres y cgroups. Así detecto las anomalías a tiempo y mantengo limpio el entorno.

En mi día a día utilizo pruebas sencillas: capsh --print me muestra el conjunto actual de habilidades, getpcaps enumera los derechos procesales y en /proc//status leo CapEff, CapPrm, CapBnd. Con auditd Realizo un seguimiento de los cambios en el estado de la capacidad (por ejemplo, regla en capset), relaciono los eventos con las implementaciones y configuro alertas cuando aparecen de repente permisos de alto nivel. En los casos más complicados, me ayuda strace -e capget,capset, con el fin de poner de manifiesto las manipulaciones de los derechos.

Ejemplos prácticos de systemd y contenedores

Muchos servicios los ejecuto como unidades de systemd y allí configuro los permisos:

  • CapabilityBoundingSet=CAP_NET_BIND_SERVICE reduce la ventana de derechos a lo estrictamente necesario.
  • AmbientCapabilities=CAP_NET_BIND_SERVICE Otorga al servicio el derecho a conectarse a los puertos 80/443 sin «file-capabilities».
  • NoNewPrivileges=yes impide futuras ampliaciones de derechos.
  • Usuario=, Grupo=, ProtectSystem=estricto, PrivateTmp=yes completan el aislamiento.

En los contenedores, inicio los procesos de la forma más minimalista posible: docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE --read-only. Para tareas de corta duración, utilizo las capacidades de tiempo de ejecución en lugar de las capacidades de archivo en la imagen, para que las compilaciones sigan siendo reproducibles y los permisos estén vinculados al entorno.

Casos concretos de migración extraídos de la práctica

  • ping sin Set-UID: En lugar de setuid root pongo setcap 'cap_net_raw=+ep' /bin/ping. De este modo, cualquier usuario puede abrir sockets ICMP sin necesidad de tener todos los privilegios de root. Lo compruebo periódicamente con getcap /bin/ping, si se ha conservado el atributo.
  • Servicio web en los puertos 80/443: Ejecuto mi servicio como usuario sin privilegios y solo introduzco cap_net_bind_service. Si el servicio ya está conectado a un proxy inverso, también puedo, como alternativa, vincularlo allí a los puertos 80/443 y utilizar un puerto alto internamente, sin necesidad de conocimientos adicionales.
  • Cambio de partes en el proceso: Para las herramientas que necesitan derechos elevados durante un breve periodo de tiempo (por ejemplo, para establecer los niveles de prioridad), configuro cap_sys_nice, realiza la acción cuanto antes y, a continuación, deja de usar la habilidad. Evito aumentar los derechos de forma permanente.

Límites y alternativas

No todos los casos de uso requieren «capabilities». A menudo existen alternativas seguras que entrañan un menor riesgo:

  • Activación del socket: El servicio de inicio (por ejemplo, systemd) abre sockets con privilegios y se los pasa al proceso. De este modo, mi servicio no necesita derechos de Bind.
  • Reenvío de puertos: Mediante reglas de cortafuegos, redirijo los puertos 80 y 443 a un puerto alto. El servicio sigue sin tener privilegios y el comportamiento del sistema no cambia.
  • Puertos de bajo nivel sin privilegios: Cuando sea adecuado, puedo elevar el umbral para los puertos no privilegiados. Sin embargo, eso amplía el margen de maniobra para todos los procesos; por eso sopeso cuidadosamente el riesgo y la comodidad.
  • Pequeños ayudantes en lugar de todoterrenos: Prefiero un binario diminuto y auditado con una sola habilidad que un gran monolito con un amplio catálogo de derechos.

Brevemente resumido

Con Capacidades de Linux Divido los poderes de root en pequeños privilegios fáciles de controlar. Las capacidades de archivo sustituyen a los binarios Set-UID, que entrañan riesgos, y reducen las consecuencias de un ataque. En combinación con reglas estrictas de sudo, roles y perfiles MAC, se crea una protección por capas con límites claros. Los conjuntos «Bounding» e «Inheritable» limitan la herencia y mantienen los procesos bajo control. Quien proceda de esta manera reduce notablemente la superficie de ataque y mantiene la carga administrativa dentro de unos límites razonables.

Artículos de actualidad