El patrón que más he visto en incidentes (o casi-incidentes) de supply chain con contenedores no es sofisticado: un equipo hereda una imagen base “oficial” desde un registry público, el pipeline la consume con :latest y, sin darse cuenta, esa base cambia. A veces cambia por una actualización legítima; otras, porque alguien comprometió la cuenta del mantenedor o el proceso de publicación. El resultado práctico es el mismo: tu CI/CD descarga algo distinto a lo que revisaste, y lo ejecuta con tus permisos, tu red y tus datos.
Cuando hablamos de ECR (AWS), ACR (Azure) o GCR/Artifact Registry (Google Cloud), el error típico es asumir que “si ya está en el registry de la empresa, es seguro”. No lo es si no hay controles al hacer push (escaneo, firma, inmutabilidad, políticas de despliegue). Un registry privado sin guardrails es, simplemente, un espejo interno de los mismos riesgos, solo que ahora con distribución más rápida hacia producción.
Qué salió mal: tags mutables y herencia de imágenes “oficiales”
El fallo de base casi siempre empieza con una decisión operativa: usar python:latest, alpine:latest o similares “por comodidad”. En un entorno corporativo, esa comodidad se convierte en variabilidad: el build de hoy no es el build de mañana, aunque el Dockerfile no haya cambiado. Cuando aparece un comportamiento anómalo (CPU al 100%, conexiones salientes raras, procesos desconocidos), el equipo pierde horas porque la reproducibilidad se rompió.
La herencia de “imágenes oficiales” no elimina el riesgo; lo desplaza. Si un atacante compromete la cuenta del mantenedor o el pipeline de publicación upstream e inyecta un criptominero o un reverse shell, tu pipeline lo tratará como una actualización legítima. Y como las imágenes base se usan transversalmente (API, jobs, workers), el blast radius no es una app: es media plataforma.
- Uso de
:latesten CI/CD
Esto permite que el tag apunte a un digest distinto sin que nadie lo note. En la práctica, el cambio entra como “un rebuild” y termina desplegado por el mismo flujo automatizado que te da velocidad. Si el runtime tiene egress a Internet, credenciales en variables o acceso a colas/buckets, el atacante hereda ese acceso.
- “Oficial” no significa “inmutable” ni “apto para tu threat model”
Aunque la imagen sea popular, tu riesgo está en el eslabón de publicación y en tu forma de consumirla. Si no anclas por digest (sha256:...), no hay garantía de que el artefacto desplegado sea el mismo que el aprobado. En auditorías internas, esto suele ser un punto de fricción: no puedes demostrar qué exacto binario ejecutaste.
Superficie de ataque en ECR, ACR y GCR: el registry como acelerador del incidente
En cloud corporativo, el registry privado suele estar integrado con IAM (roles, service principals, workload identity) y con el pipeline de build/deploy. Eso es bueno para operar, pero amplifica incidentes: si una imagen maliciosa llega al registry, se vuelve “distribución de confianza” interna. En lugar de que cada equipo haga pull desde Internet (ruidoso y a veces bloqueado), todo el mundo consume desde ECR/ACR/GCR, rápido y sin sospechas.
El malentendido frecuente es pensar que la seguridad está “en el perímetro” del registry (privado, con RBAC). La realidad es que el riesgo de supply chain es de integridad del artefacto. Puedes tener autenticación perfecta y, aun así, estar propagando una imagen con backdoor si nadie la escaneó al entrar o si nadie valida firma/digest en el despliegue.
- Compromiso upstream + replicación interna
Un escenario típico: el equipo de plataforma crea una imagen base corporativa (por ejemplo, corp/python-base) que FROM python:latest. La publica en ECR/ACR/GCR y docenas de repos la heredan. Si upstream se contamina, el siguiente rebuild de la base corporativa arrastra el problema y lo hace “estándar” en la organización.
- Permisos del runtime como multiplicador
La imagen no necesita “explotar” nada si ya se ejecuta con permisos útiles. En empresas es común ver workloads con acceso a secretos, colas, buckets o APIs internas. Un criptominero consume presupuesto; un reverse shell consume confidencialidad y puede pivotar a sistemas laterales. El registry no causa el exploit, pero sí acelera el despliegue del payload.
Señales tempranas y errores de interpretación que te hacen perder días
Cuando entra una imagen contaminada, rara vez se detecta por “alerta de container registry”. Se detecta por síntomas operativos: aumento de consumo, conexiones extrañas, o procesos inesperados. El problema es que, si el equipo no tiene trazabilidad por digest y no registra qué imagen exacta se desplegó, el diagnóstico se convierte en una discusión de hipótesis.
Otro error común es asumir que pasar la imagen por el registry corporativo “la sanea”. En muchos entornos, el registry es solo almacenamiento. Si no se fuerza escaneo al hacer push y si el despliegue no aplica políticas (deny) basadas en resultados de escaneo/firma, el control es cosmético.
- Drift entre build y runtime
Si el pipeline construye con un tag mutable, dos ejecuciones del mismo job pueden producir imágenes distintas. En incident response esto es crítico: no puedes reproducir el binario, no puedes correlacionar hashes, y el rollback se vuelve incierto (¿a qué “versión” vuelves si todo era :latest?).
- “Está en ECR/ACR/GCR, luego está aprobado”
En la práctica, ese supuesto lleva a relajar revisiones: se reduce el scrutiny en despliegue y se confía en que “plataforma lo controla”. Si plataforma no configuró inmutabilidad, no escanea en push y no exige firma, el registry termina siendo un repositorio de artefactos opacos, no un control de seguridad.
Cómo hacerlo en la práctica: inmutabilidad, escaneo en push y verificación por digest
La primera decisión operativa es cortar la mutabilidad donde más duele: tags reescribibles y consumo sin digest. En registries corporativos, bloquea overwrites (inmutabilidad de tags) y fuerza a que el despliegue referencie digest cuando el riesgo lo justifique (bases y runtimes críticos). Esto no es “purismo”: es reproducibilidad y capacidad de respuesta.
El segundo eje es que el artefacto se evalúe al entrar, no cuando ya está corriendo. El escaneo automático al hacer push no te garantiza “cero riesgo”, pero sí te evita introducir vulnerabilidades conocidas por defecto y te da un punto de control consistente. El escaneo debe ser parte del flujo de publicación al registry; si queda como tarea manual “cuando haya tiempo”, no ocurrirá.
- Ejemplo (AWS ECR): política para impedir borrar o sobrescribir tags
En AWS, combina controles de ECR con IAM para reducir mutabilidad operativa. Por ejemplo, niega ecr:BatchDeleteImage y ecr:DeleteRepository a identidades de CI/CD salvo excepciones controladas. A nivel de repositorio, habilita inmutabilidad de tags (setting del repositorio) para evitar que un push reescriba un tag existente. Valida el resultado intentando re-publicar el mismo tag y verificando que el registry lo rechaza.
- Ejemplo (Azure ACR): habilitar quarantine/escaneo en el flujo de importación
En ACR, un patrón corporativo efectivo es importar desde público hacia un repositorio controlado (en lugar de pulls directos desde Internet) y aplicar escaneo/validación antes de promover a “release”. Aunque el mecanismo exacto depende de tus herramientas (Defender for Cloud, integraciones de CI), la validación práctica es siempre la misma: el tag que consume producción solo se crea/promueve si el escaneo pasa y queda registrado como artefacto aprobado.
- Ejemplo (GCR/Artifact Registry): consumo por digest en manifests de despliegue
En GCP, el cambio más tangible es dejar de desplegar image: repo/app:tag cuando el riesgo es alto y pasar a image: repo/app@sha256:.... Lo validas revisando el manifiesto aplicado (por ejemplo, lo que realmente quedó en el cluster) y comparándolo con el digest del registry. Esto elimina la sorpresa de que “el tag se movió” entre entornos.
Firmas de imágenes y políticas de despliegue: Cosign/Notation para que el control sea ejecutable
Escanear ayuda, pero no resuelve el problema de integridad: una imagen puede estar libre de CVEs críticos y aun así incluir un payload. La firma de imágenes (Cosign o Notation) ataca el punto clave: demostrar quién produjo el artefacto y evitar que se despliegue algo no autorizado. En empresas, la diferencia entre “tenemos firmas” y “las firmas sirven” es si existe una política que bloquee despliegues no firmados.
Operativamente, esto requiere dos piezas: firmar en el pipeline (idealmente con identidad de workload, no con llaves estáticas en secretos) y verificar en el admission/deploy step. En Kubernetes suele materializarse como policy-as-code (por ejemplo, Gatekeeper/Kyverno) que exige firma válida para imágenes provenientes de ECR/ACR/GCR. En plataformas serverless/managed, se aterriza como validaciones en el pipeline de release (solo promover si la firma está presente y corresponde a la identidad esperada).
- Política corporativa mínima: “no firmado, no se despliega”
Suena dura, pero es la única forma de evitar bypasses por prisa. En la práctica, se arranca con un modo “audit” (solo reporta) para medir impacto, y se pasa a “enforce” por dominios: primero base images internas, luego workloads de exposición pública. Lo importante es que la excepción sea explícita, temporal y registrada, no un “apagamos la policy porque rompe el deploy”.
- Verificación práctica: trazabilidad de firma ↔ digest
Una verificación real no se queda en “la imagen tiene un tag firmado”. Debe atar la firma al digest. El control útil es: para un digest específico en ECR/ACR/GCR, existe una firma válida emitida por la identidad esperada del pipeline. Así, aunque alguien intente mover un tag, el despliegue no aceptará un digest no firmado.
Recomendaciones para entornos corporativos
Si tu organización consume imágenes base públicas, el riesgo principal no es “usar open source”: es consumir artefactos mutables sin anclaje, y permitir que el pipeline propague cambios no revisados. El primer guardrail que realmente reduce incidentes es dejar de depender de :latest y empezar a operar con digest para bases críticas, porque devuelve reproducibilidad y acelera respuesta ante anomalías.
Un registry corporativo (ECR/ACR/GCR) aporta control solo si se usa como punto de control: inmutabilidad de tags para evitar overwrites, escaneo automático al hacer push/import y un flujo de promoción donde producción consume únicamente artefactos aprobados. Cuando esto no existe, el registry privado se vuelve un acelerador de propagación de artefactos inseguros.
Para cerrar el círculo de supply chain, firma imágenes con Cosign/Notation en el pipeline y convierte la verificación en una política ejecutable que bloquee despliegues no firmados. En entornos con presión por entregar, la política debe estar diseñada para sobrevivir a la urgencia: audit primero para medir, enforce por fases, y excepciones mínimas con caducidad y trazabilidad.
¿Te interesa la seguridad en Cloud?
Comparto análisis técnicos, laboratorios prácticos y experiencias reales sobre Cloud Security.