Qué son las Linux capabilities y cómo mejoran la seguridad

linux-capabilities
linux-capabilities

En Linux, el usuario root tiene permiso para realizar prácticamente cualquier operación dentro del sistema. Puede modificar archivos protegidos, cambiar configuraciones de red, gestionar procesos, montar sistemas de archivos o cargar módulos en el kernel.

Sin embargo, muchas aplicaciones solamente necesitan realizar una de estas operaciones. Concederles todos los permisos de root sería innecesario y aumentaría considerablemente el impacto de una posible vulnerabilidad.

Las Linux capabilities solucionan este problema dividiendo los privilegios tradicionales de root en permisos independientes. De esta forma, un proceso puede recibir únicamente la capacidad concreta que necesita para funcionar.

👉 Y recuerda, si quieres aprender más de Linux, pincha en este curso de Linux gratis

🐳 Si quieres aprender más de Docker, pincha en este curso de Docker gratis

Qué son las Linux capabilities

Tradicionalmente, los sistemas Unix diferenciaban entre dos tipos de procesos:

  • Procesos privilegiados ejecutados por root.
  • Procesos sin privilegios ejecutados por el resto de los usuarios.

El usuario root podía superar la mayoría de las comprobaciones de permisos realizadas por el kernel. Los demás usuarios quedaban limitados por su UID, sus grupos y los permisos configurados sobre archivos y recursos.

Desde Linux 2.2, estos privilegios se dividen en unidades independientes llamadas capabilities. Técnicamente, las capabilities son atributos asociados a los hilos de ejecución, aunque normalmente se habla de las capacidades de un proceso.

Por ejemplo, una aplicación puede recibir permiso para:

  • Escuchar en un puerto privilegiado.
  • Cambiar el propietario de un archivo.
  • Configurar una interfaz de red.
  • Ajustar la hora del sistema.
  • Crear determinados tipos de sockets.
  • Enviar señales a otros procesos.

La aplicación obtiene únicamente el permiso necesario, sin recibir acceso completo como root.

Qué problema resuelven las Linux capabilities

Imagina un servidor web que necesita escuchar en el puerto 80.

Tradicionalmente, los puertos privilegiados requerían permisos de root. Una solución sencilla consistía en ejecutar todo el servidor web como administrador, aunque la única operación privilegiada que necesitaba era abrir ese puerto.

Con las Linux capabilities es posible concederle únicamente CAP_NET_BIND_SERVICE, que permite enlazar el proceso a puertos privilegiados.

El servidor puede continuar ejecutándose con un usuario normal y no obtiene permisos para modificar discos, administrar interfaces de red o cambiar la configuración del kernel.

Este mecanismo aplica el principio de mínimo privilegio: cada proceso debe disponer exclusivamente de los permisos imprescindibles para realizar su función.

Capabilities más utilizadas en Linux

Linux dispone de diferentes capabilities para separar las operaciones administrativas. Estas son algunas de las más habituales:

CapabilityFunción
CAP_CHOWNPermite cambiar el propietario y el grupo de archivos
CAP_DAC_OVERRIDEPermite ignorar determinadas comprobaciones de permisos sobre archivos
CAP_KILLPermite enviar señales a procesos que pertenecen a otros usuarios
CAP_NET_BIND_SERVICEPermite escuchar en puertos privilegiados
CAP_NET_RAWPermite utilizar sockets RAW y PACKET
CAP_NET_ADMINPermite realizar operaciones avanzadas de administración de red
CAP_SYS_TIMEPermite modificar el reloj del sistema
CAP_SYS_BOOTPermite reiniciar el sistema
CAP_SYS_MODULEPermite cargar o eliminar módulos del kernel
CAP_SYS_ADMINPermite realizar una gran cantidad de operaciones administrativas

La capability CAP_SYS_ADMIN merece especial atención. Agrupa muchas operaciones diferentes y, en algunos escenarios, puede proporcionar un nivel de acceso muy elevado. Por este motivo, debe evitarse siempre que exista una capability más específica para la operación requerida.

Cómo funcionan las Linux capabilities

Las capabilities no se almacenan en una única lista. Linux utiliza diferentes conjuntos para determinar qué privilegios puede emplear, conservar o heredar un proceso.

Permitted

El conjunto Permitted contiene las capabilities que un proceso tiene permitido utilizar.

Funciona como un límite para el conjunto Effective. Una capability que no se encuentre en Permitted normalmente no puede activarse como efectiva.

Effective

El conjunto Effective contiene las capabilities que el kernel utiliza en ese momento para comprobar si una operación está permitida.

Que una capability esté en Permitted no significa necesariamente que se esté utilizando. Para que el proceso pueda ejercerla debe encontrarse también en el conjunto Effective.

Inheritable

El conjunto Inheritable determina qué capabilities podrían conservarse cuando el proceso ejecuta otro programa mediante execve().

Su funcionamiento depende también de las capabilities configuradas en el archivo ejecutable.

Bounding

El conjunto Bounding establece el límite máximo de capabilities que un proceso puede obtener durante la ejecución de nuevos programas.

Eliminar una capability de este conjunto evita que pueda recuperarse posteriormente mediante la ejecución de un archivo con capabilities.

Ambient

El conjunto Ambient permite conservar determinadas capabilities al ejecutar programas que no tienen privilegios especiales configurados.

Las ambient capabilities aparecieron en Linux 4.3 y resultan especialmente útiles cuando una aplicación ejecuta otros binarios y necesita mantener ciertos permisos durante la cadena de ejecución.

Cómo consultar las capabilities de un archivo

Las herramientas principales para trabajar con capabilities forman parte del proyecto libcap.

En Debian y Ubuntu pueden instalarse habitualmente con:

sudo apt update
sudo apt install libcap2-bin

En Fedora, Rocky Linux, AlmaLinux y Red Hat Enterprise Linux:

sudo dnf install libcap

El comando getcap muestra las capabilities asignadas a un archivo:

getcap /ruta/al/ejecutableun 

Por ejemplo:

getcap /usr/bin/ping

Dependiendo de la distribución y de su configuración, el resultado podría ser similar a este:

/usr/bin/ping cap_net_raw=ep

También puedes buscar archivos con capabilities dentro de varios directorios:

sudo getcap -r /usr/bin /usr/sbin 2>/dev/null

La opción -r realiza una búsqueda recursiva y muestra los archivos que tienen capabilities configuradas.

Cómo consultar las capabilities de un proceso

Para revisar las capabilities del proceso actual puede utilizarse:

capsh --print

capsh muestra información sobre los conjuntos Effective, Permitted, Bounding y Ambient, entre otros datos relacionados con el contexto de seguridad.

También puedes consultar un proceso concreto mediante su PID:

getpcaps PID

Por ejemplo, para consultar las capabilities de la shell actual:

getpcaps $$

El comando getpcaps recibe uno o varios identificadores de proceso y muestra sus capabilities en formato legible.

El kernel también expone esta información en /proc:

grep '^Cap' /proc/$$/status

El resultado tendrá un formato parecido al siguiente:

CapInh:  0000000000000000
CapPrm:  0000000000000000
CapEff:  0000000000000000
CapBnd:  000001ffffffffff
CapAmb:  0000000000000000

Los valores se muestran como máscaras hexadecimales, por lo que herramientas como capsh suelen resultar más cómodas para interpretarlos.

Cómo asignar una capability a un archivo

El comando setcap permite asociar capabilities a un archivo ejecutable.

La sintaxis general es:

sudo setcap capability=conjuntos /ruta/al/ejecutable

Por ejemplo, para permitir que una aplicación escuche en puertos privilegiados:

sudo setcap cap_net_bind_service=+ep /usr/local/bin/mi-aplicacion

En esta expresión:

  • e añade la capability al conjunto Effective.
  • p la añade al conjunto Permitted.
  • + incorpora la capability a los conjuntos indicados.

Puedes comprobar la configuración con:

getcap /usr/local/bin/mi-aplicacion

El resultado será similar a:

/usr/local/bin/mi-aplicacion cap_net_bind_service=ep

Desde Linux 2.6.24, las capabilities pueden asociarse directamente a ejecutables. Esta configuración se almacena como un atributo extendido denominado security.capability.

Cómo eliminar las capabilities de un archivo

Para eliminar todas las capabilities asociadas a un ejecutable se utiliza la opción -r de setcap:

sudo setcap -r /usr/local/bin/mi-aplicacion

Después puedes verificar que se han eliminado:

getcap /usr/local/bin/mi-aplicacion

Si el comando no devuelve ningún resultado, el archivo ya no tiene capabilities asignadas.

Linux capabilities en Docker

Las capabilities son especialmente importantes en los contenedores.

Aunque un proceso se ejecute como root dentro de un contenedor Docker, normalmente no recibe todos los privilegios disponibles para el usuario root del sistema anfitrión. Docker utiliza un conjunto reducido de capabilities para limitar lo que pueden hacer los procesos del contenedor.

La opción –cap-add permite añadir una capability:

docker run --cap-add=NET_ADMIN imagen

La opción –cap-drop permite eliminarla:

docker run --cap-drop=NET_RAW imagen

Una práctica más restrictiva consiste en eliminar todas las capabilities y añadir únicamente las necesarias:

docker run \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  imagen

En Docker Compose puede configurarse de esta forma:

services:
  aplicacion:
    image: mi-aplicacion:latest
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

Siempre que sea posible, este enfoque es preferible a ejecutar el contenedor con:

docker run --privileged imagen

El modo privilegiado elimina gran parte del aislamiento de seguridad y concede al contenedor un nivel de acceso mucho mayor sobre el sistema anfitrión.

Linux capabilities en Kubernetes y OpenShift

Kubernetes permite añadir o eliminar capabilities mediante el securityContext del contenedor.

Un ejemplo seguro sería:

apiVersion: v1
kind: Pod
metadata:
  name: aplicacion
spec:
  containers:
    - name: aplicacion
      image: mi-aplicacion:latest
      securityContext:
        runAsNonRoot: true
        allowPrivilegeEscalation: false
        capabilities:
          drop:
            - ALL
          add:
            - NET_BIND_SERVICE

En los manifiestos de Kubernetes se omite el prefijo CAP_. Por ejemplo, CAP_NET_BIND_SERVICE se escribe como NET_BIND_SERVICE.

La recomendación general consiste en:

  1. Eliminar todas las capabilities con drop: ALL.
  2. Añadir exclusivamente las que necesita la aplicación.
  3. Ejecutar el contenedor como usuario no root.
  4. Desactivar la escalada de privilegios.
  5. Utilizar un perfil seccomp apropiado.

El estándar de seguridad Restricted de Kubernetes exige eliminar todas las capabilities y solamente permite volver a añadir NET_BIND_SERVICE.

En OpenShift también intervienen las Security Context Constraints o SCC. Una aplicación no podrá solicitar una capability si la SCC aplicada a su cuenta de servicio no la permite. Las SCC controlan, entre otros elementos, los contenedores privilegiados, la escalada de privilegios y las capabilities que puede solicitar cada pod.

Riesgos de utilizar capabilities

Las Linux capabilities son más seguras que entregar acceso completo como root, pero no son inofensivas.

Una capability mal asignada puede permitir que un atacante amplíe el impacto de una vulnerabilidad. Algunas, como CAP_SYS_ADMIN, CAP_SYS_MODULE, CAP_DAC_OVERRIDE o CAP_NET_ADMIN, pueden proporcionar acceso a operaciones especialmente sensibles.

También debe evitarse asignar capabilities a intérpretes genéricos como Python, Bash, Perl o PHP. Si un intérprete tiene una capability, cualquier código ejecutado mediante ese intérprete podría aprovecharla.

Por ejemplo, no sería recomendable hacer esto en un sistema real:

sudo setcap cap_net_bind_service=+ep /usr/bin/python3

En su lugar, la capability debería asignarse a un binario específico, diseñado para realizar únicamente la operación necesaria.

Buenas prácticas con Linux capabilities

Antes de asignar una capability, comprueba qué operación necesita realmente la aplicación.

Evita conceder CAP_SYS_ADMIN como solución genérica. Si existe una capability más específica, utiliza siempre la opción más limitada.

En contenedores, elimina todas las capabilities y añade solo las imprescindibles:

capabilities:
  drop:
    - ALL

Revisa periódicamente los ejecutables con capabilities:

sudo getcap -r /usr/bin /usr/sbin /usr/local/bin 2>/dev/null

Combina las capabilities con otras medidas de seguridad como usuarios no root, permisos Unix, SELinux, AppArmor, seccomp, namespaces y sistemas de archivos de solo lectura.

Por último, documenta por qué se ha concedido cada capability. De esta forma será más sencillo revisarla o eliminarla cuando la aplicación deje de necesitarla.

Conclusión

Las Linux capabilities permiten dividir los privilegios tradicionales del usuario root en permisos mucho más específicos. Gracias a este mecanismo, una aplicación puede realizar una operación privilegiada sin obtener control completo sobre el sistema.

Comandos como getcap, setcap, getpcaps y capsh permiten consultar y administrar estos permisos directamente en Linux. Docker, Kubernetes y OpenShift también utilizan capabilities para reducir los privilegios disponibles dentro de los contenedores.

Aplicadas correctamente, las Linux capabilities ayudan a seguir el principio de mínimo privilegio y reducen considerablemente el impacto de una aplicación comprometida.

Comentarios

No hay comentarios aún. ¿Por qué no comienzas el debate?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *