Montar /var/run/docker.sock dentro del contenedor convierte a la aplicación en un cliente completo de la API de Docker en el host. En la práctica, esto implica la posibilidad de iniciar y detener contenedores, montar directorios del host y gestionar la configuración de red — es decir, obtener un acceso equivalente al administrativo según la propia Docker. Si ese contenedor se ve comprometido, la evasión al nivel del nodo es posible sin explotar vulnerabilidades del kernel.
¿Por qué las organizaciones siguen haciéndolo? La razón más común es la velocidad en las compilaciones en CI, la comodidad de las herramientas de gestión o la depuración “temporal”. Estos escenarios son comprensibles, pero el precio del compromiso es alto: el contenedor obtiene la capacidad de realizar acciones que normalmente están reservadas al nodo, y una API remota sin protección adecuada se convierte en una vía directa de entrada — debe protegerse con TLS y autenticación estricta.
En este artículo analizamos el mecanismo de riesgo al exponer el socket, las configuraciones habituales que lo introducen, los indicadores en Compose y Kubernetes, y formas prácticas de mitigar el problema: proxy sobre la API de Docker con permisos mínimos, modo rootless y espacios de nombres de usuario, políticas a nivel de plataforma y alternativas seguras en la cadena de compilación.
El objetivo es ofrecer pasos prácticos que se puedan aplicar sin reestructurar radicalmente los procesos: desde una verificación rápida de la infraestructura hasta políticas y monitorización sostenibles que ayuden a prevenir un incidente desde la fase de configuración.
Qué es el socket de Docker y por qué es crítico
El demonio de Docker acepta comandos a través del socket Unix local /var/run/docker.sock. Cualquier proceso con acceso a ese socket puede gestionar el ciclo de vida de los contenedores, las redes y los volúmenes, así como iniciar nuevos contenedores con parámetros arbitrarios. En esencia, pertenecer al grupo docker equivale a privilegios administrativos en el nodo — así lo indica la documentación.
Cabe destacar el riesgo de exponer la API remota de Docker por TCP: solo debe activarse con cifrado y autenticación de clientes, de lo contrario equivale a exponer un puerto “administrativo” al exterior ver recomendaciones para proteger el acceso.
Por qué exponer docker.sock es peligroso
Al montar el socket del host dentro del contenedor, se concede a la aplicación la capacidad de controlar el demonio de Docker. Si un atacante obtiene acceso al contenedor (RCE, token comprometido, biblioteca vulnerable), el siguiente paso es trivial: iniciar un nuevo contenedor con los privilegios y montajes necesarios, montar directorios del host o modificar la red. No hacen falta exploits especiales — basta la funcionalidad estándar de la API.
- Control de los contenedores en el nodo. Crear, detener, recrear — como lo haría un operador legítimo.
- Acceso al sistema de archivos. Iniciar un contenedor montando
/o los directorios necesarios del host. - Escalada de privilegios. Lanzar contenedores privilegiados, manipular capabilities, cambios de red.
- Ocultación de rastros. Muchas acciones parecen operaciones legítimas de la API de Docker y no siempre se detectan de inmediato en los registros.
Fuentes típicas de riesgo
El montaje del socket rara vez aparece “por arte de magia”. Lo habitual es que sea un efecto secundario de la búsqueda de conveniencia y rapidez.
- CI/CD con “Docker dentro de Docker”. Se monta el socket al runner para construir imágenes, y esa configuración suele permanecer demasiado tiempo.
- Herramientas de gestión y autoactualización. Portainer, Watchtower y similares requieren acceso al demonio y a menudo obtienen más privilegios de los necesarios.
- Diagnóstico y soluciones temporales. Un acceso temporal para depuración se convierte con el tiempo en una configuración permanente.
- Kubernetes con
hostPath. Manifiestos que inyectan el socket de Docker/Containerd (/var/run/docker.sock,/run/containerd/containerd.sock) en pods, lo que rompe el aislamiento y contradice los Pod Security Standards.
Secuencia de ataque cuando se tiene acceso a la API de Docker
La secuencia es minimalista: compromiso del contenedor → detección del socket montado → llamadas a la API de Docker → lanzamiento de nuevos contenedores con montajes/privilegios necesarios → acceso al nodo. Técnicamente son llamadas estándar a la API. Por eso es crucial evitar la posibilidad de acceso en primer lugar, en lugar de confiar en que las operaciones pasarán desapercibidas.
Cómo detectar el problema: plan de comprobación
Empieza por inventariar y analizar estáticamente las configuraciones. El objetivo es localizar con rapidez dónde y por qué se introdujo el montaje.
Docker Compose y hosts individuales
- Revisa los archivos de Compose en busca de
volumesque apunten a/var/run/docker.sock. - Verifica contenedores auxiliares (Portainer, Watchtower, runners): ¿realmente necesitan el socket directo, en qué ámbito y bajo qué usuario se ejecutan?
Kubernetes
- Busca
hostPathque apunten a los sockets del runtime: Docker/Containerd/CRI-O. - Comprueba si se aplican las políticas Pod Security a nivel baseline/restricted y si existe una regla que prohiba esos montajes.
Análisis estático de IaC
- Utiliza escáneres de configuración: Trivy Config, Checkov, KICS. Sus reglas incluyen firmas para
hostPathpeligrosos y accesos a sockets.
Registros y telemetría
- Activa auditoría en Docker/Kubernetes: registra la creación de contenedores, añadidos de montajes y cambios de red. Esto permite detectar abusos.
- Monitorea accesos a los puertos remotos 2375/2376 y a los sockets Unix internos mediante las herramientas de observabilidad.
Medidas de prevención: cómo reducir el riesgo sin una reestructuración radical de procesos
Abandonar completamente el montaje es la meta ideal. Pero en infraestructuras reales suele haber compromisos. A continuación se presentan prácticas que reducen el riesgo a niveles aceptables.
Evite el acceso directo al demonio
Para las compilaciones, use herramientas que no requieran docker.sock:
- Kaniko — construcción de imágenes sin acceso al demonio, publicación directa en el registro.
- Docker BuildKit en modo aislado o rootless: caché, paralelismo y sin acceso directo al host.
- Podman y Buildah — alternativas para varios escenarios de construcción y gestión de contenedores.
Si el acceso es necesario, limítelo mediante un proxy y RBAC
No expongas el socket “a pelo” dentro del contenedor. Pon un proxy sobre la API de Docker y habilita solo los endpoints necesarios. Una opción popular es docker-socket-proxy, donde los permisos se activan por variables de entorno (enfoque de lista blanca).
Rootless Docker y espacios de nombres de usuario
Ejecutar el demonio sin privilegios de superusuario reduce las consecuencias de un compromiso. Combínalo con espacios de nombres de usuario, de modo que el UID dentro del contenedor se mapee a un UID no privilegiado en el host Rootless Docker, userns-remap.
Políticas a nivel de plataforma
Prohíbe montajes peligrosos de forma centralizada: así, aunque alguien lo intente, la plataforma rechazará la solicitud.
Kyverno (ejemplo de política)
{ "apiVersion": "kyverno.io/v1", "kind": "ClusterPolicy", "metadata": { "name": "deny-runtime-sockets" }, "spec": { "validationFailureAction": "enforce", "rules": [{ "name": "block-runtime-sockets", "match": { "resources": { "kinds": ["Pod"] } }, "validate": { "message": "El montaje de sockets de runtime está prohibido", "deny": { "conditions": { "any": [{ "key": "{{ request.object.spec.volumes[].hostPath.path || '' }}", "operator": "AnyIn", "value": ["/var/run/docker.sock","/run/containerd/containerd.sock","/var/run/crio/crio.sock"] }] } } } }] } }
OPA Gatekeeper (ejemplo de constraint)
apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sDenyHostPath metadata: name: deny-runtime-sockets spec: match: kinds: - apiGroups: [""] kinds: ["Pod"] parameters: blockedPaths: - "/var/run/docker.sock" - "/run/containerd/containerd.sock" - "/var/run/crio/crio.sock"
Refuerzo del entorno aislado
- Activa perfiles seccomp, AppArmor/SELinux y la opción
no-new-privilegespor defecto ver recomendaciones de Docker. - Minimiza las capabilities de Linux: deja solo las necesarias para la aplicación.
- En Kubernetes, utiliza Pod Security en el nivel restricted y SecurityContext que prohíban contenedores privilegiados.
API remota de Docker — solo con TLS y mTLS
Si la arquitectura requiere acceso remoto al demonio, aplica TLS, verificación de certificados cliente y aislamiento de red (ACL, VPN, segmentos privados) guía oficial.
Herramientas específicas (Portainer, Watchtower)
Para estos servicios, asigna un nodo/namespace separado, habilita TLS, mantén auditoría detallada de acciones y limita los endpoints de la API mediante un proxy. No son aplicaciones corrientes y requieren control específico.
CI/CD sin exponer el socket
La construcción de imágenes es la principal tentación para montar el socket. Hoy existen alternativas maduras.
- Kaniko — construcción dentro de un contenedor; el artefacto se envía directamente al registro; soporta caché de capas.
- BuildKit — ofrece rendimiento y caché sin necesidad de gestionar el demonio en el host; soporta modo rootless.
- Runners efímeros — si se necesita Docker completo, realiza la compilación en una VM separada y destrúyela al finalizar.
- Integridad de la cadena de suministro — firma de imágenes (Cosign/Sigstore), atestaciones (SLSA) y políticas que acepten solo artefactos firmados.
Monitorización y alertas
Incluso con políticas estrictas conviene vigilar eventos ligados a la gestión de contenedores.
- Anomalías en Docker/K8s: creación de contenedores fuera de los procedimientos de lanzamiento, ejecución con
--privileged, aparición dehostPathapuntando a sockets. - Indicadores de red: accesos a 2375/2376, tráfico inesperado hacia el demonio desde hosts no habituales.
- Auditoría de Kubernetes: filtra por verbs create/patch en Pod/DaemonSet/Deployment y verifica volumes/hostPath.
Qué hacer si el «socket ya está dentro»
Un contenedor con acceso a la API de Docker debe considerarse un posible puente al nodo. Plan de respuesta:
- Aislamiento. Restringe la red del Pod/contenedor y preserva el estado (snapshots, registros).
- Auditoría de las llamadas a la API. Revisa el historial de creación de contenedores, montajes, cambios de red e imágenes utilizadas.
- Inspección del nodo. Busca procesos/servicios desconocidos, usuarios añadidos, configuraciones modificadas y timers nuevos.
- Rotación de secretos. Cambia claves, tokens y contraseñas a los que se pudo tener acceso con prioridad.
- Restauración desde un estado limpio. Reconstrucción de imágenes y redeploy; la reparación in situ es posible pero arriesgada.
- Informe postmortem. Por qué apareció el montaje, por qué las comprobaciones no lo detectaron y cómo evitar que se repita.
Lista de verificación breve para producción
- No montes
docker.sockni sockets del runtime en aplicaciones que no lo requieran. - Si se necesita acceso, que sea solo a través de un proxy con lista blanca de métodos y una cuenta con permisos mínimos.
- Usa Rootless Docker y/o userns-remap cuando sea posible.
- En Kubernetes, aplica Pod Security (restricted), Kyverno/Gatekeeper y NetworkPolicy.
- Construye imágenes con Kaniko/BuildKit; para excepciones, usa runners efímeros.
- Activa auditoría en Docker/K8s y alertas para patrones peligrosos.
- Escanea IaC regularmente (Trivy/Checkov/KICS) y bloquea PR que introduzcan montajes de sockets.
Preguntas frecuentes
«Tenemos un entorno cerrado. ¿Realmente es un problema?»
Sí. Un perímetro interno reduce la probabilidad de un ataque externo, pero no evita el compromiso de credenciales ni vulnerabilidades en aplicaciones. El acceso a la API de Docker concede demasiados privilegios como para confiar en una red “cerrada” como barrera principal.
«Portainer/Watchtower no funcionan sin el socket. ¿Qué hacer?»
Asigna un nodo/namespace dedicado, limita los endpoints de la API mediante un proxy, habilita TLS y activa auditoría detallada. Es una configuración aceptable si se minimizan los permisos y se mantiene un control continuo.
«¿SELinux/AppArmor resuelven el problema?»
Estos mecanismos son útiles y necesarios como parte de una defensa en profundidad. Sin embargo, con acceso a la API de Docker, un atacante opera dentro de las interfaces permitidas por el demonio. Por tanto, siguen siendo necesarias políticas a nivel de plataforma y la restricción de la API.
«Necesito una depuración puntual. ¿Se puede temporalmente?»
Solo en un entorno aislado y con registro, con permisos temporales y eliminación posterior del recurso. Preferible utilizar un proxy que permita únicamente los métodos necesarios y ejecutar la depuración en un host separado.
Conclusiones
Exponer docker.sock no es un “compromiso cómodo”, sino un canal de control directo del nodo. La buena noticia es que existen alternativas maduras: herramientas de compilación sin socket, proxy sobre la API con permisos mínimos, modo rootless, espacios de nombres de usuario y políticas a nivel de plataforma. La combinación de estas medidas permite eliminar la configuración peligrosa o mantenerla estrictamente controlada en casos excepcionales. Así se reduce la probabilidad de evasión desde un contenedor y se facilita la investigación si algo sale mal.