Módulo 6: Runtime Security Admission Control And Image Scanning
1. Introducción al módulo: el portero antes de `etcd`
Descripción
Los Módulos 1-5 construyeron un clúster completo: Pods, Deployments, Services, ConfigMaps, Secrets, probes, autoscaling, Ingress, NetworkPolicy, y GitOps pull-based con ArgoCD sincronizando andes-cargo-status-api desde un repositorio Git real. En ningún momento, sin embargo, se le preguntó a ningún objeto —antes de crearlo— si tenía permitido existir. Cualquier Pod bien formado, con cualquier imagen, con cualquier cantidad de CPU o memoria (o ninguna), llegó a etcd sin que nadie lo detuviera. Este módulo cierra esa puerta: instala dos motores de políticas distintos que se paran, literalmente, en el único punto de entrada al clúster (kube-apiserver, Módulo 1, lección 6) y deciden, objeto por objeto, si tiene permitido pasar — antes de que exista.
Este no es un tema nuevo del ecosistema Andes Cargo. Es un tema que otra guía ya nombró, con precisión, y dejó explícitamente para esta.
Conexión con el módulo
cloud-security-and-guardrails-guide construyó ocho módulos completos de seguridad preventiva y detectiva sobre la infraestructura Terraform/AWS de Andes Cargo —OIDC, secretos, conftest/Rego contra un terraform plan, escaneo de HCL con Trivy y Checkov, SBOM y firma con cosign—. En su Módulo 7, esa guía nombró explícitamente el par de conceptos que este módulo construye (preventivo/detectivo), y en su frontera de alcance dejó esta cita exacta, sin ambigüedad, señalando hacia aquí.
La cita textual completa
cloud-security-and-guardrails-guide/DISENO.md, en la sección "NO entra en (frontera con guías hermanas)", dice, palabra por palabra:
"EKS y runtime de contenedores (admission controllers en clúster — OPA Gatekeeper, Kyverno —, escaneo de imágenes Docker,
NetworkPolicy) →kubernetes-and-eks-in-production-guide. Andes Cargo no tiene contenedores en este ecosistema (el handler Lambda se empaqueta en.zip, no en imagen); el escaneo y la firma de esta guía son de artefacto de despliegue y de IaC, no de imagen de contenedor."
Vale la pena leer esa cita dos veces, porque nombra tres cosas que delega, no una:
- Admission controllers en clúster — OPA Gatekeeper y Kyverno, nombrados por su nombre propio, sin construirse ahí.
- Escaneo de imágenes Docker — distinto, la propia cita lo aclara, del escaneo que esa guía sí hace (
trivy configsobre HCL, en su Módulo 5). NetworkPolicy— que, en realidad, ya construiste tú, en el Módulo 4 de esta misma guía, antes de llegar aquí. Se nombra en la cita porque, al momento de escribir esa frontera,cloud-security-and-guardrails-guideno sabía todavía en qué orden ibas a leer las guías del ecosistema — la cita es una promesa de cobertura, no un anuncio de que faltaba construirla.
Y hay una frase, dentro de esa misma cita, que merece su propio párrafo: "Andes Cargo no tiene contenedores en este ecosistema". Esa era la foto exacta hasta el punto en que cloud-security-and-guardrails-guide se escribió — el caso Andes Cargo, en su origen (aws-core-services-guide), es un handler Lambda empaquetado en .zip, sin Docker de por medio. Tú, sin embargo, empezaste este módulo habiendo ya construido cinco módulos completos sobre un clúster de Kubernetes real, con una imagen Docker real (andes-cargo-status-api:latest) corriendo en Pods reales. La premisa "Andes Cargo no tiene contenedores" dejó de ser cierta en el momento exacto en que terminaste el Módulo 1 de esta guía — este módulo es, entre otras cosas, el que hereda esa corrección de continuidad y la usa como terreno de trabajo real, no hipotético.
Qué NO cubre cloud-security-and-guardrails-guide, y qué sí cubre este módulo
La tabla siguiente no es un resumen genérico — es la traducción literal, punto por punto, de la cita anterior a lo que vas a construir en las próximas siete lecciones:
Lo que cloud-security-and-guardrails-guide sí construyó | El artefacto exacto | Lo que este módulo construye en su lugar |
|---|---|---|
Policy-as-code con conftest/OPA (Módulo 4) | Rego evaluando un terraform plan en JSON, fuera del clúster, como un archivo estático | Rego (Gatekeeper) y YAML (Kyverno) evaluando objetos en vivo, dentro del clúster, en el instante de cada kubectl apply |
| Escaneo de infraestructura con Trivy (Módulo 5) | trivy config sobre archivos .tf (HCL) — busca configuración insegura declarada, nunca ejecutada | trivy image sobre andes-cargo-status-api:latest — busca vulnerabilidades reales, ya instaladas, en las capas de un artefacto que sí corre |
| Preventivo vs. detectivo, nombrado (Módulo 7) | CloudTrail como el ejemplo central de "detectivo": queda registro, después del hecho | Admission control como el ejemplo central de "preventivo": decide antes de que el objeto exista — el mismo vocabulario, aplicado a una capa distinta |
Supply chain, SBOM y firma con cosign (Módulo 6) | Verifica que un artefacto de despliegue (el .zip de Lambda) no fue alterado, antes de que apply.yml lo suba | Fuera de alcance de este módulo — firmar y verificar una imagen de contenedor (cosign sobre OCI) seguiría el mismo patrón conceptual, pero no se construye aquí; queda nombrado como el paso natural que seguiría a este módulo si el ecosistema lo necesitara |
La fila que de verdad importa retener, antes de seguir: el mismo problema —"¿esta configuración es segura antes de que corra?"— tiene una solución distinta según en qué capa vive el objeto que evalúas. Un terraform plan es un documento JSON que existe antes de que AWS cree nada; conftest lo evalúa como archivo, sin tocar ninguna API en vivo. Un Pod de Kubernetes, en cambio, nace en el momento exacto en que kube-apiserver lo recibe — no hay un "plan" separado que evaluar de antemano, así que el motor de políticas tiene que interceptar la solicitud misma, en vivo, dentro del clúster. Esa diferencia de arquitectura —archivo estático fuera vs. objeto en vivo dentro— es el hilo que atraviesa las ocho lecciones de este módulo, y vas a verlo con nombre explícito en la lección 3.
Analogía: el portero que revisa la lista antes de dejarte entrar
Imagina un edificio de oficinas con dos sistemas de seguridad. El primero es una cámara en el vestíbulo: graba todo lo que pasa, y si alguien entra sin autorización, hay una grabación que lo prueba — después del hecho, cuando ya está adentro. El segundo es un portero, parado en la única puerta del edificio, con una lista en la mano: revisa esa lista antes de que cualquier persona cruce el umbral, y si el nombre no está, esa persona nunca entra — no hay nada que grabar, porque el evento que la cámara habría capturado simplemente nunca ocurrió.
Un admission controller es ese portero, aplicado a kube-apiserver. No es la cámara que revisa después (eso, en el vocabulario que cloud-security-and-guardrails-guide ya usó en su Módulo 7, es "detectivo" — CloudTrail, los logs de auditoría de Kubernetes, que este módulo no construye). Es el portero que se para exactamente en el único punto de entrada al clúster —el mismo kube-apiserver que la lección 6 del Módulo 1 te mostró como "la única puerta de entrada"— y decide, objeto por objeto, antes de que etcd lo guarde, si tiene permitido existir. Vas a ver el punto exacto del ciclo de vida de un request donde este portero se para en la lección 2.
El mapa de este módulo: las 8 lecciones
MÓDULO 6 — SEGURIDAD DE RUNTIME: ADMISSION CONTROL Y ESCANEO DE IMAGEN
M6.1 Introducción (esta) la cita, la frontera, el portero
M6.2 Qué es un admission controller el punto exacto del ciclo de vida
M6.3 OPA Gatekeeper: ConstraintTemplate/Constraint Rego dentro de un CRD de K8s
M6.4 Manos a la obra: Gatekeeper + primera política EJECUTADO — v3.23.0, rechazo real
M6.5 Kyverno: la alternativa YAML-nativa Rego vs. YAML, sin ganador
M6.6 Manos a la obra: la misma política, en Kyverno EJECUTADO — v1.18.2, rechazo real
M6.7 Manos a la obra: trivy image EJECUTADO — hallazgos reales
M6.8 Proyecto: los guardrails de runtime EJECUTADO — ambos motores + trivy
| # | Lección | Qué construye |
|---|---|---|
| 1 | Introducción (esta) | La cita textual completa, la frontera exacta, el portero como analogía central |
| 2 | Qué es un admission controller | Autenticación → autorización → admission → etcd; preventivo, no detectivo |
| 3 | OPA Gatekeeper: ConstraintTemplate/Constraint | Rego dentro de un CRD; contraste explícito con conftest (fuera del clúster) |
| 4 | Manos a la obra: instalando Gatekeeper | Ejecutado: v3.23.0, política de límites de recursos, Pod rechazado y Pod admitido |
| 5 | Kyverno: la alternativa YAML-nativa | Rego vs. YAML declarativo; cuándo un equipo elige cada uno, sin declarar ganador |
| 6 | Manos a la obra: la misma política, en Kyverno | Ejecutado: v1.18.2, misma prueba, comparación lado a lado |
| 7 | Manos a la obra: trivy image | Ejecutado: hallazgos reales de andes-cargo-status-api:latest, por severidad |
| 8 | Proyecto: los guardrails de runtime de Andes Cargo | Ejecutado: ambos motores activos a la vez + trivy image como gate antes de cargar una imagen |
Al cerrar este módulo, andes-cargo-cluster va a tener, por primera vez desde el Módulo 1, un portero real parado en kube-apiserver — y vas a saber, con evidencia literal, qué mensaje exacto muestra cuando rechaza algo.
Errores comunes
Pensar que este módulo repite el Módulo 4 de cloud-security-and-guardrails-guide con otro nombre (de solapamiento aparente). Qué pasa: alguien, al ver "políticas" y "Rego" mencionados en ambas guías, asume que este módulo es una copia del módulo de conftest. Cómo detectarlo: si tu resumen mental es "ya vi esto, es lo mismo con otro logo". Cómo corregirlo: el lenguaje (Rego) puede coincidir en Gatekeeper, pero el momento y el objeto que evalúa son completamente distintos — conftest lee un archivo JSON estático, generado por terraform plan, en una máquina que no tiene ninguna conexión con AWS en el instante de la evaluación. Gatekeeper corre dentro del clúster, como un Deployment real, y responde a cada solicitud HTTP que kube-apiserver le reenvía, en el instante exacto en que ocurre. La lección 3 de este módulo dedica una sección completa a esta distinción.
Asumir que "Andes Cargo no tiene contenedores" sigue siendo cierto (de continuidad desactualizada). Qué pasa: alguien lee la cita de cloud-security-and-guardrails-guide en esta lección y concluye que el ecosistema completo de Andes Cargo sigue sin Docker. Cómo detectarlo: si tu modelo mental de Andes Cargo, después de leer esta lección, sigue siendo "cuatro servicios serverless, un .zip de Lambda, nada de contenedores". Cómo corregirlo: esa premisa era cierta cuando cloud-security-and-guardrails-guide se escribió; dejó de serlo en el Módulo 1 de esta guía, cuando cargaste andes-cargo-status-api:latest en andes-cargo-cluster por primera vez. El Módulo 8 de esta guía (lección 6) documenta esa corrección de continuidad de forma explícita, para que ningún alumno del ecosistema se quede con la foto vieja.
Esperar que este módulo firme imágenes con cosign, porque cloud-security-and-guardrails-guide lo hizo con el .zip de Lambda (de expectativa de paridad). Qué pasa: alguien, viendo que la guía hermana firmó su artefacto de despliegue, espera que este módulo firme andes-cargo-status-api:latest de la misma forma. Cómo detectarlo: si buscas un paso de cosign sign/cosign verify en las lecciones 4, 6 o 8. Cómo corregirlo: firmar imágenes OCI es, conceptualmente, la misma idea aplicada a un artefacto distinto — pero está fuera del alcance declarado de este módulo, que se concentra en admission control y escaneo de vulnerabilidades. Esta lección lo nombra en la tabla de arriba, explícitamente, como el paso natural que no se construye aquí — no por descuido, sino porque el alcance de este módulo ya lo dice la cita: "admission controllers en clúster... escaneo de imágenes Docker", no "firma de imágenes".
Ejercicios
Ejercicio 1 — Reescribe la cita de memoria, sin copiarla. Sin volver a mirar la sección "La cita textual completa" de esta lección, escribe en tus propias palabras las tres cosas exactas que cloud-security-and-guardrails-guide delega hacia esta guía.
Ver solución
Las tres cosas son: (1) admission controllers corriendo dentro del clúster —nombrados explícitamente como OPA Gatekeeper y Kyverno—; (2) escaneo de imágenes Docker —distinto del escaneo de HCL/Terraform que esa guía sí hizo—; y (3) NetworkPolicy —que, en el orden real en que leíste el ecosistema, ya construiste en el Módulo 4 de esta misma guía antes de llegar aquí. Si tu respuesta nombró las tres sin necesitar releer la cita, tienes clara la frontera exacta que gobierna este módulo.
Ejercicio 2 — Explica por qué "Andes Cargo no tiene contenedores" dejó de ser cierto, con una fecha exacta. En una frase, indica el punto exacto —el módulo y la lección— en el que esa premisa se volvió falsa, y por qué.
Ver solución
Se volvió falsa en el Módulo 1, lección 7 de esta guía (kubernetes-and-eks-in-production-guide), el momento en que andes-cargo-status-api:latest se cargó por primera vez en andes-cargo-cluster con kind load docker-image — desde ese instante, Andes Cargo tiene, de verdad, un servicio corriendo como contenedor dentro de un clúster real, no solo un handler Lambda empaquetado en .zip.
Ejercicio 3 — Predice la diferencia entre conftest y Gatekeeper antes de leer la lección 3. Basándote únicamente en la tabla de esta lección, predice: si le muestras el mismo Pod YAML tanto a conftest (con una regla Rego copiada) como a Gatekeeper, ¿cuál de los dos puede rechazarlo antes de que ese Pod exista de verdad en un clúster, y cuál no?
Ver solución
Ninguno de los dos "gana" en ese sentido — los dos son preventivos, cada uno en su propio contexto. conftest puede evaluar ese YAML como archivo estático, en cualquier máquina, sin ningún clúster corriendo — perfecto para un paso de CI antes de que nadie intente aplicar nada. Gatekeeper, en cambio, necesita un clúster real corriendo, con el webhook instalado, para interceptar la solicitud en el momento exacto de kubectl apply — no puede evaluar un archivo sin que alguien lo aplique de verdad contra kube-apiserver. La diferencia no es "quién es más preventivo": es "en qué instante del ciclo de vida de la infraestructura actúa cada uno" — conftest, antes de que exista intención de aplicar nada; Gatekeeper, en el instante exacto en que alguien lo intenta.
Resumen y siguiente paso
Esta lección conectó este módulo, con cita textual completa, con la frontera que cloud-security-and-guardrails-guide dejó explícita en su propio diseño: admission controllers en clúster (OPA Gatekeeper, Kyverno) y escaneo de imágenes Docker, delegados hacia aquí porque esa guía trabaja sobre un .zip de Lambda, no sobre una imagen de contenedor. Viste la tabla completa de qué construye cada guía sobre el mismo problema general —"¿es esto seguro antes de que corra?"— en capas distintas, y la analogía central del módulo: el portero que revisa la lista antes de dejarte entrar, no la cámara que graba después.
Antes de avanzar deberías poder: citar de memoria las tres cosas que la frontera delega; explicar por qué "Andes Cargo no tiene contenedores" dejó de ser cierta, con el módulo y la lección exactos; y distinguir, en una frase, la diferencia de arquitectura entre conftest (archivo estático, fuera del clúster) y un admission controller (objeto en vivo, dentro del clúster).
Siguiente lección: qué es un admission controller, y por qué corre antes de que el objeto exista. Ahí vas a ver el punto exacto del ciclo de vida de un request —autenticación, autorización, admission, etcd— y por qué esto es, con el mismo vocabulario que cloud-security-and-guardrails-guide ya usó en su Módulo 7, estrictamente preventivo.
Recursos
cloud-security-and-guardrails-guide(NIEVA),DISENO.md, sección "NO entra en" — la fuente textual completa de la cita de esta lección.cloud-security-and-guardrails-guide(NIEVA), Módulo 7, lección 1 — la distinción preventivo/detectivo que este módulo retoma en la lección 2.kubernetes-and-eks-in-production-guide(NIEVA), Módulo 1, lección 6 —kube-apiservercomo la única puerta de entrada al clúster, la base técnica de todo este módulo.- Kubernetes — Admission Controllers Reference — documentación oficial del mecanismo que este módulo construye con dos motores reales.
- Open Policy Agent Gatekeeper — el primero de los dos motores, instalado de verdad en la lección 4.
- Kyverno — el segundo motor, instalado de verdad en la lección 6.
- Trivy — Container Image — el escáner de imagen, ejecutado de verdad en la lección 7.