Seguridad en Contenedores: Seccomp, AppArmor y Rootless Podman
La seguridad en entornos de contenedores ha dejado de ser un "nice-to-have" para convertirse en un pilar fundamental de cualquier infraestructura moderna. Con la adopción masiva de Kubernetes y Docker, los vectores de ataque se han multiplicado, haciendo que técnicas como Seccomp, AppArmor y el uso de Podman rootless sean esenciales para un Linux hardening efectivo. En este artículo, exploraremos a fondo estas tres herramientas, sus mecanismos internos y cómo implementarlas en un entorno de producción real.
Entendiendo la Amenaza: ¿Por qué no basta con aislar?
La mayoría de las soluciones de contenedores (Docker, containerd) utilizan namespaces y cgroups para aislar procesos. Sin embargo, el núcleo del sistema operativo (kernel) es compartido. Un fallo de seguridad en una syscall maliciosa o un exploit que escape del namespace puede comprometer todo el host. Aquí es donde entran en juego las capas de seguridad adicionales: perfiles de syscalls (Seccomp), políticas de control de acceso obligatorio (AppArmor) y la ejecución sin privilegios de root (Rootless).
1. Seccomp: El Filtro de Syscalls a Nivel de Kernel
Seccomp (Secure Computing Mode) es una funcionalidad del kernel de Linux que permite restringir las llamadas al sistema (syscalls) que un proceso puede realizar. Piensa en ello como un firewall para el kernel: solo se permiten las syscalls estrictamente necesarias para que el contenedor funcione.
¿Cómo funciona?
Seccomp opera mediante reglas que se aplican a un proceso hijo (el contenedor). Cuando el proceso intenta ejecutar una syscall, el kernel intercepta la petición y la compara con el perfil cargado. Si la syscall no está permitida, el proceso es terminado (o se le devuelve un error, según la política).
Perfiles por defecto y personalizados
- Default Docker/containerd: Docker incluye un perfil Seccomp por defecto que bloquea alrededor de 44 syscalls peligrosas (como
mount,reboot,kexec_load). Es un buen punto de partida. - Perfiles personalizados: Para aplicaciones que requieren syscalls específicas (por ejemplo,
ptracepara depuración), necesitas crear un perfil JSON. Aquí tienes un ejemplo mínimo:
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["accept", "bind", "connect", "read", "write", "open", "close", "mmap", "munmap"],
"action": "SCMP_ACT_ALLOW"
}
]
}
Implementación práctica en Podman
Para aplicar un perfil Seccomp personalizado en Podman:
podman run --security-opt seccomp=/ruta/a/miperfil.json nginx
[TIP] Puedes generar perfiles Seccomp dinámicamente con herramientas como inspeck-gadget o usando strace durante el desarrollo para identificar las syscalls que realmente necesita tu aplicación.
2. AppArmor: Control de Acceso Obligatorio (MAC) para Contenedores
Mientras Seccomp filtra syscalls, AppArmor (Application Armor) proporciona un control de acceso obligatorio (MAC) a nivel de archivos, redes y capacidades. AppArmor asocia un perfil de seguridad a un ejecutable o a un contenedor, definiendo qué recursos puede acceder y cómo.
Perfiles AppArmor: Sintaxis y ejemplos
Un perfil AppArmor se escribe en un archivo de texto y se compila con apparmor_parser. La sintaxis es declarativa y muy legible. Aquí tienes un perfil básico para un contenedor web que solo necesita acceso a /var/www/html y a la red:
#include <tunables/global>
profile contenedor-web flags=(attach_disconnected) {
#include <abstractions/base>
#include <abstractions/lxc/container-base>
# Acceso a archivos de la aplicación
/var/www/html/** r,
/var/www/html/index.html rw,
# Red: permitir conexiones TCP salientes
network inet tcp,
network inet6 tcp,
# Denegar todo lo demás
deny /etc/shadow r,
deny /proc/** rw,
}
Cargar y aplicar el perfil
- Guarda el perfil en
/etc/apparmor.d/contendor-web. - Cárgalo:
sudo apparmor_parser -r /etc/apparmor.d/contendor-web. - Ejecuta el contenedor con Podman:
podman run --security-opt apparmor=contendor-web nginx
AppArmor vs SELinux: ¿Cuál elegir?
| Característica | AppArmor | SELinux |
|---|---|---|
| Facilidad de uso | Alta (perfiles basados en rutas) | Media (etiquetas y políticas complejas) |
| Granularidad | Media | Alta (control a nivel de objeto) |
| Mantenimiento | Sencillo | Complejo |
| Popularidad en contenedores | Muy alta (Ubuntu, Debian) | Alta (Red Hat, Fedora) |
[INFO] Si usas distribuciones basadas en Red Hat (RHEL, Fedora, CentOS), SELinux es la opción nativa. En Ubuntu/Debian, AppArmor es el estándar. Ambos son igual de efectivos si se configuran correctamente.
3. Podman Rootless: El Fin del Demonio con Privilegios
Uno de los mayores riesgos de seguridad en Docker tradicional es que el demonio (dockerd) se ejecuta como root. Si un atacante logra comprometer el demonio, tiene acceso total al host. Podman rootless elimina este problema al ejecutar contenedores completamente sin privilegios de root.
¿Cómo funciona?
Podman utiliza user namespaces para mapear el usuario root dentro del contenedor a un usuario no privilegiado fuera del contenedor. Por ejemplo, si ejecutas podman run -u root, dentro del contenedor eres root, pero fuera del contenedor eres el usuario uid=1000. Esto significa que incluso si el proceso escapa del namespace, solo tiene los permisos de un usuario normal.
Ventajas clave de Rootless Podman
- Sin demonio: No hay un proceso con privilegios elevados escuchando en un socket.
- Aislamiento real: El kernel trata al contenedor como un proceso de usuario normal.
- Mejor hardening: No necesitas
sudopara ejecutar contenedores. - Compatibilidad: Soporta volúmenes, redes (slirp4netns) y systemd.
Configuración paso a paso
-
Instalar Podman (en Ubuntu/Debian):
sudo apt update && sudo apt install podman slirp4netns fuse-overlayfs -
Configurar el usuario:
echo "usuario:1000:65536" | sudo tee -a /etc/subuid echo "usuario:1000:65536" | sudo tee -a /etc/subgid -
Ejecutar un contenedor rootless:
podman run --rm -it alpine sh
[WARNING] Rootless Podman tiene limitaciones: no puedes montar dispositivos de bloque, no puedes usar puertos privilegiados (<1024) sin redirección, y el rendimiento de red puede ser ligeramente inferior debido a slirp4netns. Sin embargo, para el 99% de los casos de uso, es la opción más segura.
Comparativa: Docker vs Podman (Rootless)
| Aspecto | Docker (rootful) | Podman (rootless) |
|---|---|---|
| Demonio | Sí (root) | No |
| User namespace | No por defecto | Sí, siempre |
| Puertos <1024 | Sí | No (necesita redirección) |
| Rendimiento de red | Nativo | Slirp4netns (ligera pérdida) |
| Seguridad | Media | Alta |
4. Integración de las Tres Capas: Una Estrategia de Defensa en Profundidad
La seguridad real no depende de una sola herramienta, sino de la combinación de varias. Aquí te muestro cómo integrar Seccomp, AppArmor y Rootless Podman en un solo comando:
podman run \
--security-opt seccomp=/ruta/a/perfil-seccomp.json \
--security-opt apparmor=mi-perfil-apparmor \
--user 1000:1000 \
nginx
Flujo de trabajo recomendado
- Desarrollo: Ejecuta el contenedor sin restricciones y monitoriza las syscalls y accesos a archivos.
- Generación de perfiles: Usa
straceyaudit2allow(para AppArmor) para crear perfiles mínimos. - Pruebas: Aplica los perfiles en un entorno de staging y verifica que la aplicación funciona correctamente.
- Producción: Despliega con Podman rootless y perfiles estrictos.
Ejemplo de automatización con systemd
Puedes crear un servicio systemd para que el contenedor rootless arranque automáticamente:
[Unit]
Description=Contenedor Nginx Rootless
After=network.target
[Service]
Type=forking
User=usuario
ExecStart=/usr/bin/podman run --name nginx-rootless --security-opt seccomp=... --security-opt apparmor=... -p 8080:80 nginx
ExecStop=/usr/bin/podman stop nginx-rootless
Restart=always
[Install]
WantedBy=default.target
5. Buenas Prácticas y Checklist de Linux Hardening
Para cerrar, aquí tienes una lista de verificación para endurecer tu entorno de contenedores:
- Usa Podman rootless siempre que sea posible.
- Aplica perfiles Seccomp restrictivos (empieza con el perfil por defecto y personaliza solo lo necesario).
- Carga perfiles AppArmor para cada tipo de contenedor (web, base de datos, worker).
- Desactiva capacidades innecesarias con
--cap-drop=ALL --cap-add=NET_BIND_SERVICE. - Monta sistemas de archivos de solo lectura (
--read-only). - No ejecutes como root dentro del contenedor (usa
--user). - Actualiza el kernel regularmente (las vulnerabilidades de contenedores suelen ser parches de kernel).
- Monitoriza con Falco o Tracee para detectar comportamientos anómalos.
Conclusión
La seguridad en contenedores no es un producto que se instala, sino una práctica que se integra en cada capa del stack. Seccomp filtra syscalls, AppArmor controla el acceso a recursos, y Podman rootless elimina el riesgo de un demonio privilegiado. Juntos, forman una defensa sólida contra escapes de contenedores y ataques al kernel.
Implementar estas técnicas no solo protege tu infraestructura, sino que también te prepara para entornos de producción más exigentes, donde el cumplimiento normativo (PCI DSS, SOC 2) exige medidas de Linux hardening avanzadas. Empieza hoy: migra tus cargas de trabajo a Podman rootless, genera perfiles Seccomp mínimos y escribe políticas AppArmor para cada aplicación. Tu futuro yo (y tu equipo de seguridad) te lo agradecerán.
