Puedes ejecutar Docker en producción durante meses sin que aparezca ningún problema. Los contenedores arrancan, las aplicaciones responden y nada falla. Luego, un puerto expuesto o un permiso mal configurado crea un punto de entrada que un atacante no tuvo que ganarse. La mayoría de los errores de seguridad en Docker no parecen errores hasta que algo sale mal.
Este artículo cubre las configuraciones concretas que ponen en riesgo los entornos de contenedores, qué posibilidades le dan a un atacante cada una de ellas, y cierra con una lista de verificación que puedes aplicar a tu propia configuración hoy mismo.
Por qué la seguridad en Docker es más difícil de lo que parece
Los contenedores dan sensación de aislamiento. Inicias uno, ejecuta su propio espacio de procesos y, desde dentro, el contenedor de al lado no existe. Hay aislamiento, pero es parcial. Los contenedores comparten el kernel del host, lo que significa que, en determinadas condiciones, un proceso dentro de un contenedor puede acceder por completo al sistema anfitrión.
Docker viene configurado para facilitar el trabajo del desarrollador, no para endurecer la seguridad en producción. Acceso root activado. Todos los puertos pueden enlazarse a cualquier interfaz. Sin monitorización en tiempo de ejecución. La mayoría de los desarrolladores aceptan esa configuración, despliegan el contenedor y siguen adelante. Es un enfoque razonable para empezar, pero no es una postura de seguridad definitiva.
Según Informe State of Kubernetes Security 2024 de Red Hat, el 67 % de las organizaciones retrasó o ralentizó el despliegue de aplicaciones por preocupaciones de seguridad en contenedores o Kubernetes. Esa fricción no suele venir de ataques. Viene de equipos que descubren que sus configuraciones de contenedores necesitaban un endurecimiento que nunca llegaron a implementar.
Con frecuencia vemos contenedores corriendo en producción con la misma configuración que tenían en la máquina local de un desarrollador. Ahí es donde los errores de seguridad en Docker tienden a acumularse en silencio, sin síntomas visibles hasta que algo se audita o falla.
Los errores que generan esas brechas son concretos, predecibles y, en su mayoría, evitables, empezando por el nivel de configuración.
Errores de configuración más comunes en Docker
La mayoría de las brechas en contenedores no empiezan con un exploit de día cero. Empiezan con una configuración establecida el primer día, sin pensar demasiado en la exposición de red o el alcance de los privilegios.
La configuración predeterminada de Docker está pensada para que las cosas funcionen. La distancia entre funcional y seguro es donde se acumulan los riesgos de seguridad en contenedores Docker, especialmente en despliegues auto-gestionados que nunca se vuelven a revisar.
Vemos este patrón con frecuencia: contenedores en servidores con IP pública con enlaces de puertos, configuraciones de usuario y configuraciones de red exactamente igual a como estaban en el despliegue inicial.
Ejecutar contenedores como root
Cuando inicias un contenedor Docker sin especificar un usuario, se ejecuta como root. Eso significa que cualquier proceso dentro del contenedor, incluida tu aplicación, tiene privilegios de root dentro del espacio de nombres del contenedor.

Ser root dentro de un contenedor no es lo mismo que ser root en el host, pero la separación no es absoluta. Los exploits de escalada de privilegios dirigidos al runtime, como el conocido runc CVE-2019-5736 y otros fallos similares, suelen necesitar un proceso de contenedor con root para ejecutarse con éxito.
Los contenedores sin root eliminan ese requisito del que dependen esos exploits, reduciendo significativamente la superficie de ataque para ese tipo de vulnerabilidades, aunque no eliminan por completo el riesgo de escape de contenedor.
Añadir una directiva USER a tu Dockerfile resuelve esto. Algunas imágenes oficiales incluyen un usuario sin privilegios que puedes activar con una directiva USER, pero muchas siguen usando root por defecto sin un usuario de aplicación predefinido. En esos casos, creas el usuario en el Dockerfile antes de cambiarte a él. Para la mayoría de los despliegues autogestionados, este único cambio elimina toda una categoría de riesgo de escalada.
Exponer demasiados puertos a internet
Cuando publicas un puerto con Docker, Docker escribe sus propias reglas de iptables directamente. Esas reglas se aplican antes que las reglas del firewall del host. Esto es un comportamiento conocido reportado por la comunidad y documentado en la guía de filtrado de paquetes de Docker, no una mala configuración, y significa que UFW y herramientas similares no bloquean lo que Docker ya ha abierto.

Docker escribe directamente en iptables, saltándose los valores predeterminados de UFW y firewalld en muchos hosts Linux. Eso significa que un puerto vinculado a 0.0.0.0 puede ser accesible públicamente aunque tu firewall parezca configurado correctamente. Los grupos de seguridad de cloud y las reglas de la cadena DOCKER-USER pueden seguir bloqueando ese tráfico, así que la exposición real depende de tu configuración de red concreta.
Vincula los servicios a 127.0.0.1 siempre que sea posible, enruta el tráfico público a través de un proxy inverso y publica solo lo que realmente necesite acceso externo. Un proxy inverso es la forma más fiable de controlar qué queda expuesto desde fuera del host.
Ignorar el aislamiento de red entre contenedores
Cualquier contenedor en esa red puede alcanzar a cualquier otro sin restricciones. El bridge por defecto no aplica ningún filtrado de tráfico entre los contenedores que lo comparten, y la mayoría de los despliegues nunca cambian esa configuración.

Si un contenedor se ve comprometido, esa comunicación abierta se convierte en una vía de movimiento lateral. Un contenedor frontend puede llegar a una base de datos, a un API interno o a cualquier otro servicio en el mismo bridge por defecto, incluso cuando ese acceso nunca fue intencional.
Las redes definidas por el usuario te dan control explícito sobre qué contenedores pueden comunicarse entre sí, pero una sola red personalizada compartida por todos tus servicios sigue permitiendo tráfico libre entre contenedores. El aislamiento real requiere colocar en redes separadas los servicios que no deben comunicarse. Desactivar el bridge por defecto es el punto de partida, no el destino.
Descuidar el socket de Docker
El socket de Docker en /var/run/docker.sock es la interfaz de control de todo el motor de Docker. Montarlo en un contenedor le otorga acceso API directo al daemon que se ejecuta en el host.

Con ese acceso, un contenedor puede iniciar nuevos contenedores, montar directorios del host, inspeccionar y modificar contenedores en ejecución, y controlar efectivamente la máquina host. La superficie de ataque equivale a tener root en el host, por lo que cualquier herramienta que requiera acceso al socket merece una evaluación cuidadosa.
Para la mayoría de los casos de uso, existen alternativas más seguras: APIs con alcance limitado o herramientas de gestión de Docker que no requieren acceso al socket. Docker-in-Docker tiene sus propios compromisos en seguridad y operaciones, y no es un sustituto directo.
Los errores de configuración crean la exposición inicial. Las decisiones sobre imágenes y dependencias determinan cómo esa exposición se agrava con el tiempo.
Errores en imágenes y secretos que sobreviven al contenedor
Cuando detienes un contenedor, los errores de configuración que contiene se detienen con él. Cuando reconstruyes a partir de una imagen que tiene una vulnerabilidad o una credencial codificada de forma fija, el problema reaparece al iniciar el contenedor. Los errores a nivel de imagen no se resetean entre despliegues.
Viajan con la imagen a cada entorno que la descarga, a cada registro que la almacena y a cada miembro del equipo que la ejecuta. Esa persistencia convierte la gestión de imágenes y secretos en una categoría de riesgo propia, que conviene auditar por separado de la configuración.
Este patrón es frecuente: una imagen elegida con cuidado al inicio del proyecto y que nunca se ha reconstruido desde entonces, alejándose poco a poco de la línea de seguridad que representaba en su momento.
Uso de imágenes no confiables u obsoletas
Los registros públicos están abiertos a cualquiera. Se han distribuido imágenes maliciosas a través de Docker Hub con mineros de criptomonedas y puertas traseras incrustadas en el historial de capas, que persisten entre reinicios del contenedor. Verificar antes de descargar es importante, especialmente con imágenes de editores no oficiales o desconocidos.

El problema aparte es la obsolescencia. Una imagen oficial que descargaste hace seis meses y nunca has reconstruido ha ido acumulando vulnerabilidades Docker sin parchear con cada CVE divulgado contra sus paquetes. La imagen no está rota. Simplemente ya no está actualizada.
Informe State of the Software Supply Chain 2024 de Sonatype encontró que en el 95% de los casos en que se consume un componente vulnerable, ya existe una versión corregida disponible, y el 80% de las dependencias de aplicaciones permanecen sin actualizar durante más de un año. Ese patrón también aplica a las imágenes base de Docker, ya que dependen de los mismos paquetes de código abierto.
Usa imágenes oficiales de editores verificados y fija etiquetas de versión específicas en lugar de depender de "latest". Establece un ciclo de reconstrucción periódico para mantener tus imágenes actualizadas.
Credenciales codificadas de forma fija en Dockerfiles y archivos Compose
Las credenciales escritas en una instrucción ENV o ARG de un Dockerfile, codificadas de forma fija en un bloque de entorno de Compose, pasadas como argumentos de construcción o almacenadas en un archivo .env confirmado en el control de versiones no desaparecen cuando detienes el contenedor. Permanecen en el historial de capas de la imagen o en el control de código fuente, accesibles para cualquiera que pueda llegar a ellos.

Este es uno de los errores de seguridad de Docker más ignorados porque no genera problemas visibles durante el desarrollo. Una clave API en una instrucción ENV funciona correctamente. Pero también está en tu repositorio, integrada en tu imagen y distribuida a donde sea que viaje esa imagen.
Docker Compose moderno incluye un mecanismo nativo de secretos que monta las credenciales en tiempo de ejecución sin integrarlas en la imagen. Los secretos API de Docker y los gestores externos de secretos siguen el mismo principio. Estas son las opciones que mantienen las credenciales completamente fuera de los artefactos de construcción y los archivos confirmados.
Las variables de entorno en tiempo de ejecución son una mejora respecto a las credenciales codificadas de forma fija, pero siguen exponiéndose a través de la salida de Docker inspect, los logs y los volcados de memoria. Son un paso adelante respecto a los secretos integrados en la imagen, no una solución definitiva.
No actualizar las imágenes de contenedor de forma regular
Ejecutar la misma imagen durante meses es un hábito habitual. Cada día que pasa desde que se divulga una nueva vulnerabilidad hasta que reconstruyes, tus contenedores acumulan una ventana de exposición que crece sin ningún cambio visible.
Establece un calendario de reconstrucción consistente. Automatiza ese proceso en la medida de lo posible y ejecuta un escáner de vulnerabilidades periódicamente contra tus imágenes actuales. El objetivo no es la perfección. Es reducir el tiempo entre la publicación de un parche y su despliegue.
El control de acceso y la monitorización pueden quedar en segundo plano en despliegues rápidos. Son también las categorías donde los incidentes pasan más tiempo sin detectarse.
Vacíos en el control de acceso y la visibilidad
Una vez que un contenedor está en ejecución con una configuración sólida e imágenes actualizadas, quedan dos categorías de fallos. Ambas son invisibles por naturaleza: no notarás un problema de control de acceso débil hasta que alguien lo aproveche, y no notarás un vacío en la monitorización hasta que necesites investigar actividad que nunca quedó registrada.
El mismo Investigación Red Hat 2024 encontró que el 42 % de los equipos no contaba con las capacidades suficientes para hacer frente a la seguridad de contenedores y las amenazas relacionadas.
Los problemas de monitorización suelen salir a la luz durante las investigaciones de incidentes, no antes. Para cuando la visibilidad se convierte en prioridad, la respuesta ya es reactiva, no preventiva.
Autenticación débil y paneles de gestión expuestos
Un panel de gestión de contenedores en una IP pública sin autenticación no requiere un atacante sofisticado. Solo necesita conocer la dirección. Es un umbral mucho más bajo de lo que la mayoría de los equipos imagina.

Las herramientas de monitorización y gestión autoalojadas suelen incluir una interfaz web accesible en todas las interfaces de red. Dejarlas en una IP pública sin autenticación es el equivalente, en el mundo de los contenedores, a dejar un panel de administración sin llave.
Autenticación, un proxy inverso y ubicación en red privada son el mínimo indispensable. El control de acceso es un paso de configuración que se añade a cualquier interfaz de gestión, no algo que venga activado de serie.
El mismo principio se aplica a Docker CLI y gestión por GUI; el acceso a nivel de administrador sobre el daemon conlleva el mismo riesgo independientemente de la interfaz.
No monitorizar lo que hacen tus contenedores
Si un contenedor se ve comprometido, la actividad del atacante deja rastro: cambios en el comportamiento de los procesos, conexiones de red inusuales y modificaciones inesperadas de archivos. Sin una recopilación de logs en marcha, ese rastro no existe en una forma sobre la que puedas actuar.
La recopilación centralizada de logs, el registro de auditoría de contenedores y las herramientas de monitorización en tiempo de ejecución te proporcionan los datos necesarios para detectar actividad anómala antes de que se agrave. El objetivo no es analizar cada línea, sino tener los datos disponibles cuando necesites investigar.
Los entornos de contenedores que corren en producción sin pipeline de logs ni alertas no son de bajo mantenimiento. Son entornos sin supervisión. Son dos estados operativos muy distintos.
Por qué el entorno de infraestructura también importa
La seguridad de contenedores empieza por la configuración, pero esa configuración corre sobre infraestructura. Un host con redes mal configuradas, recursos compartidos o sin filtrado a nivel de red crea condiciones que afectan a todos los contenedores que corren sobre él. Configurar correctamente los contenedores y configurar correctamente el servidor son dos tareas distintas.
Muchos problemas de seguridad de Docker se ven amplificados por condiciones que los propios contenedores heredan:
- Un servidor en tenencia compartida sin aislamiento hardware entre inquilinos
- Un kernel del host sin parches aplicados
- Un host sin filtrado de red integrado a nivel de red
Esto no elimina la necesidad de los pasos de configuración descritos antes, ya que el bastionado adecuado de contenedores es importante independientemente de la capa de infraestructura. Partir de una infraestructura aislada elimina una capa de preocupación de la ecuación.
En Cloudzy ofrecemos dos opciones según lo que requiera tu configuración:
- Linux VPS: un entorno limpio para desplegar Docker por tu cuenta y aplicar los pasos de bastionado descritos en este artículo
- Portainer VPS: una opción con un solo clic con Portainer preinstalado; el servidor arranca y ya estás en el panel de control
Ambas opciones funcionan sobre la misma infraestructura: virtualización KVM, procesadores AMD Ryzen 9 CPU a hasta 5,7 GHz de frecuencia boost, memoria DDR5, almacenamiento NVMe SSD, hasta 40 Gbps de red y protección DDoS gratuita mediante filtrado de BuyVM, en 12 ubicaciones globales con un SLA de disponibilidad del 99,95 %.
Para un análisis más detallado sobre cómo ejecutar Portainer en un VPS, lo cubrimos en un artículo específico.
Lista de verificación de seguridad práctica para despliegues con Docker
Los errores de seguridad con Docker descritos anteriormente suelen deberse a decisiones de configuración tomadas una sola vez y que nunca se revisan. Ejecutar esta lista de verificación sobre una configuración existente ayuda a detectar esas lagunas. Es una guía de auditoría, no de despliegue.
Estas buenas prácticas de seguridad en Docker explican cómo proteger los contenedores Docker frente a los errores de configuración más comunes descritos anteriormente.
Referencia rápida: los 9 errores
| Error | Categoría | Solución en una línea |
| Ejecutar como root | Configuración | Añade la directiva USER a tu archivo Dockerfile |
| Puertos vinculados a 0.0.0.0 | Configuración | Vincula a 127.0.0.1 y enruta a través de un proxy inverso |
| Sin aislamiento de red | Configuración | Separa los servicios en redes distintas definidas por el usuario según sus necesidades de acceso. |
| Socket de Docker montado | Configuración | Elimina el montaje; usa APIs con alcance limitado o alternativas |
| Imágenes no verificadas u obsoletas | Imagen | Usa imágenes oficiales con etiquetas de versión fijas |
| Secretos escritos directamente en el código | Imagen | Mueve las credenciales a variables de entorno en tiempo de ejecución o a un gestor de secretos |
| Sin calendario de reconstrucción de imágenes | Imagen | Establece una frecuencia de reconstrucción mensual; automatiza donde sea posible |
| Paneles sin autenticación | Acceso | Añade autenticación y traslada las interfaces de gestión a redes privadas |
| Sin recolección de logs de contenedores | Acceso | Configura logging centralizado y monitorización en tiempo de ejecución |
Recomendamos ejecutarlo primero contra configuraciones existentes, ya que es donde es más probable que ya existan los problemas.
Contenedores ejecutándose como no-root: Revisa tus archivos Docker en busca de una directiva USER. Si no existe ninguna, el contenedor se ejecuta como root.
Bindings de puertos limitados a localhost o con proxy: Ejecuta docker ps y revisa los bindings de puertos. Una entrada 0.0.0.0:PORT puede ser accesible públicamente en hosts donde ningún security group externo, firewall o regla de cadena DOCKER-USER lo bloquee.
Redes bridge personalizadas en uso: Los contenedores en el bridge por defecto de Docker pueden comunicarse entre sí libremente. Los contenedores en el mismo bridge definido por el usuario también pueden comunicarse, así que separa los servicios en redes distintas según el nivel de confianza para lograr un aislamiento real.
Socket de Docker no montado en contenedores: Revisa los archivos Compose y los argumentos de ejecución. Si /var/run/docker.sock aparece como volumen, confirma que es necesario e intencionado.
Imágenes base de publicadores verificados con versiones fijadas: Un FROM ubuntu:latest descarga una versión no especificada y potencialmente desactualizada. Fija una versión concreta.
Sin secretos en archivos Docker, archivos Compose ni argumentos de build: El historial de capas de imagen persiste las credenciales después de eliminar el contenedor. Usa Compose secrets, Swarm secrets, montajes de secretos en el build o un gestor de secretos externo. Las variables de entorno en tiempo de ejecución son mejor opción que los valores hardcodeados, aunque siguen apareciendo en la salida de inspect y en los logs.
Frecuencia de reconstrucción de imágenes definida: Las imágenes antiguas acumulan vulnerabilidades. Una frecuencia de reconstrucción mensual mantiene la ventana de exposición bajo control para la mayoría de configuraciones.
Interfaces de gestión protegidas con autenticación: Cualquier panel en una IP pública sin autenticación es un punto de entrada abierto. Situarlas en una red privada es preferible siempre que sea posible.
Logs de contenedores recopilados: Sin un pipeline de logs, la detección de incidentes depende de que el impacto en el sistema sea visible. Es una señal tardía sobre la que actuar.
Conclusión
La configuración por defecto de Docker está pensada para facilitar el despliegue, no para la seguridad. La mayoría de los errores que se tratan en este artículo tienen su origen en ajustes que nunca se modificaron tras el despliegue inicial, no en ataques sofisticados.
Las correcciones son, en su mayor parte, decisiones de configuración que se toman una sola vez: una directiva USER, un cambio en el binding de puertos, una red personalizada, un calendario de reconstrucción. Para la mayoría de los entornos, no requieren ninguna herramienta adicional.
Configurar correctamente el contenedor es la primera tarea. La infraestructura en la que se ejecuta es la segunda. Ambas importan, y ninguna sustituye a la otra.