Módulo 8: Capstone The Andes Cargo Security Gate
8. Proyecto final: el security gate de Andes Cargo como entregable
Descripción
Este es el cierre de toda la guía, no solo de este módulo. Las lecciones 1 a 7 construyeron y probaron el gate, pieza por pieza; este proyecto lo integra en lo que de verdad es desde el momento en que un equipo real lo adopta: un repositorio completo, defendible línea por línea frente a un entrevistador técnico, con evidencia ejecutada —no una promesa— de que cada control funciona.
Conexión con el módulo
Cada proyecto de esta guía, desde THREAT-MODEL.md en el Módulo 1, terminó con la misma pregunta: "¿puedes demostrar, con evidencia ejecutada, que esto funciona, no solo que existe?". Este proyecto es esa pregunta aplicada al repositorio completo. RISK-MAP.md cierra aquí, formalmente, sus siete filas — las seis que ya estaban Resolved al cierre del Módulo 7, más la confirmación de que el gate de este módulo capstone verifica, en un pipeline real, que esas seis resoluciones siguen sosteniéndose.
Paso 1 — El repositorio completo, en un vistazo
find andes-cargo-infra -type f -not -path "*/.git/*" -not -path "*/.terraform/*" | sort
Qué esperar (literal — la lista completa de archivos que esta guía, de punta a punta, dejó en andes-cargo-infra/):
.actrc
.github/act-events/pr-event.json
.github/workflows/apply.yml
.github/workflows/ci.yml
.github/workflows/drift.yml
.gitignore
.trivyignore
GUARDRAILS-MAP.md
RISK-MAP.md
THREAT-MODEL.md
cosign.pub
dynamodb.tf
iam.tf
lambda.tf
lambda/function.zip
lambda/handler.py
lambda/requirements.txt
manifest.sig
modules/iam-role/main.tf
modules/oidc-provider/main.tf
modules/s3-bucket/main.tf
oidc.tf
policy/least-privilege-iam.rego
policy/no-destroy-shipments.rego
policy/no-public-buckets.rego
providers.tf
s3.tf
sbom.cyclonedx.json
secrets.tf
versions.tf
cosign.key no aparece en esta lista, a propósito — gitignorado desde el Módulo 6, lección 5, nunca versionado. Todo lo demás sí: tres documentos de portfolio (THREAT-MODEL.md, RISK-MAP.md, GUARDRAILS-MAP.md), tres artefactos de cadena de suministro (sbom.cyclonedx.json, cosign.pub, manifest.sig), tres políticas Rego, tres módulos Terraform reutilizables, y tres workflows —ci.yml, apply.yml, drift.yml— de los cuales dos (ci.yml, apply.yml) llevan los controles de seguridad de esta guía completa.
Paso 2 — El gate completo, una última vez, como confirmación final
Antes de declarar este proyecto terminado, corre el gate completo una vez más, sobre el estado final del repositorio — la misma disciplina de verificación final que cada proyecto de esta guía ya exigió:
terraform plan -out=tfplan -input=false
terraform show -json tfplan > tfplan.json
conftest test tfplan.json -p policy/
Qué esperar (literal):
4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions
trivy config --exit-code 1 --severity CRITICAL,HIGH .
echo "trivy exit=$?"
cosign verify-blob --key cosign.pub --bundle manifest.sig --insecure-ignore-tlog=true lambda/function.zip
Qué esperar (literal):
Report Summary
┌───────────────────────────┬───────────┬───────────────────┐
│ Target │ Type │ Misconfigurations │
├───────────────────────────┼───────────┼───────────────────┤
│ . │ terraform │ 0 │
├───────────────────────────┼───────────┼───────────────────┤
│ dynamodb.tf │ terraform │ 0 │
├───────────────────────────┼───────────┼───────────────────┤
│ lambda.tf │ terraform │ 0 │
├───────────────────────────┼───────────┼───────────────────┤
│ modules/s3-bucket/main.tf │ terraform │ 0 │
├───────────────────────────┼───────────┼───────────────────┤
│ secrets.tf │ terraform │ 0 │
└───────────────────────────┴───────────┴───────────────────┘
trivy exit=0
WARNING: Skipping tlog verification is an insecure practice that lacks transparency and auditability verification for the blob.
Verified OK
Los tres resultados de siempre — porque nada cambió desde la lección 4. Este es, precisamente, el punto de correrlo una última vez aquí: un proyecto de portfolio no se declara terminado porque en algún momento pasó — se declara terminado porque sigue pasando, corrido de nuevo, en el momento exacto de entregarlo.
RISK-MAP.md: las siete filas, cerradas
| Order | ID | Control | Status |
|---|---|---|---|
| 1 | TM-01 | OIDC federation + scoped trust policy | Resolved (M2) |
| 2 | TM-07 | Least-privilege role tightening | Resolved (M2.7) |
| 3 | TM-05 | SSM Parameter Store / Secrets Manager | Resolved (M3) |
| 4 | TM-04 | no-public-buckets.rego | Resolved (M4.7) |
| 5 | TM-06 | no-destroy-shipments.rego | Resolved (M4.6) |
| 6 | TM-02 | SBOM + cosign sign-blob/verify-blob | Resolved (M6.6, verificado en pipeline en M6.8) |
| 7 | TM-03 | CloudTrail | Resolved (M7.5) |
Siete de siete. El gate de este módulo (lecciones 3 a 5) no agrega una octava fila —ya lo estableció la lección 6— pero es, en sí mismo, la prueba de que las filas 4, 5 y 6 (las tres que dependen directamente de conftest/cosign) siguen sosteniéndose bajo la presión de un pipeline real, no solo de un comando aislado en una terminal.
Cómo defender este trabajo en una entrevista
Un entrevistador técnico que revise este repositorio completo no necesita que recites Rego, YAML, o el algoritmo ECDSA de memoria. Necesita que puedas responder, sin dudar, cuatro tipos de pregunta — una por cada capa que este proyecto integra:
1. "¿Por qué estos tres controles específicos, en este orden?" — la respuesta vive en el Módulo 8 completo: policy-check primero porque es el más barato (milisegundos, sin ninguna dependencia externa); iac-scan segundo porque evalúa configuración con reglas de la comunidad, más caro pero todavía sin ninguna herramienta externa que instalar; verify-artifact último porque depende de una instalación externa (cosign) y de artefactos committeados, no del plan en sí. El orden no es alfabético — es de costo creciente, y la lección 5 lo demostró con un fallo real que nunca gastó el tiempo de los otros dos.
2. "¿Cómo sabes que el gate realmente bloquea lo que dice bloquear, no solo lo describe?" — la respuesta es la lección 5 completa: un intento real de ensanchar AppServerRole a "Action": "*", corrido con act pull_request, terminó en 🏁 Job failed en policy-check, con grep -c "iac-scan\|verify-artifact" devolviendo 0 sobre el log completo — no una promesa de que "debería bloquear algo así", sino la evidencia de que bloqueó, específicamente, esto.
3. "¿Qué de este proyecto es real, y qué es representativo?" — la respuesta es la lección 6 de este módulo, con cuatro límites, cada uno con su causa técnica exacta (IAM Policy Enforcement de LocalStack Base/Ultimate, cobertura no confirmada de GuardDuty/Config, y la decisión de alcance de una sola cuenta). Ningún entrevistador serio espera que un laboratorio $0 reproduzca cada centímetro de un entorno de producción — sí espera que sepas, con precisión, dónde está exactamente la línea.
4. "Si Andes Cargo creciera, ¿qué le faltaría a este proyecto?" — la respuesta es la lección 7: cuatro guías hermanas, cada una con una frontera exacta, una de ellas (finops-and-cost-guardrails-guide) ya construida sobre el ci.yml exacto de este módulo. Saber señalar, con precisión, qué está fuera del alcance deliberado de este trabajo —y por qué— es tan valioso en una entrevista como saber explicar lo que sí construiste.
Errores comunes
Presentar este proyecto como "un pipeline de CI/CD" en vez de "un security gate específico dentro de un pipeline heredado". Qué pasa: alguien, resumiendo este trabajo para un entrevistador, dice "construí un pipeline de GitHub Actions con Terraform" —una descripción que no distingue este trabajo del contenido de cicd-and-gitops-on-aws-guide, la guía que construyó el pipeline original—. Cómo detectarlo: si tu resumen de una frase no menciona conftest, Trivy, ni cosign en absoluto. Cómo corregirlo: el valor específico de este proyecto es el gate de seguridad —tres controles nombrados, encadenados, con evidencia de que detienen lo que deben detener— agregado a un pipeline que ya existía. Un entrevistador que conozca el ecosistema de guías de este repositorio va a notar de inmediato si tu descripción confunde "construí el pipeline" con "endurecí un pipeline ya construido".
Mostrar solo el caso donde el gate pasa, sin el caso donde falla, como evidencia de portfolio. Qué pasa: alguien, preparando este proyecto para una entrevista, incluye solo la salida de la lección 4 (todo en verde), sin la de la lección 5 (el fallo real, detenido en policy-check). Cómo detectarlo: si tu carpeta de evidencia solo tiene capturas de 🏁 Job succeeded, nunca de 🏁 Job failed. Cómo corregirlo: la pregunta 2 de la sección de entrevista de esta lección ya lo explica — un gate que solo demuestra que deja pasar cambios buenos no demuestra que bloquea cambios malos. La evidencia completa, la que de verdad convence a un entrevistador técnico, incluye ambos casos, con el mismo nivel de detalle.
Olvidar mencionar RISK-MAP.md al hablar de este proyecto, tratándolo como un documento aparte sin conexión con el gate técnico. Qué pasa: alguien describe el gate de seguridad y, por separado, el documento de gestión de riesgos, sin conectar los dos. Cómo detectarlo: si tu explicación del gate nunca menciona qué fila de RISK-MAP.md cada control cierra. Cómo corregirlo: la tabla de esta lección ya lo muestra — cada control técnico de este proyecto existe porque un riesgo documentado, con evidencia, lo necesitaba, no porque "sería una buena práctica tenerlo". Esa trazabilidad —de un hallazgo de STRIDE en el Módulo 1 hasta un job real de CI en el Módulo 8— es, en sí misma, una de las piezas más fuertes de este portfolio: demuestra un proceso de seguridad completo, no una colección de herramientas sueltas.
Ejercicios
Ejercicio 1 — Reconstruye, de memoria y sin mirar ninguna lección anterior, el ci.yml completo de este módulo: los tres jobs, sus needs:, y el comando central de cada uno. Escribe, en un archivo nuevo, la estructura completa —nombres de job, dependencias, comando principal de cada uno— sin consultar la lección 3.
Ver solución
policy-check (sin needs:): terraform init → terraform plan -out=tfplan → terraform show -json tfplan > tfplan.json → conftest test tfplan.json -p policy/. iac-scan (needs: policy-check): trivy config --exit-code 1 --severity CRITICAL,HIGH .. verify-artifact (needs: iac-scan): cosign verify-blob --key cosign.pub --bundle manifest.sig --insecure-ignore-tlog=true lambda/function.zip. Si tu reconstrucción coincide con esto en la secuencia y el propósito de cada job, aunque no en cada detalle sintáctico exacto, entiendes el gate lo suficiente como para explicarlo sin notas en una entrevista real — que es, precisamente, el estándar que este ejercicio busca confirmar.
Ejercicio 2 — Elige una de las cuatro preguntas de entrevista de esta lección y practica responderla en voz alta, cronometrada a menos de noventa segundos. Sin leer la respuesta escrita de esta lección, responde una de las cuatro preguntas como si estuvieras frente a un entrevistador real, y cronométrate.
Ver solución
No hay una única respuesta correcta que verificar aquí —el ejercicio es de práctica, no de corrección—, pero una respuesta fuerte, para cualquiera de las cuatro, comparte una estructura: nombra el mecanismo técnico exacto (el needs:, el mensaje de deny específico, la funcionalidad de pago de LocalStack), cita la evidencia real que lo respalda (un log, un código de salida, un conteo de grep), y evita la palabra "debería" — cada respuesta fuerte de esta guía, desde el Módulo 1, se apoya en "corrió, y esto fue lo que pasó", nunca en una promesa de comportamiento no verificado. Si tu respuesta de noventa segundos incluyó las tres piezas —mecanismo, evidencia, sin "debería"—, estás listo para esta pregunta en una entrevista real.
Ejercicio 3 — Escribe el README.md de una sola página que resumiría este repositorio completo para alguien que nunca vio esta guía. En no más de 200 palabras, escribe la introducción que le explicarías a un colega nuevo que se une al equipo de Andes Cargo, sin asumir que conoce ninguna de las ocho guías de este ecosistema.
Ver solución
Una versión razonable: "andes-cargo-infra/ declara la infraestructura de Andes Cargo (S3, DynamoDB, Lambda, IAM) en Terraform, desplegada a través de un pipeline de GitHub Actions. Todo cambio propuesto en un Pull Request atraviesa un security gate de tres controles, en orden: policy-check evalúa el plan contra tres políticas Rego (nunca destruir la tabla de envíos, ningún permiso IAM sin acotar, ningún bucket sin bloqueo de acceso público); iac-scan escanea la configuración con Trivy en busca de errores comunes de infraestructura; verify-artifact confirma, con una firma criptográfica, que el código que Lambda va a ejecutar es exactamente el que el equipo aprobó. Los tres jobs están encadenados: si el primero falla, los siguientes ni siquiera arrancan. THREAT-MODEL.md y RISK-MAP.md documentan por qué cada control existe, riesgo por riesgo. GUARDRAILS-MAP.md distingue qué de este sistema previene activamente un problema y qué solo deja evidencia de que ocurrió. Antes de tocar policy/ o cualquier workflow, léelos primero." El punto del ejercicio es practicar comunicar, en un espacio breve, el "por qué" completo de un sistema de seguridad a alguien que no tiene el contexto de ocho módulos — la misma habilidad que un entrevistador está evaluando cuando te pide que expliques tu portfolio.
El proyecto completo, en un vistazo final
andes-cargo-infra/
├── THREAT-MODEL.md (M1 — el modelo de amenazas que gobierna toda la guía)
├── RISK-MAP.md (M1 → 7/7 filas Resolved)
├── GUARDRAILS-MAP.md (M7 — preventivo/detectivo × implementado/representativo/nombrado)
├── secrets.tf (M3)
├── policy/ (M4 — 3 políticas Rego, 4 reglas deny)
├── modules/
│ ├── s3-bucket/
│ ├── iam-role/
│ └── oidc-provider/ (M2)
├── lambda/
│ ├── handler.py
│ ├── function.zip (890 bytes — EL artefacto que M6 firma y M8 verifica en pipeline)
│ └── requirements.txt
├── sbom.cyclonedx.json (M6)
├── cosign.pub (M6 — committeado)
├── cosign.key (M6 — gitignorado, NUNCA versionado)
├── manifest.sig (M6)
├── .trivyignore (M5 — supresiones documentadas)
└── .github/workflows/
├── ci.yml ← policy-check + iac-scan + verify-artifact (M8)
├── apply.yml ← verify-artifact + terraform-apply (M6.8, heredado sin cambios)
└── drift.yml (heredado de cicd-and-gitops-on-aws-guide, sin cambios)
Resumen y siguiente paso
Este proyecto final integró ocho módulos de trabajo —un modelo de amenazas, identidad federada, secretos gestionados, tres políticas de policy-as-code, dos escáneres de la comunidad, un SBOM y una firma criptográfica, y un mapa de guardrails preventivos/detectivos— en un solo repositorio, verificado una última vez de punta a punta: 4 tests, 4 passed, Misconfigurations: 0 en cinco archivos, Verified OK. RISK-MAP.md cierra sus siete filas. Preparaste, con evidencia concreta en cada respuesta, las cuatro preguntas que un entrevistador técnico haría frente a este trabajo.
Con esto, cloud-security-and-guardrails-guide queda completa: ocho módulos, el hueco de mercado que VALIDACION.md marcó como "cero" en toda la competencia —OIDC, SBOM, cosign/Sigstore, policy-as-code preventivo— cerrado con evidencia ejecutada en cada lección que lo permitió, y con honestidad exacta en las cuatro que no. Lo que Andes Cargo construyó aquí no es un ejercicio de práctica — es, literalmente, el mismo patrón que un equipo de infraestructura real usaría para dejar de confiar en la memoria de un revisor humano, y empezar a confiar en un sistema que revisa por él, en el orden correcto, cada vez.
Recursos
- Este curso, Módulo 1, lecciones 7 y 8 — el origen de
THREAT-MODEL.md/RISK-MAP.md, la fuente que gobierna cada control construido después. - Este curso, Módulo 7, lección 8 — el origen de
GUARDRAILS-MAP.md, la clasificación final de las ocho piezas de guardrail de esa capa. - Este curso, Módulo 8, lecciones 3, 4 y 5 — la evidencia ejecutada completa del gate que este proyecto verifica una última vez.
src/paths/aws-cloud-ecosystem/VALIDACION.md— la auditoría de mercado que fijó, desde el principio, por qué esta guía existe y qué hueco de competencia cierra.