Blog
Defensa contra escapes de contenedores: Una guía práctica de aislamiento de Docker para alojamiento multi-inquilino
Aprenda a proteger los contenedores de Docker contra vulnerabilidades de escape y fallos de aislamiento en entornos multi-inquilino con pasos concretos y ejemplos.

Resumen
Los contenedores Docker comparten el kernel del host, lo que hace que el aislamiento sea crítico, especialmente en el alojamiento multi-inquilino, donde un solo escape de contenedor puede comprometer a todos los inquilinos. Muchos desarrolladores asumen que los contenedores son máquinas virtuales perfectamente aisladas, pero la realidad es diferente. Este artículo explica las características del kernel de Linux detrás del aislamiento de Docker (namespaces, cgroups) y los vectores de ataque que los amenazan. Aprenderá pasos prácticos para endurecer su configuración de Docker: limitar privilegios, usar un tiempo de ejecución seguro, escanear imágenes e implementar segmentación de red. Siguiendo un ejemplo del mundo real de un proveedor de alojamiento multi-inquilino de WordPress, verá cómo aplicar estas defensas. También cubrimos advertencias como las compensaciones de rendimiento y el uso de seccomp/AppArmor. El objetivo es brindarle una estrategia de aislamiento robusta que evite los escapes de contenedores y mantenga a sus inquilinos seguros.
Introducción
Si administra una plataforma de alojamiento multi-inquilino, ya sea alojamiento compartido de WordPress, una aplicación SaaS o un servicio de entorno de desarrollo, el escape de contenedores es el escenario de pesadilla. Una vulnerabilidad en el kernel o una configuración errónea puede permitir que un inquilino se escape de su contenedor y acceda a los datos de otros inquilinos o al propio host. El aislamiento de Docker se basa en características del kernel de Linux como namespaces y cgroups, pero las configuraciones predeterminadas a menudo son insuficientes para una seguridad robusta. Este artículo lo guiará a través de los vectores de ataque y proporcionará pasos accionables para bloquear sus contenedores Docker, ilustrado con un ejemplo real de WordPress multi-inquilino. Para una visión más amplia de la orquestación de producción, consulte nuestra guía sobre Orquestación de aplicaciones contenerizadas listas para producción.
Comprensión del aislamiento de Docker
Los contenedores Docker utilizan namespaces de Linux para proporcionar aislamiento a nivel de proceso: los namespaces PID aíslan los árboles de procesos, los namespaces de red separan las interfaces de red, los namespaces de montaje aíslan los montajes del sistema de archivos y los namespaces de usuario permiten mapear la raíz del contenedor a un usuario no privilegiado del host. Los grupos de control (cgroups) limitan el uso de recursos como CPU, memoria y E/S de disco. Estas características juntas crean un "sandbox" alrededor de cada contenedor. Sin embargo, a diferencia de una máquina virtual que ejecuta un kernel separado, los contenedores comparten el kernel del host. Esto significa que una vulnerabilidad en el kernel (por ejemplo, CVE-2022-0492) puede ser explotada para escapar del aislamiento del namespace del contenedor. Además, las configuraciones erróneas como ejecutar contenedores como root dentro del contenedor, otorgar al contenedor todas las capacidades o no eliminar las capacidades de Linux innecesarias pueden ampliar la superficie de ataque.
Vectores de ataque
Los vectores de ataque comunes incluyen:
- Exploits del kernel: Explotar un error en el kernel del host para obtener acceso al host.
- Contenedores privilegiados: Ejecutar con
--privilegedotorga todas las capacidades y omite la mayoría del aislamiento. - Abuso de capacidades: Incluso sin modo privilegiado completo, un contenedor con capacidades peligrosas como
CAP_SYS_ADMINoCAP_NET_ADMINpuede montar sistemas de archivos o manipular configuraciones de red. - Prácticas de imágenes inseguras: Usar imágenes base con vulnerabilidades conocidas o incluir herramientas innecesarias como compiladores o intérpretes de shell.
- Namespaces de montaje compartidos: Montar directorios del host en contenedores puede permitir el escape si no son de solo lectura.
Pasos prácticos de seguridad
1. Ejecutar contenedores como usuario no root
Por defecto, Docker ejecuta contenedores como root dentro del contenedor. Si un atacante obtiene acceso root dentro del contenedor, tiene más influencia. Cree un usuario en su Dockerfile y use la directiva USER. Además, evite usar la bandera --user en Docker Compose para mapear a un usuario de host arbitrario si es posible.
2. Eliminar todas las capacidades y agregar solo las necesarias
Las capacidades de Linux dividen los privilegios de superusuario en unidades más pequeñas. En Docker Compose, use cap_drop: ALL y luego cap_add solo las requeridas (por ejemplo, NET_BIND_SERVICE). Evite capacidades peligrosas como SYS_ADMIN, NET_ADMIN, SYS_PTRACE.
3. Usar sistema de archivos raíz de solo lectura
Establezca read_only: true en la definición de su contenedor. Esto evita que los atacantes escriban en el sistema de archivos del contenedor. Si su aplicación necesita escribir archivos temporales, monte un volumen tmpfs en esa ubicación.
4. Habilitar la reasignación de namespaces de usuario
La reasignación de namespaces de usuario mapea el usuario root del contenedor a un usuario no root del host. Esto agrega una capa de aislamiento, ya que incluso si un root de contenedor se escapa, tendrá los privilegios del usuario reasignado. Habilítelo en /etc/docker/daemon.json con "userns-remap": "default". Tenga en cuenta que esto puede complicar los permisos de volumen. Para más detalles, consulte Dominando el aislamiento de Docker para alojamiento web seguro y eficiente.
5. Aplicar perfiles Seccomp y AppArmor/AppArmor
Seccomp restringe las llamadas al sistema que un contenedor puede realizar. Docker proporciona un perfil seccomp predeterminado que bloquea llamadas al sistema peligrosas. También puede crear perfiles personalizados. De manera similar, AppArmor (o SELinux) proporciona control de acceso obligatorio. Use AppArmor para confinar su contenedor a un conjunto mínimo de operaciones permitidas. El perfil de seguridad se puede establecer a través de security_opt en Docker Compose.
6. Usar imágenes base mínimas y escanear en busca de vulnerabilidades
Elija imágenes pequeñas como Alpine o Distroless que tengan una superficie de ataque menor. Escanee regularmente las imágenes con herramientas como Docker Scout, Trivy o Clair. Integre el escaneo en su canalización de CI/CD para evitar que se implementen imágenes vulnerables.
7. Segmentación de red con redes bridge personalizadas
Cree redes bridge separadas para cada inquilino o nivel de aplicación. Esto limita el tráfico este-oeste. En Docker Compose, defina redes y aísle servicios. Use internal: true si un servicio no necesita acceso a Internet saliente. Las reglas de firewall en el host restringen aún más el tráfico entre contenedores.
8. Limitar recursos con Cgroups
Establezca límites de CPU y memoria en Docker Compose usando deploy.resources.limits. Esto evita que un contenedor comprometido lance un ataque de agotamiento de recursos. Además, establezca kernel_memory y memory_reservation para un control más fino.
Ejemplo del mundo real: Alojamiento multi-inquilino de WordPress con Docker Compose
Considere un escenario en el que aloja varios sitios de WordPress para diferentes clientes, cada uno en su propio contenedor Docker. Una configuración insegura podría verse así:
version: '3'
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- ./wp-content:/var/www/html/wp-content
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: somewordpress
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
Esta configuración es vulnerable: el contenedor de WordPress se ejecuta como root por dentro, tiene todas las capacidades (ya que no se ha eliminado ninguna), monta un directorio del host con acceso de escritura y tiene acceso de red sin restricciones.
Ahora vamos a endurecerlo:
version: '3'
services:
wordpress:
image: wordpress:latest
user: www-data
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /var/www/html/wp-content/plugins
security_opt:
- seccomp=seccomp-profile.json
- apparmor=wordpress-profile
networks:
- frontend
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wp-uploads:/var/www/html/wp-content/uploads
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
db:
image: mysql:5.7
user: mysql
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
networks:
- backend
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: somewordpress
volumes:
- db_data:/var/lib/mysql
deploy:
resources:
limits:
cpus: '0.25'
memory: 128M
networks:
frontend:
driver: bridge
internal: false
backend:
driver: bridge
internal: true
volumes:
wp-uploads:
db_data:
Mejoras clave:
- Ambos contenedores se ejecutan como usuarios no root (
www-dataymysql). - Todas las capacidades eliminadas, solo se agrega
NET_BIND_SERVICE. - El sistema de archivos de WordPress es de solo lectura, excepto por un montaje tmpfs y un volumen de subidas.
- Se aplican perfiles de Seccomp y AppArmor (necesitaría proporcionar perfiles personalizados).
- Redes separadas aíslan la web de la base de datos, con la red de la base de datos interna.
- Límites de recursos para evitar el agotamiento de recursos.
Para más información sobre el endurecimiento de Docker específico para WordPress, consulte Docker para WordPress: Por qué los contenedores aislados lo cambian todo.
Advertencias
- Reasignación de namespaces de usuario: Si bien es potente, interrumpe el montaje de volúmenes porque la UID de host reasignada no es la misma que la UID del contenedor. Es posible que deba precrear directorios con los permisos correctos o usar volúmenes de Docker con soporte de reasignación.
- Perfiles Seccomp/AppArmor: Los perfiles personalizados requieren comprender los patrones de llamadas al sistema y acceso a archivos de su aplicación. Los perfiles excesivamente restrictivos pueden romper la funcionalidad. Pruebe a fondo.
- Rendimiento: Las capas de seguridad adicionales como seccomp y AppArmor tienen una sobrecarga mínima, pero los límites de recursos y los sistemas de archivos de solo lectura pueden afectar a las aplicaciones con muchas escrituras.
- Complejidad de la orquestación: En un entorno multi-inquilino, la gestión de archivos Docker Compose por inquilino puede volverse engorrosa. Considere usar una herramienta de orquestación de nivel superior como Kubernetes, pero eso introduce sus propias consideraciones de seguridad.
Conclusión
El escape de contenedores es una amenaza real en el alojamiento Docker multi-inquilino, pero es prevenible. Al comprender los mecanismos de aislamiento y aplicar defensa en profundidad —eliminar capacidades, ejecutar como no root, habilitar namespaces de usuario, seccomp, AppArmor, segmentación de red y escaneo regular de imágenes— puede reducir drásticamente el riesgo. Recuerde que la configuración predeterminada de Docker no está lista para producción para cargas de trabajo multi-inquilino. Implemente estos pasos hoy para proteger a sus inquilinos y su infraestructura. Para una descripción general completa de las mejores prácticas de seguridad de Docker, consulte Protección de sus aplicaciones web con Docker: una guía práctica de aislamiento y mejores prácticas.
Sources (5)
- Docker and Container Isolation - Medium
- What is container isolation? Mechanisms, limitations, and secure runtimes | Blog - Northflank
- Container Isolation Explained for Kubernetes and Beyond - Edera
- Docker Security: 5 Risks and 12 Best Practices for Securing Your Containers - Tigera.io
- 9 Security Best Practices for Docker Containers - Kinsta®

