Cómo proteger los contenedores Docker en producción

Mon Aug 24 2026

heroImage: “/images/blog-heros/how-to-secure-docker-containers-in-production.png”

Cómo proteger los contenedores Docker en producción

El informe de ActiveState de 2026 encuestó a 250 líderes de DevSecOps de Norteamérica. Todos los encuestados consideraron la contenerización crítica para la estrategia de producción, y el 82 % afirmó que probablemente había sufrido al menos una brecha relacionada con contenedores en los 12 meses anteriores. El mismo informe concluyó que el 91 % consideraba que la visibilidad limitada de los componentes de los contenedores era su mayor punto ciego de seguridad.

Un escaneo de una imagen Docker es un control, no un programa de seguridad de producción. Te indica qué hay dentro de una imagen; no te dice qué privilegios, montajes, redes, acceso al daemon o comportamientos de runtime recibe esa imagen.

Por eso, protege Docker en producción siguiendo el orden del riesgo: refuerza la imagen, limita el despliegue, protege el daemon y el host, detecta el comportamiento en runtime y convierte esos controles en el camino más sencillo para los desarrolladores. El objetivo es ofrecer un valor predeterminado seguro que los desarrolladores puedan consumir sin abrir un ticket de seguridad para cada actualización rutinaria.

SentinelOne cita un 85 % de incidentes relacionados con contenedores en 2023, pero esa cifra anterior, comunicada por un proveedor, utiliza un periodo distinto y no debería combinarse con la encuesta de ActiveState.

Y el texto alternativo dice: Ciclo de vida de la seguridad de contenedores: fases de compilación, registro, despliegue, runtime y respuesta, con la encuesta de ActiveState de 2026 que muestra que el 82 % de las organizaciones experimentaron una brecha de seguridad de contenedores.

En este artículo

Por qué una lista de comprobación de seguridad de Docker no es suficiente

Una lista de comprobación mezcla distintos riesgos en un solo conjunto: las vulnerabilidades de las imágenes, el exceso de capacidades, los sockets expuestos, una configuración débil del host y los procesos sospechosos requieren controles diferentes en puntos diferentes.

ActiveState informa de que el 90 % todavía utiliza imágenes públicas modificadas ligeramente, mientras que el 77 % confía más en catálogos seleccionados que en registros públicos. Esa contradicción señala un problema de flujo de trabajo: un catálogo que exige aprobación de seguridad para cada parche se convierte en una cola que los desarrolladores intentarán evitar.

Por eso, sigue este orden. Cada etapa cierra un modo de fallo distinto:

  1. Crea una imagen pequeña y trazable.
  2. Almacena y verifica el artefacto exacto.
  3. Rechaza configuraciones de despliegue inseguras.
  4. Reduce lo que el host y el daemon pueden exponer.
  5. Supervisa el comportamiento en vivo y asigna un responsable de respuesta.
  6. Automatiza las actualizaciones y las excepciones.

Trata las cifras de la encuesta como orientativas, no como pruebas.

Protege la imagen antes de que llegue a tu registro

Considera un pequeño servicio orders-api creado a partir de una imagen pública de Python. Su primer Dockerfile podría tener este aspecto:

FROM python:latest

WORKDIR /app
COPY . .

RUN apt-get update \
    && apt-get install -y build-essential curl \
    && pip install -r requirements.txt

ENV DATABASE_PASSWORD=change-me

CMD ["python", "app.py"]

La etiqueta móvil latest rompe la reproducibilidad. Los compiladores y gestores de paquetes permanecen en la imagen de runtime, el proceso se ejecuta como root y la contraseña persiste en el historial de la imagen.

Utiliza una compilación multi-stage. Fija la base a una versión o digest procedente de tu proceso de bases compatibles. Elige un runtime minimalista, distroless, Alpine o scratch cuando la aplicación lo permita. Los runtimes más pequeños contienen menos paquetes, aunque las imágenes distroless dificultan la depuración interactiva. Documenta tu método de depuración antes de adoptar una.

Este ejemplo utiliza un entorno virtual para que la ruta de dependencias sea explícita:

FROM python:<pinned-build-version> AS build

WORKDIR /build
RUN python -m venv /venv
ENV PATH="/venv/bin:$PATH"

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

FROM <pinned-minimal-python-runtime>

WORKDIR /app
COPY --from=build /venv /venv
COPY --from=build /build/app.py .

ENV PATH="/venv/bin:$PATH"
USER 10001:10001
CMD ["python", "app.py"]

Utiliza .dockerignore para mantener la configuración local, las credenciales, las pruebas y los resultados de compilación fuera del contexto de compilación:

.git
.env
tests/
__pycache__/
*.pem

El Dockerfile establece el usuario y el contenido; CI debe hacerlos cumplir. Escanea durante la compilación y en CI con Trivy, Grype, Clair o Anchore. La política —no el recuento bruto de CVE— decide qué hallazgos bloquean el lanzamiento: sopesa la gravedad, la explotabilidad, la alcanzabilidad y la necesidad del paquete.

Firma y verifica la imagen antes del despliegue — Cosign es una opción. Registra la revisión del código fuente, el trabajo de compilación, el digest y el firmante como evidencia del lanzamiento.

Restringe quién puede subir imágenes a los repositorios de producción. Conserva etiquetas inmutables o despliega por digest desde fuentes de confianza y con firmas verificadas.

El orders-api corregido elimina DATABASE_PASSWORD de la imagen y lee el secreto de runtime que se muestra a continuación.

latest no es una estrategia de versionado. “Pasó el escaneo una vez” no demuestra que un artefacto de producción siga siendo seguro.

Haz que sea difícil desplegar configuraciones de runtime inseguras

El servicio Compose original también necesita correcciones:

services:
  api:
    image: orders-api:latest
    ports:
      - "8080:8080"
      - "9090:9090"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      DATABASE_PASSWORD: change-me

Publica un puerto innecesario y monta el socket de Docker. Pasa una credencial como valor de entorno. No tiene límites de recursos. El sistema de archivos raíz sigue siendo escribible.

Utiliza esto como perfil Compose inicial para una API sin estado; prueba cada configuración con el servicio en lugar de copiarla como política universal:

services:
  api:
    image: registry.example.com/orders-api@sha256:<approved-digest>
    expose:
      - "8080"
    user: "10001:10001"
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    mem_limit: 512m
    cpus: "1.0"
    pids_limit: 256
    tmpfs:
      - /tmp

expose mantiene el puerto 8080 disponible para otros servicios de la red Compose sin publicarlo directamente en el host. Coloca TLS en un proxy inverso o balanceador de carga si esa es tu arquitectura. Si la API debe estar expuesta directamente a Internet, define explícitamente ese límite y protégelo allí.

Los valores predeterminados de Docker son un punto de partida, no una política de producción — la explotabilidad depende de la carga de trabajo, el host, la red y el atacante.

Aplica el perfil mediante la revisión de Compose, la automatización del despliegue o la admisión de Kubernetes:

  • Utiliza un usuario dedicado. Establece USER en el Dockerfile y confirma que la aplicación funciona sin root. Rootless Docker u otro runtime rootless añade un límite útil cuando la compatibilidad lo permite.
  • Elimina primero las capacidades. --cap-drop ALL elimina el conjunto de capacidades predeterminado del contenedor; vuelve a añadir únicamente las capacidades que la carga de trabajo demuestre necesitar.
  • Haz que el sistema de archivos raíz sea de solo lectura. --read-only bloquea las escrituras ordinarias en el sistema de archivos de la imagen. Proporciona en su lugar al proceso un sistema de archivos temporal o un volumen con un alcance limitado.
  • Limita los recursos. Establece --memory, --cpus y --pids-limit. Estos límites acotan una forma importante de agotamiento de recursos; no impiden todas las vías de denegación de servicio.
  • Limita la exposición de red. Publica los puertos necesarios y conecta únicamente las redes necesarias.

El funcionamiento rootless y el mínimo privilegio pueden romper software que se vincula a puertos privilegiados. Documenta las excepciones con un control compensatorio y una fecha de caducidad.

Mantén los secretos y el socket de Docker fuera del radio de impacto

Una capa de imagen posterior puede ocultar un secreto del sistema de archivos final y, al mismo tiempo, dejar la capa anterior en el historial de la imagen. Mantén DATABASE_PASSWORD fuera del Dockerfile y del repositorio de código fuente.

Para orders-api, un despliegue Docker Compose que utilice un secreto montado podría tener este aspecto:

services:
  api:
    image: registry.example.com/orders-api@sha256:<approved-digest>
    secrets:
      - database_password

secrets:
  database_password:
    external: true

La aplicación debe leer el archivo del secreto en lugar de esperar DATABASE_PASSWORD:

from pathlib import Path

database_password = Path(
    "/run/secrets/database_password"
).read_text().strip()

Las variables de entorno solo son aceptables cuando el runtime las protege de los registros, los informes de fallos y los procesos hermanos no confiables; de lo contrario, utiliza un secreto montado o Vault/AWS Secrets Manager. Rota las credenciales cuando se sospeche una exposición.

El socket de Docker merece una prohibición estricta en los servicios de aplicaciones ordinarios:

volumes:
  - /var/run/docker.sock:/var/run/docker.sock

Un montaje del socket delega el control del daemon: un contenedor comprometido puede ampliar el incidente al host. El acceso remoto a la Docker API necesita TLS, restricción de red y autenticación — nunca expongas un daemon sin autenticación.

CIS detecta desviaciones; no demuestra seguridad

El CIS Docker Benchmark te proporciona una línea base repetible para la configuración del host Docker, el daemon y los contenedores. CIS es útil precisamente porque resulta aburrido; tratar su puntuación como una prueba de seguridad es la parte peligrosa.

Docker Bench for Security audita muchas de esas áreas. Lee atentamente el comando antes de ejecutarlo — monta rutas sensibles del host y el socket de Docker, así que ejecútalo únicamente en un entorno administrativo aprobado:

docker run -it --net host --pid host --cap-add audit_control \
  -v /var/lib:/var/lib \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /usr/lib/systemd/system:/var/lib/systemd/system \
  -v /etc:/etc \
  --label docker_bench_security \
  docker/docker-bench-security

Adapta los montajes a tu entorno y proceso de seguridad. No pegues esto en un host desconocido como si fuera un diagnóstico inofensivo.

Trata una comprobación fallida como una brecha de control. Registra el host o contenedor afectado, la justificación de la excepción, el control compensatorio y una fecha de caducidad.

CIS cubre la configuración del host, el daemon y el contenedor; el escaneo de dependencias, la detección en runtime y la respuesta a incidentes necesitan controles independientes. Ejecuta la auditoría según un calendario y después de cambios en el host para que detecte desviaciones, no una puntuación ceremonial.

Añade detección en runtime porque los escaneos no pueden ver el comportamiento

Un escáner examina un artefacto. La detección en runtime examina lo que hace una carga de trabajo activa. Como señala vcso.ai, “El escaneo que detecta un paquete vulnerable en una imagen de contenedor durante la compilación no detecta la amenaza que solo se materializa en runtime”.

Una compilación limpia aún puede utilizarse de forma indebida después del despliegue, por ejemplo mediante un fallo descubierto recientemente o una ruta de solicitud inesperada. Las herramientas de runtime observan llamadas al sistema, procesos y flujos de red, y después alertan cuando el comportamiento se desvía de la política. Falco es un ejemplo de detección de llamadas al sistema de código abierto.

Empieza con reglas vinculadas al comportamiento conocido de la aplicación. Vigila la aparición de shells inesperadas. Supervisa las escrituras en rutas sensibles y las nuevas conexiones salientes. Rastrea operaciones sensibles a las capacidades. Ajusta las reglas con el responsable del servicio. La detección a la que nadie responde es telemetría, no protección.

En Kubernetes, los controladores de admisión rechazan imágenes, usuarios, capacidades, montajes del host o configuraciones de recursos que infringen la política antes de que se inicien los pods; la supervisión en runtime observa lo que ocurre después de la admisión. Para Docker independiente o Compose, aplica comprobaciones equivalentes en la automatización del despliegue o en la política del host.

Asigna la responsabilidad de respuesta antes de activar las alertas:

  1. Identifica la carga de trabajo, el digest de la imagen, el host o nodo, el proceso y la actividad de red.
  2. Aísla o detén la carga de trabajo según el procedimiento de impacto del servicio.
  3. Rota las credenciales que podrían haber sido accesibles.
  4. Conserva los registros y las pruebas relevantes.
  5. Reconstruye a partir de una base compatible y limpia, y vuelve a desplegar.
  6. Añade una regla preventiva de despliegue o runtime para el fallo.

Exige telemetría útil, alertas explicables y un responsable de respuesta — ningún producto individual detecta todos los ataques.

Crea una ruta de imagen dorada que los desarrolladores utilicen

Un catálogo que espera la aprobación de seguridad para cada parche es una cola que los desarrolladores evitarán.

La contradicción se repite en las encuestas: las personas valoran la ruta más segura, pero a menudo esa ruta tarda demasiado.

Proporciona al catálogo:

  • un pequeño conjunto de bases de lenguajes y servicios;
  • un propietario identificado y un SLA de actualización;
  • versiones y digests fijados;
  • reconstrucciones automatizadas cuando cambien los paquetes base;
  • escaneo, firma y procedencia;
  • ejemplos de uso que se puedan copiar;
  • una ruta de solicitud de autoservicio para nuevas bases;
  • excepciones con propietario, motivo, control compensatorio y fecha de caducidad.

Una solicitud de nueva base debería activar una compilación automatizada que pruebe, escanee, firme y publique. Seguridad revisa la política y los casos excepcionales. No debería inspeccionar manualmente cada parche rutinario.

Permite que los equipos consuman imágenes aprobadas sin abrir un ticket. Cuando cambie una base, publica el nuevo digest, los paquetes afectados y una ventana de migración. Si un equipo necesita una biblioteca de sistema diferente, haz que la ruta de solicitud sea visible y tenga un plazo definido.

Un catálogo no eliminará todos los usos de imágenes públicas. Puede reducir las excepciones sin gobierno al hacer que la opción compatible sea más fácil de adoptar que una línea FROM improvisada.

Elige las herramientas según el control que te falte

Compra el control que te falte. Elige en función de la brecha que cierre, no de la calidad de su demostración. Las siguientes rutas de madurez son ejemplos extraídos de la comparativa de CiphersSecurity de 2026, no clasificaciones de rendimiento independientes.

Situación del equipoEjemplos para empezarPregunta que debes probar
Equipo pequeño con un pipeline de CI establecidoTrivy más Falco¿Puedes escanear y firmar lanzamientos, dirigir las alertas de runtime y exportar evidencias sin crear una nueva cola operativa?
Equipo centrado en Kubernetes que necesita aplicación de políticasSysdig o Aqua¿El producto aplica la política en la admisión y en runtime para tu clúster, y puede el flujo de respuesta identificar al equipo responsable?
Equipo grande multinube con responsabilidades fragmentadasWiz, Prisma Cloud o CrowdStrike¿Asigna activos a propietarios en todo tu entorno, muestra las brechas de política con una profundidad útil y produce evidencias de corrección?

Son puntos de partida, no recomendaciones. Un equipo pequeño debería aplicar primero el escaneo de imágenes, la firma, la política de despliegue y un detector ligero. Una plataforma Kubernetes necesita pronto controles de admisión y runtime porque muchos equipos comparten el clúster. Un entorno multinube fragmentado puede beneficiarse de una CNAPP después de haber definido la propiedad y los controles de referencia.

Docker Scout y SentinelOne Singularity Cloud Security son otros ejemplos del mercado. Una única consola CNAPP puede mostrar las brechas de forma atractiva y, aun así, dejarlas sin corregir. Prueba cada candidato con tu registro, ruta de despliegue, modelo de identidad, punto de aplicación de políticas, enrutamiento de alertas y exportación de evidencias.

Convierte los controles en un ciclo recurrente de producción

Utiliza esta secuencia de implementación:

  1. Haz inventario del entorno. Encuentra las imágenes, los registros, los hosts Docker, los endpoints del daemon, los montajes de sockets, los contenedores root, las configuraciones privilegiadas y los límites de producción.
  2. Elimina las debilidades de mayor impacto. Elimina los secretos integrados, el uso innecesario de root, el modo privilegiado, el exceso de capacidades y los montajes del host no aprobados.
  3. Haz que los artefactos sean reproducibles. Fija las bases y utiliza compilaciones multi-stage. Escanea en CI, firma las imágenes y después despliega por digest.
  4. Aplica la política de despliegue. Exige usuarios compatibles, capacidades eliminadas, sistemas de archivos de solo lectura, límites de recursos, redes aprobadas y registros de confianza.
  5. Audita los hosts. Ejecuta Docker Bench según el CIS Docker Benchmark siguiendo un calendario y registra las excepciones.
  6. Detecta el comportamiento en vivo. Añade supervisión de llamadas al sistema, procesos y red con un responsable de respuesta identificado.
  7. Automatiza el mantenimiento. Reconstruye las bases compatibles y vuelve a probar las aplicaciones. Vuelve a publicar imágenes firmadas, notifica a los consumidores y haz caducar las excepciones.

Este orden es un buen valor predeterminado, no un sustituto del modelado de amenazas de tus cargas de trabajo. Mide la explotabilidad, los requisitos de privilegios y la exposición a Internet antes de cambiar la secuencia para un servicio de alto riesgo.

ActiveState informa de que el 100 % de los encuestados probablemente utilizaría IA o automatización para priorizar vulnerabilidades, mientras que el 95 % esperaba que la corrección inteligente se convirtiera en estándar para 2026. Utiliza esa ayuda para clasificar los hallazgos, sugerir cambios en las dependencias o el Dockerfile, abrir pull requests de corrección y resumir las cargas de trabajo afectadas.

Trata el resultado de la IA como un cambio propuesto; el propietario del servicio sigue siendo responsable de las pruebas, la aprobación, la procedencia y la reversión. La IA puede redactar una pull request útil. No puede demostrar que la aplicación siga funcionando ni que el artefacto resultante sea confiable.

Para orders-api, genera este registro de lanzamiento a partir de los metadatos de CI y la configuración de despliegue, y después compáralo en cada lanzamiento:

digest | user | capabilities | writable paths | reachable networks | detector | response owner

Si un lanzamiento no puede responder a esos siete campos, detén el despliegue y corrige la ruta de evidencias antes de añadir otro producto de seguridad.