Módulo 1: Threat Modeling Andes Cargo
2. Verde no es sinónimo de seguro
Descripción
Esta lección hace una sola cosa, con evidencia concreta en vez de una afirmación abstracta: separa, línea por línea, lo que un plan limpio, un apply exitoso y un pipeline en verde confirman de verdad, de lo que un lector apurado asume que confirman. Vas a usar el propio ci.yml de Andes Cargo —el mismo que ya corriste en cicd-and-gitops-on-aws-guide— como la prueba, no un ejemplo inventado.
Conexión con el módulo
La lección 1 te dio el mapa. Esta lección instala la razón de fondo por la que ese mapa existe: si "verde" ya significara "seguro", esta guía entera sería innecesaria. La lección 3 te da el framework (STRIDE) para preguntar, con estructura, lo que un pipeline verde nunca preguntó. Las lecciones 4 y 5 aplican ese framework al proyecto real.
Analogía: la inspección que aprueba el auto, no el viaje
Un auto que arranca a la primera, mantiene la velocidad en la autopista y no prende ninguna luz en el tablero pasó una cierta clase de verificación: el motor funciona, la transmisión responde, la batería tiene carga. Ninguna de esas señales te dice si los cinturones de seguridad están instalados, si los frenos tienen pastillas con vida útil, o si los neumáticos tienen la presión correcta para manejar bajo lluvia. Podrías manejar ese auto cien kilómetros sin ningún problema —y descubrir el fallo exactamente en el momento en que más importaba que no fallara. "Arranca y anda bien" y "es seguro manejarlo bajo cualquier condición" son dos preguntas distintas, evaluadas por dos verificaciones distintas. Un plan/apply/pipeline en verde es la primera pregunta. Esta guía entera es la segunda.
Qué confirma, de verdad, un plan limpio
Cuando corriste terraform plan sobre andes-cargo-infra/ en terraform-and-iac-guide, y viste algo como:
Plan: 12 to add, 0 to change, 0 to destroy.
eso confirma, con certeza total, tres cosas: el HCL es sintácticamente válido; Terraform pudo resolver el grafo de dependencias entre los doce recursos sin ningún ciclo ni referencia rota; y el provider de AWS aceptó calcular qué llamadas haría, dado el estado actual y la configuración deseada. Eso es todo lo que un plan promete. No promete que el AssumeRolePolicyDocument de AppServerRole esté correctamente acotado, que el bucket bloquee acceso público, o que ningún secreto esté escrito en texto plano en alguno de los .tf que ese plan acaba de leer. Terraform evalúa coherencia interna —¿esto que escribiste es una configuración válida y aplicable?—, nunca postura de seguridad —¿esto que escribiste debería existir así?—.
Qué confirma, de verdad, un apply exitoso
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
confirma que cada llamada a la API de AWS (o LocalStack) que el plan propuso tuvo éxito, en el orden correcto que el grafo de dependencias exigía. No confirma que esas llamadas hayan sido las correctas desde el punto de vista de seguridad. AWS acepta, sin ninguna objeción, crear un rol IAM con "Action": "s3:*" sobre "Resource": "*" con exactamente el mismo Apply complete! que crear un rol acotado a dos verbos sobre un solo bucket. La API de AWS no tiene ninguna opinión sobre si el permiso que le pediste crear es razonable —tiene una opinión sobre si el JSON es válido y si quien lo pide tiene autorización para pedirlo—. Esas son preguntas distintas, y solo la segunda es la que un apply responde.
Qué confirma, de verdad, un pipeline en verde
Esto ya lo viste, literal, en cicd-and-gitops-on-aws-guide, Módulo 4, lección 7 —el mismo ci.yml de Andes Cargo, corrido con act:
[ci/terraform-checks] ✅ Success - Main Terraform format check [125.128ms]
[ci/terraform-checks] ✅ Success - Main Terraform init [15.666698709s]
[ci/terraform-checks] ✅ Success - Main Terraform validate [1.754935459s]
[ci/terraform-checks] ✅ Success - Main Install awslocal [9.942404542s]
[ci/terraform-checks] ❌ Failure - Main Confirm the runner can reach LocalStack on the host [8.658047584s]
[ci/terraform-checks] ✅ Success - Main Install tflocal [2.438441625s]
[ci/terraform-checks] | Plan: 12 to add, 0 to change, 0 to destroy.
[ci/terraform-checks] ✅ Success - Main Terraform plan [4.307120666s]
[ci/terraform-checks] ✅ Success - Main Publish the plan to the job summary [66.274334ms]
[ci/terraform-checks] 🏁 Job succeeded
🏁 Job succeeded confirma que cada step del job terminó sin un código de salida distinto de cero (o que, en el caso del paso de conectividad, tenía continue-on-error: true explícitamente configurado para no bloquear el resto). No confirma nada sobre el contenido de lo que se ejecutó. Fíjate en algo importante para esta lección: ese Job succeeded es del ci.yml anterior a que cicd-and-gitops-on-aws-guide migrara las credenciales de valores escritos directamente a secrets.AWS_ACCESS_KEY_ID. El pipeline estaba en verde con la credencial expuesta en el YAML, y siguió en verde después de moverla a un Secret — porque ningún paso de ese job, en ninguna de las dos versiones, evaluó jamás dónde vivía esa credencial. Job succeeded mide que el proceso definido no falló. No mide si el proceso definido hizo las preguntas correctas.
El inventario honesto: lo que ya sabes que "verde" dejó pasar en Andes Cargo
Esta no es una lista hipotética. Es exactamente lo que las tres guías anteriores de este ecosistema construyeron, con pipeline en verde en cada paso, sin que ningún control lo haya señalado —porque ningún control de ese tipo existía todavía—:
| Lo que "verde" confirmó | Lo que "verde" nunca preguntó |
|---|---|
ci.yml corre fmt/validate/plan y termina en Job succeeded | ¿La credencial que usa ese job es de larga vida o federada? (Módulo 2 de esta guía) |
terraform apply crea AppServerRole sin ningún error | ¿AppServerRole tiene exactamente los permisos que el código de la app usa, o más? (Módulo 2) |
.secrets vive gitignoreado, git log no lo muestra en el historial | ¿Existe algún secreto real que, algún día, alguien tenga que rotar sin downtime? (Módulo 3) |
Plan: 12 to add — ningún recurso propuesto genera error de sintaxis | ¿Alguno de esos doce recursos, si se aplicara, dejaría el bucket público o el rol demasiado amplio? (Módulo 4) |
terraform validate confirma HCL sintácticamente correcto | ¿Ese mismo HCL tiene algún hallazgo de seguridad conocido por la comunidad (AVD-AWS-XXXX, CKV_AWS_XXX)? (Módulo 5) |
Apply complete! confirma que function.zip se desplegó | ¿Ese .zip es exactamente el que alguien revisó, o pudo modificarse entre la revisión y el despliegue? (Módulo 6) |
El apply termina sin ningún error de permisos | Si alguien cambiara una política de IAM mañana a mano, ¿quedaría algún registro de quién lo hizo? (Módulo 7) |
Siete preguntas, ninguna contestada por "verde", cada una con el módulo exacto de esta guía que la contesta. Esta tabla, con nombres más precisos y evidencia real del inventario, es la que vas a reconstruir en la lección 5 de este módulo con el framework STRIDE, y la que se convierte en documento formal en las lecciones 7 y 8.
El movimiento de mercado de 2026: seguridad como capacidad que se consume, no compuerta que se cruza
La investigación de mercado que sostiene el diseño de esta guía (src/paths/aws-cloud-ecosystem/STRATEGY.md) documenta un cambio concreto en cómo los equipos de plataforma maduros piensan la seguridad:
"La versión madura es 'build in': la seguridad es una capacidad de plataforma que los desarrolladores consumen automáticamente, no una checklist que deben satisfacer ni una compuerta que deben pasar."
La distinción importa, y vale la pena leerla con cuidado. Un modelo de "compuerta" —un checklist manual que alguien revisa antes de aprobar un merge, una lista de verificación de seguridad en un documento aparte— depende de que un humano se acuerde de aplicarlo, tenga tiempo de aplicarlo con atención, y no lo salte bajo presión de entrega. Es exactamente el mismo punto débil que ya viste en la lección 5 del Módulo 8 de terraform-and-iac-guide: el humano que aprobó el destroy de Claude Code sin leer el plan completo no falló por malicia, falló porque la disciplina dependía enteramente de su atención en ese momento exacto.
"Build in" es distinto: la seguridad deja de ser algo que alguien revisa después, y pasa a ser algo que el propio sistema exige antes, sin que nadie tenga que acordarse de pedirlo. Un conftest test que corre automáticamente en cada pull_request y bloquea el merge si una política falla no depende de que alguien se acuerde de revisar manualmente el plan en busca de un Shipments marcado para destrucción —lo bloquea, siempre, sin excepción, porque es parte del pipeline mismo, no una recomendación en un documento aparte. Esta es, literalmente, la arquitectura completa de esta guía: cada módulo de M2 a M7 construye una capacidad que M8 conecta al pipeline como algo que un cambio malo no puede evitar, no como algo que alguien debería recordar revisar.
Por qué esto no es solo vocabulario. Es tentador leer "build in" como una forma más elegante de decir "automatiza tus checklists". La diferencia real es de diseño: un checklist automatizado que sigue siendo opcional —un script que alguien puede correr o no correr— sigue dependiendo de la disciplina humana, solo que ahora la disciplina humana es "acordarse de correr el script" en vez de "acordarse de revisar la lista". Un guardrail "build in" de verdad está encadenado al camino que un cambio tiene que atravesar para llegar a producción —el needs: entre jobs que vas a construir en el M8— de forma que evitarlo requeriría, activamente, quitar el guardrail del pipeline, no simplemente no ejecutarlo una vez.
Errores comunes
Concluir que "verde no es sinónimo de seguro" significa "no confíes en tu pipeline" (de alcance). Qué pasa: alguien lee esta lección y empieza a dudar de cada Job succeeded como si escondiera, necesariamente, algo malo. Cómo detectarlo: si tu reacción a un pipeline en verde pasa de "confío" a "sospecho de todo, sin evidencia específica". Cómo corregirlo: un pipeline en verde sigue siendo información real y valiosa —confirma, con certeza, todo lo que efectivamente evalúa—. El punto de esta lección no es desconfiar del verde, es tener claro exactamente qué preguntas ese verde contestó y cuáles no, para poder agregar las que faltan (el trabajo del resto de esta guía) en vez de vivir con una falsa sensación de cobertura completa.
Pensar que agregar más pasos al pipeline automáticamente lo vuelve "build in" (de definición). Qué pasa: alguien agrega un step de escaneo a ci.yml pero lo configura con continue-on-error: true —el mismo flag que, en el ci.yml heredado, existe a propósito para el chequeo de conectividad a LocalStack, no para un hallazgo de seguridad—. Cómo detectarlo: si un hallazgo crítico de Trivy o una política Rego que falla no impide que el job termine con Job succeeded. Cómo corregirlo: "build in" exige que el guardrail pueda, de verdad, bloquear el camino —sin esa capacidad de bloqueo real, sigue siendo una recomendación visible en los logs, no una compuerta que un cambio malo no puede cruzar. El Módulo 8 de esta guía es explícito sobre cuáles de los tres jobs nuevos deben poder fallar el job completo, y por qué.
Buscar, en esta lección, algún fallo real de Andes Cargo que ya haya causado un incidente (de expectativa). Qué pasa: alguien espera que esta lección revele que alguna de las tres guías anteriores "hizo algo mal" en el sentido de un error de ejecución. Cómo detectarlo: si buscas un Error o un Failure real en el inventario de la sección anterior. Cómo corregirlo: las tres guías anteriores hicieron exactamente lo que se propusieron enseñar, correctamente. El punto de esta lección no es que hayan fallado —es que, a propósito, todavía no cubrieron una capa distinta del problema, la que esta guía existe para agregar. "Incompleto por diseño, hasta ahora" no es lo mismo que "roto".
Ejercicios
Ejercicio 1 — Encuentra una octava pregunta. La tabla de esta lección tiene siete filas, una por módulo de M2 a M8 (sin contar M1). Basándote en lo que ya sabes de Andes Cargo, propón una octava pregunta de seguridad real que "verde" tampoco contestó, y que no aparezca en la tabla.
Ver solución
No hay una única respuesta correcta, pero un ejemplo sólido: "¿Cuánto tiempo tarda alguien en detectar que una credencial de .secrets se filtró, si eso pasara?" — ninguna de las tres guías anteriores construyó ningún mecanismo de detección de secretos filtrados; verde en ci.yml nunca preguntó eso porque nunca corrió ningún escáner sobre el propio repositorio. Esa pregunta específica, de hecho, la contesta el Módulo 3 de esta guía (trivy fs --scanners secret, ya nombrado en el diseño del M3.7). Cualquier pregunta razonable sobre una capa de seguridad que ninguna guía anterior evaluó cuenta como una respuesta válida a este ejercicio.
Ejercicio 2 — Explica la diferencia entre "compuerta" y "build in" con un ejemplo propio, distinto de conftest. Sin usar el ejemplo de conftest test/needs: de esta lección, propone otro ejemplo —de cualquier dominio, no necesariamente de software— donde la diferencia entre "una verificación que alguien debe recordar aplicar" y "una verificación que el sistema exige automáticamente" sea clara.
Ver solución
Un ejemplo típico: un cinturón de seguridad que el conductor debería ponerse (compuerta que depende de la memoria y la disciplina de la persona) frente a un auto que no arranca hasta que el sensor del cinturón detecta que está abrochado (build in — la seguridad está integrada en el mecanismo mismo, no en la buena voluntad de quien conduce). La analogía completa: el checklist de seguridad de un documento aparte que nadie revisa bajo presión de entrega es el cinturón "debería"; el job de CI que bloquea un merge automáticamente es el auto que no arranca. Cualquier ejemplo que capture correctamente esa distinción —dependencia de la memoria humana frente a un mecanismo que actúa solo— es una respuesta válida.
Ejercicio 3 — Predice qué de la tabla de esta lección se resuelve primero, y por qué. Sin mirar el orden de los módulos en la lección 1, ¿cuál de las siete filas de la tabla esperarías que esta guía resuelva primero, basándote únicamente en cuál parece más urgente o más simple de resolver? Compara tu predicción con el orden real.
Ver solución
No hay una respuesta "incorrecta" en la predicción en sí —el ejercicio es sobre el razonamiento—, pero el orden real de la guía resuelve primero la identidad federada y el mínimo privilegio (Módulo 2), antes que secretos, políticas o escaneo. La razón de diseño: la identidad es la capa sobre la que todas las demás dependen —una credencial de larga vida comprometida, o un rol demasiado amplio, amplifica el impacto de cualquier otro problema que aparezca después (un secreto filtrado importa menos si la identidad que lo usa ya está acotada a lo mínimo necesario)—. Si tu predicción coincidió con "identidad primero", identificaste correctamente el principio de diseño; si no coincidió, vale la pena notar la diferencia entre "lo que parece más grave en aislamiento" y "lo que reduce más el impacto de todo lo demás si se resuelve primero".
Resumen y siguiente paso
En esta lección separaste, con evidencia real del propio ci.yml de Andes Cargo, lo que un plan limpio, un apply exitoso y un pipeline en verde confirman —coherencia sintáctica, éxito de cada llamada, ausencia de errores en los pasos definidos— de lo que nunca preguntaron: postura de seguridad. Viste el inventario honesto de siete preguntas sin contestar que las tres guías anteriores dejaron abiertas, cada una apuntando al módulo de esta guía que la resuelve. Y viste la cita completa de STRATEGY.md sobre el movimiento de mercado de 2026: seguridad "build in", una capacidad que el desarrollador consume automáticamente, no una compuerta que debe recordar cruzar.
Antes de avanzar deberías poder: explicar, con el ci.yml de Andes Cargo como ejemplo, qué confirma y qué no confirma cada uno de plan/apply/pipeline en verde; y explicar la diferencia real —no solo de vocabulario— entre un guardrail de "compuerta" y uno "build in".
La lección 3 te da la estructura formal para convertir "verde no es sinónimo de seguro" en una pregunta sistemática: STRIDE, las seis formas en que algo puede fallar, cada una con su nombre.
Recursos
cicd-and-gitops-on-aws-guide, Módulo 4, lección 7 (07-hands-on-dummy-credentials-for-localstack.md) — la salida literal deci.ymlcitada en esta lección, antes y después de migrar las credenciales.- AWS Well-Architected Framework — Security Pillar — la fuente oficial de AWS sobre por qué la seguridad se diseña como capa continua, no como verificación puntual.
src/paths/aws-cloud-ecosystem/STRATEGY.md— la fuente completa de la cita "build in" de esta lección, y del hallazgo de mercado sobre el trabajo de plataforma desplazándose de "escribir IaC" a "entregar guardrails".src/paths/aws-cloud-ecosystem/VALIDACION.md— la auditoría que confirma, con evidencia de foros y ofertas de empleo, que IAM y radio de explosión son el vocabulario de seguridad que el mercado ya espera en 2026.