← Blog

Seguridad de imágenes Docker: escaneo, hardening y procedencia

Guía práctica de seguridad de imágenes Docker: escanea vulnerabilidades, haz hardening con imágenes mínimas, firma y protege la cadena de suministro.

Bruno Baldo·Oct 5, 2026·Actualizado el Sep 14, 2026·12 min de lectura·Revisado por Rainforest Technologies

Una imagen Docker es el único artefacto que viaja desde el portátil de una persona desarrolladora, a través del CI, hasta un registry y hasta lo que sea que la ejecute en producción. Eso convierte a la seguridad de imágenes Docker en una de las inversiones de mayor apalancamiento que un equipo puede hacer: aplica hardening a la imagen una vez y todo entorno que la descargue hereda el resultado; entrega una imagen vulnerable o alterada una vez y cada uno de ellos hereda eso en su lugar. La imagen es un sistema de archivos congelado en el que el runtime confía por completo: no inspecciona lo que hay dentro, simplemente lo ejecuta. Decidir qué entra, verificarlo con escaneo de imágenes de contenedor y demostrar de dónde vino es donde la seguridad de la cadena de suministro de contenedores realmente empieza.

Este es un análisis a fondo de la imagen en sí, parte del panorama más amplio de seguridad de Docker y contenedores. Está deliberadamente enfocado en Docker y en el registry: para ver cómo las mismas preocupaciones se manifiestan en la capa de orquestación —admission control, pulls verificados, drift en runtime— consulta la guía complementaria sobre seguridad de imágenes Kubernetes. Aquí nos quedamos con el build, el registry y el flujo de trabajo local donde se crean las imágenes.

Anatomía del riesgo de imagen

Para proteger una imagen a propósito, y no por costumbre, ayuda nombrar los distintos tipos de riesgo que carga.

Paquetes del sistema operativo. La imagen base trae una distribución entera de bibliotecas y utilidades de sistema. Estas acumulan CVE con el tiempo, y una imagen base que estaba limpia hace dos meses casi con seguridad ya no lo está hoy. Los paquetes del sistema operativo sin parche son la fuente aislada más común de vulnerabilidades de imagen.

Dependencias de la aplicación. Tu aplicación incorpora bibliotecas open-source de npm, PyPI, Maven, módulos Go y sus dependencias transitivas. Una versión con vulnerabilidades conocidas enterrada en lo profundo del árbol es tan explotable dentro de un contenedor como en cualquier otro lugar, y más fácil de pasar por alto.

Layers e historial. Una imagen Docker no es un sistema de archivos plano; es una pila de layers, cada uno registrando un paso del build. Los layers se cachean, se direccionan por contenido y son inmutables. Eso es excelente para la reproducibilidad y pésimo para cualquier cosa que desearías no haber confirmado, porque un archivo agregado en un layer persiste en el historial aunque un layer posterior lo elimine.

Secretos incrustados. Los secretos terminan incrustados en imágenes con más frecuencia de la que se admite: una clave de API en una línea ENV, un token .npmrc, una clave SSH COPY-ada para una dependencia privada y nunca eliminada. Debido al comportamiento de layers anterior, RUN rm secret.key no elimina el secreto: solo lo oculta del sistema de archivos final mientras lo deja intacto en un layer anterior.

Procedencia. Por último, la pregunta que la mayoría de las imágenes no puede responder por sí sola: ¿de dónde vino esto en realidad? Sin procedencia no puedes distinguir una imagen que tu CI construyó y aprobó de una que un atacante subió a tu registry bajo la misma tag.

Hardening en el origen: imágenes base mínimas y non-root

Las victorias de seguridad más baratas ocurren antes de que corra cualquier escáner, controlando qué entra en la imagen en primer lugar.

Prefiere imágenes base mínimas o distroless. Una imagen distroless contiene tu aplicación y sus dependencias de runtime y casi nada más: sin shell, sin gestor de paquetes, sin utilidades de uso general. Eso reduce la superficie de ataque de forma directa (menos paquetes significa menos CVE) y hace la post-explotación mucho más difícil, porque un atacante que logra ejecución de código no encuentra shell con el que pivotar. Un build multi-stage te permite compilar en una imagen con toolchain completo y entregar solo el resultado, de modo que los compiladores y las herramientas de build nunca lleguen a producción.

Ejecuta como un usuario non-root. Si el proceso no necesita root, no le concedas root.

# Multi-stage build: compile in a full image, ship a minimal one

FROM golang:1.23 AS build

WORKDIR /src

COPY . .

RUN CGO_ENABLED=0 go build -o /app ./cmd/server

FROM gcr.io/distroless/static:nonroot

COPY --from=build /app /app

USER nonroot:nonroot

ENTRYPOINT ["/app"]

La elección de la imagen base y las instrucciones del Dockerfile a su alrededor merecen tratarse como una disciplina propia; consulta las mejores prácticas de seguridad de Dockerfile para los detalles del build, desde el pinning de versiones hasta el orden de los layers para que los secretos nunca entren en ellos.

Escaneo de vulnerabilidades: SCA en toda la imagen

No puedes corregir lo que no puedes ver, y el escaneo de imágenes de contenedor es cómo lo ves. Un escaneo eficaz usa análisis de composición de software (SCA) para inventariar todo lo que hay en la imagen —tanto paquetes del sistema operativo como dependencias de la aplicación— y cruzar ese inventario con datos de vulnerabilidades. Escanear solo el layer del sistema operativo o solo las dependencias de la aplicación deja la mitad de la imagen sin examinar; el escaneo de vulnerabilidades de imagen tiene que abarcar el artefacto entero.

Dos principios hacen que el escaneo sea útil en lugar de ruido.

Escanea en el build y de forma continua. Escanea en CI para que la persona desarrolladora reciba retroalimentación en el pull request que introdujo una dependencia mala, mientras la corrección todavía es un cambio de cinco minutos. Luego escanea de nuevo en el registry, de forma programada, porque los datos de vulnerabilidades cambian aunque tu imagen no lo haga. Una imagen que pasó limpia la semana pasada puede fallar esta semana cuando se divulga un nuevo CVE crítico contra un paquete que ya contiene. Solo el reescaneo continuo de imágenes almacenadas captura eso.

Haz que el build falle ante los críticos con corrección disponible. Un escaneo que solo emite un reporte se ignora. Conecta el escáner al pipeline para que los nuevos hallazgos de severidad crítica (y, cuando corresponda, alta) rompan el build, y acota el gate a problemas que de verdad tengan una corrección disponible, para que los equipos no queden bloqueados por CVE que no pueden resolver.

# CI step: scan and fail on new fixable critical/high findings

rainforest image scan registry.example.com/app:$GIT_SHA \

  --severity CRITICAL,HIGH \

  --fail-on CRITICAL,HIGH \

  --ignore-unfixed

Inspeccionar layers e historial en busca de secretos filtrados

El escaneo de vulnerabilidades encuentra paquetes vulnerables; no necesariamente encuentra la clave privada que alguien copió durante un build. Como los layers son inmutables y se cachean, la detección de secretos tiene que mirar el historial de layers, no solo el sistema de archivos final.

Los propios metadatos de la imagen son el punto de partida. docker history muestra el comando detrás de cada layer, lo que expone errores obvios como un secreto pasado como argumento de build o definido en ENV:

docker history --no-trunc registry.example.com/app:$GIT_SHA

Para ir más allá, descomprime la imagen e inspecciona el contenido de cada layer. Guardar una imagen la expande en sus tarballs de layer individuales, de modo que un archivo eliminado en un layer posterior sigue siendo recuperable —y detectable— en el layer que lo agregó:

docker save registry.example.com/app:$GIT_SHA -o app.tar

mkdir app && tar -xf app.tar -C app

# each layer/*.tar is a filesystem diff you can search for keys, tokens, .env files

La detección automatizada de secretos integra esto al pipeline para que cada layer se escanee en busca de patrones de credenciales como parte del mismo gate que ejecuta el SCA, lo cual es mucho más confiable que esperar que un revisor detecte un token filtrado en un diff. La remediación no es rm: es reconstruir sin el secreto en ningún layer, rotar la credencial expuesta y usar build secret mounts para que el valor nunca llegue a entrar en una imagen.

Tags versus digests inmutables

Una tag como app:1.4 es un puntero mutable. Quien pueda hacer push al registry puede reapuntarla a un contenido distinto, lo que significa que una imagen que escaneaste y aprobaste puede convertirse en silencio en una imagen diferente bajo el mismo nombre. Un digest —app@sha256:...— es la identidad de la imagen direccionada por contenido y no puede cambiar sin cambiar la referencia.

Las reglas prácticas se desprenden de eso:

  • Nunca hagas deploy de `:latest` en producción. Con :latest no puedes decir qué se está ejecutando, no puedes reproducir un deploy y no puedes vincular una carga de trabajo en ejecución a un resultado de escaneo específico.
  • Fija las referencias de producción por digest. Un digest es reproducible y evidencia alteraciones; es la garantía más fuerte de que lo que verificaste es lo que se ejecuta.
  • Trata las tags de release como inmutables. Una vez que una tag apunta a un digest, no la reapuntes. Muchos registries pueden imponer la inmutabilidad de tags de forma directa.

Cómo se almacenan y sirven esas imágenes es un tema propio; la seguridad de container registry cubre en profundidad los registries privados, el control de acceso y la imposición de inmutabilidad.

Firma de imágenes y procedencia

El escaneo te dice qué hay dentro de una imagen. La firma de imágenes y la procedencia te dicen de dónde vino y si conviene confiar en ella.

La mecánica es directa. Cuando tu pipeline construye una imagen, firma criptográficamente el digest resultante y registra attestations: declaraciones legibles por máquina sobre cómo se produjo la imagen: qué commit de origen, qué builder, qué pasos corrieron. Las propias herramientas de Docker han ofrecido esto en varias formas a lo largo de los años (Docker Content Trust y, más recientemente, firmas separadas y attestations mediante un flujo estilo Notation y firma sin clave con transparency log al estilo del enfoque cosign). El principio subyacente es el mismo sin importar la herramienta: firma el digest en el momento del build, verifica la firma antes de confiar en la imagen.

Este es el núcleo del framework SLSA (Supply-chain Levels for Software Artifacts), que define niveles crecientes de integridad de procedencia para un build. La firma cierra una brecha que ni el escaneo ni el control de acceso al registry pueden cerrar: incluso si un atacante sube una imagen maliciosa bajo un nombre legítimo, no llevará una firma válida de una clave que tu organización controla, y la verificación la rechaza. Como la firma y la verificación viven en el pipeline y no en un paso manual, la procedencia se impone de forma automática para cada imagen, en lugar de depender de que alguien se acuerde de comprobar.

Un SBOM para cada imagen

Un software bill of materials (SBOM) es un inventario completo y legible por máquina de todo lo que contiene una imagen: cada paquete del sistema operativo y cada dependencia de la aplicación, con versiones. Generar uno por imagen y almacenarlo como attestation junto a la imagen cambia la forma en que respondes a la próxima gran vulnerabilidad.

Cuando un CVE crítico cae sobre una biblioteca de uso extendido, la pregunta "¿cuáles de nuestras imágenes entregan la versión afectada?" se convierte en una consulta a SBOM almacenados en lugar de una ronda frenética de rebuilds e inspección manual. El SBOM también es la entrada natural para el escaneo continuo: reevaluar un SBOM almacenado contra datos de vulnerabilidades frescos es exactamente como un reescaneo de registry marca una imagen que estaba limpia cuando se construyó. Los builders modernos pueden emitir un SBOM como parte del build, de modo que carga las mismas garantías de procedencia que la propia imagen. Aquí es donde la seguridad de imágenes se encuentra con el análisis de composición de software de la forma más directa: el SBOM es el inventario compartido del que ambas dependen.

De la imagen a lo que la ejecuta

Todo lo anterior produce un artefacto confiable; algo todavía tiene que rechazar los que no lo son. En un flujo de trabajo centrado en Docker, esa imposición vive en el CI (haz que el build falle) y en el registry (bloquea o pon en cuarentena las imágenes que incumplen la política). Cuando esas imágenes se ejecutan bajo un orquestador, las mismas señales —una firma válida, un escaneo aprobado, una referencia por digest en lugar de una tag mutable— se convierten en entradas para el admission control, que puede denegar cualquier pod cuya imagen no cumpla la política antes siquiera de ser agendado. La guía de seguridad de imágenes Kubernetes cubre ese gate en detalle. El punto importante es la continuidad: la firma que adjuntas y el SBOM que generas en el momento del build son exactamente la evidencia que la capa de admisión comprueba en el momento del deploy, de modo que la seguridad de imágenes y la imposición en tiempo de deploy son dos extremos de una misma cadena.

Ese es el patrón en cada sección de aquí. La seguridad de imágenes no es una sola herramienta sino una secuencia de checkpoints —imagen base, build, escaneo, verificación de secretos, firma, SBOM, almacenamiento, pinning— y una debilidad en cualquier eslabón socava el resto. Cuanto antes en esa secuencia se detecta un problema, más barato es corregirlo, y por eso buena parte del trabajo pertenece al CI y al registry, y no al posdeploy.

Cómo ayuda Rainforest

Proteger toda esa cadena es más fácil cuando los checkpoints comparten una única visión de tu software. Rainforest reúne la seguridad de contenedores y el análisis de composición de software para que puedas escanear imágenes Docker tanto en paquetes del sistema operativo como en dependencias de la aplicación, revelar secretos incrustados en el historial de layers, generar un SBOM por imagen y hacer seguimiento de los hallazgos desde el pull request hasta el registry. Como la misma plataforma también evalúa las dependencias que tus aplicaciones incorporan y la infraestructura como código que las despliega, una imagen y todo lo que la rodea se evalúan como una única cadena de suministro conectada, y no de forma aislada, que es como las fallas de la cadena de suministro de software, rastreadas como la categoría A03 en el OWASP Top 10 (2025), llegan de verdad a producción.

Si estás construyendo tu seguridad de imágenes Docker, agenda una demo y recorreremos el escaneo, el hardening y la procedencia para tu cadena de suministro de imágenes de extremo a extremo.

Preguntas frecuentes

¿Cómo escaneo una imagen Docker en busca de vulnerabilidades?

Usa un escáner de imágenes de contenedor apoyado en análisis de composición de software (SCA) que inventaríe tanto los paquetes del sistema operativo como las dependencias de la aplicación y los cruce con CVE conocidos; escanear solo un layer deja el otro sin examinar. Ejecuta el escaneo en CI para que las personas desarrolladoras reciban retroalimentación en el cambio que introdujo el problema, y ejecútalo de nuevo en el registry de forma programada para que las imágenes ya publicadas se reevalúen a medida que se divulgan nuevas vulnerabilidades. Configura el pipeline para que falle ante nuevos hallazgos de severidad crítica (y típicamente alta), y acota el gate a problemas que tengan una corrección disponible, para que siga siendo accionable.

¿Qué es la firma de imágenes y por qué importa?

La firma de imágenes adjunta una firma criptográfica al digest de una imagen, y las attestations de procedencia registran cómo se construyó la imagen (el modelo SLSA). Antes de que algo confíe en la imagen, verifica esa firma. Esto importa porque el escaneo y el control de acceso al registry no pueden decirte que una imagen vino de verdad de tu pipeline: un atacante que pueda hacer push a tu registry podría sustituir una imagen maliciosa bajo un nombre legítimo. Una firma válida de una clave que tu organización controla, comprobada en el momento de la verificación, es lo que atrapa exactamente esa sustitución.

¿Debería usar tags o digests de imagen?

Usa digests inmutables (app@sha256:...) para cualquier cosa que despliegues en producción. Una tag es un puntero mutable que puede reapuntarse a un contenido distinto, así que una imagen que escaneaste y aprobaste puede convertirse en silencio en una imagen diferente bajo el mismo nombre; un digest está direccionado por contenido y no puede cambiar sin que cambie la referencia. Nunca hagas deploy de :latest, porque hace que los deploys sean no reproducibles e imposibles de vincular a un escaneo específico. Las tags de release legibles por humanos están bien por conveniencia, siempre que las trates como inmutables y fijes el deploy real por digest.

¿Qué es una imagen distroless?

Una imagen distroless es una imagen base mínima que contiene solo tu aplicación y sus dependencias de runtime: sin shell, sin gestor de paquetes y sin ninguna de las utilidades de uso general que trae una distribución Linux normal. Eso reduce la superficie de ataque (menos paquetes significa menos CVE para que un escáner encuentre) y hace la post-explotación mucho más difícil, porque un atacante que obtiene ejecución de código no tiene shell con el que pivotar. Combínala con un usuario non-root y un build multi-stage para que los compiladores y las herramientas de build queden por completo fuera de la imagen final.

¿Cómo encuentro secretos incrustados en una imagen?

Mira el historial de layers, no solo el sistema de archivos final, porque un secreto agregado en un layer sobrevive ahí aunque un layer posterior lo borre. Empieza con docker history --no-trunc para atrapar secretos pasados por argumentos de build o ENV, luego usa docker save para descomprimir la imagen en sus tarballs por layer y buscar en cada uno claves, tokens y archivos .env. Mejor aún, ejecuta detección automatizada de secretos en tu pipeline para que cada layer se escanee como parte del mismo gate que el SCA. Si encuentras uno, reconstruye sin el secreto en ningún layer, rota la credencial expuesta y usa build secret mounts para que el valor nunca vuelva a entrar en una imagen.

Bruno Baldo

Escrito por

Bruno Baldo

CMO

Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Siga leyendo