Módulo 1: Threat Modeling Andes Cargo
8. Proyecto: el mapa de riesgos de Andes Cargo
Descripción
THREAT-MODEL.md (lección 7) contesta "¿qué puede salir mal?", organizado por categoría de STRIDE. Este proyecto final del módulo contesta la tercera pregunta del modelado de amenazas —"¿qué vamos a hacer al respecto?"— y la reorganiza por una dimensión distinta y más útil para lo que sigue: el orden real en que esta guía va a resolver cada riesgo, no el orden alfabético de un acrónimo. El resultado es RISK-MAP.md, un segundo documento en la raíz de andes-cargo-infra/, con formato de ADR (Architecture Decision Record) — la misma clase de documento que un equipo de plataforma real escribiría para justificar, con evidencia, por qué construye las cosas en el orden en que las construye.
Conexión con el módulo
Este es el cierre del módulo, y el documento que gobierna, literalmente, la secuencia de lecciones que vas a atravesar en M2 a M8. Cada fila de este mapa es una promesa verificable: cuando termines el módulo que esa fila nombra, vuelves a este documento y marcas la fila como resuelta —el mismo mecanismo de mantenimiento que THREAT-MODEL.md ya declaró en su sección 6—.
Paso 1 — Por qué un ADR, y no solo una tabla suelta
Un Architecture Decision Record documenta una decisión de diseño con su contexto y su justificación, no solo su resultado — la diferencia entre "hacemos esto" y "hacemos esto, en este orden, por esta razón, y esta es la alternativa que descartamos". RISK-MAP.md no es únicamente la tabla de siete filas: es la tabla más el razonamiento de por qué esta guía resuelve identidad antes que auditoría, y política preventiva antes que escaneo de comunidad. Ese razonamiento es exactamente lo que le permite a alguien —un entrevistador técnico, un compañero de equipo nuevo— entender no solo qué se hizo, sino si el orden en que se hizo tenía criterio detrás.
Paso 2 — El documento completo
En la raíz de andes-cargo-infra/, junto a THREAT-MODEL.md, crea RISK-MAP.md:
# RISK-MAP.md — Risk-to-Control Roadmap for `cloud-security-and-guardrails-guide`
**Status:** Accepted · **Date:** this module's close · **Supersedes:** none
**Governs:** Modules 2 through 8 of `cloud-security-and-guardrails-guide`
**Source:** `THREAT-MODEL.md`, section 4 (STRIDE findings, `TM-01` through `TM-07`)
## Context
`THREAT-MODEL.md` identified seven concrete risks in `andes-cargo-infra/`, organized by STRIDE
category. STRIDE order is useful for *finding* risks systematically — it is not, by itself, a
useful order for *resolving* them. This document reorders the same seven risks by the sequence in
which this guide actually builds their controls, and states the reasoning behind that sequence, so
that sequence reads as a deliberate decision, not an arbitrary module order.
## Decision
Resolve risks in this order: **identity first** (Module 2), because a scoped identity reduces the
blast radius of every other risk that depends on "what can this credential do" — including risks
this document does not yet know about. **Secrets second** (Module 3), because a properly scoped
identity is a prerequisite for secrets that are readable only by the identities that need them.
**Preventive policy-as-code third** (Module 4), because it is the single most direct answer to the
guide's own blast-radius case study (this module, lesson 6): a control that blocks a bad `plan`
before `apply`, independent of human attention at the moment of approval. **Community-rule scanning
fourth** (Module 5), deliberately without closing a new `TM-` row of its own — it complements
Module 4's self-authored rules with rules the team did not have to think of, and its role in this
map is coverage, not resolution of a named risk. **Supply chain fifth** (Module 6), because signing
an artifact only makes sense once the pipeline that produces it authenticates safely (Module 2) and
the policy gate that reviews its plan already exists (Module 4). **Detective guardrails sixth**
(Module 7), deliberately last among the modules that close a risk: this guide's design principle,
stated in Module 7's own introduction, is preventive before detective — a guardrail that stops a
bad change is worth more than one that only records it happened, so preventive controls (M2-M4, M6)
come first, and the guardrail that provides attribution after the fact (M7) closes the sequence
before the capstone. **Module 8 closes no new row** — it chains the executable controls (M4, M5,
M6) into a single gate inside the inherited pipeline.
## The map
| Order | ID | STRIDE | Risk | Control | Module | Status |
|--:|---|---|---|---|---|---|
| 1 | TM-01 | Spoofing | Long-lived static pipeline credentials | OIDC federation + scoped trust policy | M2 | Open |
| 2 | TM-07 | Elevation of privilege | `AppServerRole` broader than its actual usage | Least-privilege role tightening | M2.7 | Open |
| 3 | TM-05 | Information disclosure | Plaintext credentials on disk (`.secrets`) | SSM Parameter Store / Secrets Manager | M3 | Open |
| 4 | TM-04 | Information disclosure | S3 bucket with no public-access block | `no-public-buckets.rego` | M4 | Open |
| 5 | TM-06 | Denial of service | No control blocks a destructive `plan` on `Shipments` | `no-destroy-shipments.rego` | M4 | Open |
| 6 | TM-02 | Tampering | `function.zip` deployment artifact unsigned | SBOM + `cosign sign-blob`/`verify-blob` | M6 | Open |
| 7 | TM-03 | Repudiation | No CloudTrail trail, no attributable audit record | CloudTrail (as far as LocalStack Hobby allows) | M7 | Open |
## Consequences
Every row's `Status` column moves from `Open` to `Resolved` — with the closing module's lesson
number noted — as this guide's modules complete. Module 5, despite appearing in the guide's module
sequence between rows 5 and 6, deliberately owns no row of its own: its contribution is community
rule coverage over the whole project, not a named risk from `THREAT-MODEL.md`. Module 8 also owns
no new row: it is the capstone that chains M4 (`policy-check`), M5 (`iac-scan`), and M6
(`verify-artifact`) into one gate, proven with a change that passes and a change the gate stops.
## Alternatives considered
**Resolve in STRIDE order (S → T → R → I → D → E).** Rejected: STRIDE order groups TM-04 and TM-05
apart despite both mitigating in different modules (M4 and M3, respectively), and would resolve
Tampering (TM-02, needs M2's safe pipeline identity as a prerequisite) before Spoofing (TM-01,
which builds that same prerequisite). STRIDE is a finding taxonomy, not a build sequence.
**Resolve preventive and detective controls in parallel.** Considered, rejected for this guide's
teaching sequence specifically: building CloudTrail (M7) before the preventive controls it would
need to attribute (M2-M4, M6) exist would mean auditing a system that has not yet closed its most
concrete, evidence-backed risk (TM-06, this module's lesson 6). A production team with more
engineers might parallelize this; a single learner following one guide benefits from the sequence
that builds on itself without forward references to unbuilt controls.
Paso 3 — Verificando el documento
grep -c '^| [1-7]' RISK-MAP.md
grep -o 'TM-0[1-7]' RISK-MAP.md | sort -u | wc -l
Qué esperar (literal — el contenido lo escribiste tú, la forma es determinista):
7
7
Siete filas numeradas en la tabla, siete identificadores TM- distintos referenciados en todo el documento (contando la tabla y la sección de contexto) — ningún riesgo de THREAT-MODEL.md quedó fuera de este mapa, y ninguno aparece duplicado.
Cómo leer este documento, seis meses después
La prueba real de un ADR no es si tiene buena forma el día que se escribe — es si sigue siendo útil cuando nadie recuerda el contexto completo de memoria. Frente a este documento, un lector nuevo debería poder responder, sin preguntarle a nadie: ¿qué riesgo existe? (columna Risk, con su ID trazable a THREAT-MODEL.md); ¿qué lo resuelve? (columna Control, nombrando el mecanismo exacto, no una descripción vaga); ¿está resuelto ya? (columna Status, la única que cambia con el tiempo); y ¿por qué en este orden? (la sección Decision, con el razonamiento explícito, no solo el resultado). Si alguna de esas cuatro preguntas requiere releer una lección completa para contestarla, el documento no cumplió su función.
El cierre del Módulo 1
Con THREAT-MODEL.md y RISK-MAP.md escritos, este módulo entrega exactamente lo que prometió en la lección 1: no un candado construido —ninguno de los siete riesgos de esta tabla está resuelto todavía, y el Status de las siete filas lo dice con honestidad, Open—, sino el mapa completo y verificado de qué candado falta, con qué evidencia, en qué orden, y con qué criterio. Entras al Módulo 2 con una lista de tareas concretas, trazable hasta un comando real que corriste en la lección 4, en vez de una sensación general de "hay que mejorar la seguridad".
Errores comunes
Reordenar las filas de RISK-MAP.md por preferencia personal, sin actualizar la sección Decision (de coherencia del documento). Qué pasa: alguien, no de acuerdo con el orden M2→M3→M4→M6→M7, reordena la tabla pero deja la sección Decision explicando el orden original. Cómo detectarlo: si tu tabla y tu narrativa de "por qué este orden" cuentan historias distintas. Cómo corregirlo: en un ADR real, cambiar la decisión exige actualizar el razonamiento completo, no solo la tabla — si tienes una razón sólida para un orden distinto (por ejemplo, tu propio contexto de trabajo hace que secretos sea más urgente que identidad), la sección Alternatives considered es exactamente el lugar para documentar esa decisión distinta con su propia justificación, no un silencio entre tabla y narrativa.
Marcar una fila como Resolved antes de que el control esté realmente construido y verificado (de expectativa, ver también la lección 7). Qué pasa: alguien, al empezar el Módulo 2, actualiza el Status de TM-01 a Resolved apenas lee la introducción de ese módulo, antes de aplicar la identidad OIDC de verdad. Cómo detectarlo: si el Status de una fila cambia antes de haber corrido la verificación que el módulo correspondiente exige (por ejemplo, awslocal iam list-open-id-connect-providers confirmando el provider real en M2.4). Cómo corregirlo: el mismo principio de la lección 2 de este módulo aplica aquí — "en progreso" y "resuelto" son estados distintos, y la única evidencia válida de "resuelto" es la verificación real del módulo que cierra esa fila, no la intención de resolverlo.
Tratar RISK-MAP.md como redundante con THREAT-MODEL.md, y descartar uno de los dos (de alcance). Qué pasa: alguien, viendo que ambos documentos contienen los mismos siete identificadores, decide que uno de los dos sobra. Cómo detectarlo: si tu razón para eliminar uno es "dicen lo mismo". Cómo corregirlo: contestan preguntas distintas y complementarias — THREAT-MODEL.md responde "¿qué puede salir mal, y por qué?" (la vista del auditor de seguros de la lección 4, organizada para encontrar riesgos sistemáticamente); RISK-MAP.md responde "¿en qué orden lo resolvemos, y por qué ese orden?" (la vista del equipo de plataforma que tiene que priorizar trabajo real). Un entrevistador técnico revisando este portfolio esperaría encontrar los dos, cada uno cumpliendo su función.
Ejercicios
Ejercicio 1 — Actualiza RISK-MAP.md a mano, prediciendo el cierre del Módulo 2. Sin haber hecho todavía el Módulo 2 de esta guía, escribe cómo quedarían las filas 1 y 2 de la tabla (TM-01, TM-07) una vez que ese módulo termine, incluida la columna Status y una nota breve de qué verificación las respaldaría.
Ver solución
Una actualización razonable: fila 1 (TM-01) — Status: Resolved (M2.6), con nota "OIDC identity provider applied and verified via awslocal iam list-open-id-connect-providers; ci.yml no longer reads static AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY from .secrets". Fila 2 (TM-07) — Status: Resolved (M2.7), con nota "AppServerRole scoped to the exact S3 actions and prefix its code uses, verified via awslocal iam get-role-policy". El punto del ejercicio no es adivinar el HCL exacto del Módulo 2 —eso lo vas a construir en su momento—, sino practicar el hábito de que cada actualización de Status venga acompañada de qué comando o evidencia la respalda, nunca solo la palabra "Resolved" sin más.
Ejercicio 2 — Explica, con tus propias palabras, por qué el Módulo 5 no tiene fila propia en este mapa. Un compañero, revisando RISK-MAP.md, pregunta por qué un módulo entero de la guía (escaneo de IaC con Trivy y Checkov) no cierra ningún riesgo de THREAT-MODEL.md. ¿Es esto una laguna del diseño?
Ver solución
No es una laguna — es una distinción real de qué tipo de valor aporta cada módulo. Los siete riesgos de THREAT-MODEL.md son los que este equipo específico identificó, con su propio conocimiento del sistema, en el Módulo 1. Las reglas de Trivy y Checkov (Módulo 5) son reglas que la comunidad de seguridad escribió, basadas en patrones de mala configuración observados en miles de proyectos distintos — su valor es encontrar categorías de problemas que el equipo de Andes Cargo no pensó en buscar, precisamente porque nadie piensa en todo. Que el Módulo 5 no cierre una fila de este mapa específico no significa que no aporte seguridad real; significa que su aporte es de una naturaleza distinta —cobertura amplia de la comunidad, en vez de resolución de un hallazgo propio— y el mapa lo refleja con honestidad en vez de forzar una fila artificial para que "cierre prolijo".
Ejercicio 3 — Defiende el orden de este mapa frente a una objeción concreta. Un entrevistador técnico te dice: "yo hubiera puesto la cadena de suministro (SBOM, cosign) antes que la gestión de secretos — proteger el código que se despliega me parece más urgente que dónde vive una contraseña de prueba". ¿Cómo responderías, usando la sección Alternatives considered como referencia?
Ver solución
Una respuesta completa reconoce el mérito de la objeción sin ceder el argumento central: "Es una prioridad razonable en aislamiento, pero la secuencia de este mapa no ordena por 'qué se siente más grave' — ordena por qué construcción depende de cuál otra. Firmar un artefacto con cosign (Módulo 6) presupone que el pipeline que lo firma ya se autentica de forma segura (Módulo 2) y que existe una revisión automática del cambio antes de que se aplique (Módulo 4) — construir la firma antes de esas dos piezas protegería un artefacto que sale de un pipeline todavía vulnerable a los riesgos que Módulo 2 y 4 resuelven. La sección 'Alternatives considered' del documento nombra exactamente este tipo de objeción y explica por qué el orden elegido evita construir sobre una base que todavía no existe." Si tu respuesta reconoce la validez de la prioridad alternativa y explica la dependencia real que la descarta, tienes la defensa completa.
Resumen y siguiente paso
En este proyecto final del módulo escribiste RISK-MAP.md, un ADR con la misma disciplina que un equipo de plataforma real usaría: los siete riesgos de THREAT-MODEL.md, reordenados por secuencia de resolución real (identidad → secretos → política preventiva → escaneo comunitario → cadena de suministro → guardrails detectivos → capstone), con el razonamiento explícito de por qué ese orden y no otro, incluidas dos alternativas consideradas y descartadas con su propia justificación. Cerraste el módulo con ambos documentos —THREAT-MODEL.md y RISK-MAP.md— en la raíz de andes-cargo-infra/, siete riesgos identificados, cero resueltos todavía, honestamente marcados Open.
Antes de cerrar este módulo deberías poder: recitar los siete riesgos con su ID, su categoría de STRIDE y el módulo que los resuelve, sin mirar ningún documento; explicar el criterio de secuencia completo (identidad primero, detectivo al final, M5 y M8 sin fila propia); y defender ese orden frente a una objeción razonable, con evidencia de dependencia real, no solo preferencia.
Con esto, el Módulo 1 de cloud-security-and-guardrails-guide queda completo: STRIDE aprendido y aplicado, la superficie de ataque real de Andes Cargo inventariada con comandos reales, el incidente Claude Code destroy reencuadrado desde el ángulo del control automatizado, y dos documentos de portfolio defendibles frente a cualquier pregunta técnica. El Módulo 2 abre la primera fila de este mapa: identidad federada OIDC, construida de verdad hasta el límite exacto que LocalStack Hobby permite.
Recursos
- AWS Prescriptive Guidance — Architecture decision records — la referencia oficial de AWS sobre el formato ADR que
RISK-MAP.mdsigue (contexto, decisión, consecuencias, alternativas consideradas). - Este módulo, lección 7 (
THREAT-MODEL.md) — la fuente de los siete riesgos que este documento reordena. - Este módulo, lección 6 — el incidente Claude Code
destroy, citado en la sección Decision como el caso concreto detrás de priorizarconftest(M4) sobre otros controles. src/guides/cloud-security-and-guardrails-guide/DISENO.md— el diseño completo de esta guía, fuente de la secuencia M2-M8 que este documento justifica.