Module 5: Securing The Ai Workload
1. Introduction: the gate already exists, this workload enters it
Description
ADR-001-llm-as-escalation-path.md (Module 1) has a row with this module's exact name: "M5 — Securing the AI workload | Extends the inherited security gate to the escalation path's new Terraform, least privilege scoped to one model ARN". Notice the verb: extends, not builds. This module doesn't build any new security mechanism — it takes the complete security gate that cloud-security-and-guardrails-guide already designed, tested, and left running green (policy-check, iac-scan, verify-artifact, chained in ci.yml with act pull_request), and confirms that same gate, with no change to its own machinery, correctly evaluates the Terraform and the artifact this specific module adds: bedrock.tf, modules/bedrock-guardrail/, and the .zip for extract-shipment-manifest-fields.
Connection to the module
This guide's Modules 3 and 4 built two real pieces of AI infrastructure: BedrockManifestExtractorRole (Module 3, lesson 4), with bedrock:InvokeModel scoped to a single model's ARN; and Bedrock's complete managed guardrail (Module 4), with its six mechanisms declared in HCL. Neither piece, up to this point, had gone through any automated control — they were verified by hand, reading terraform plan's output. This module closes that gap: the same role and the same Terraform enter, for the first time, the gate cloud-security-and-guardrails-guide already built for the entire andes-cargo-infra/ project.
Analogy: a new package through the same airport scanner
An airport doesn't build a different X-ray scanner for every new type of baggage that starts moving across its belts. The same scanner, with the same rules — is there something metallic where there shouldn't be? does this object's shape match anything prohibited? —, checks a suitcase of clothes, a box of electronics, or a package no one had seen come through before. What changes isn't the scanner: it's the content that enters inspection. If the scanner is well calibrated, it catches a real problem without anyone having to reconfigure the machine for "today's type of package."
cloud-security-and-guardrails-guide's security gate is that scanner. policy-check evaluates any Terraform plan against the policy/ library, without caring whether the new resource is an S3 bucket, a DynamoDB table, or — as in this module — an IAM role that invokes a Bedrock model. iac-scan runs trivy config against any .tf file in the project, with no exception list for "AI files." verify-artifact verifies any .zip against its signature, whether it's process-shipment-manifest's or extract-shipment-manifest-fields's. Building a new scanner for AI baggage — a fourth job, a different tool — would repeat work that already works, and worse: it would create two security standards where there should be only one.
What this module inherits, without reinstalling anything
Before the first line of new code, it's worth stating with exact precision what already exists, already run and verified by cloud-security-and-guardrails-guide, and what this module uses as-is:
WHAT ALREADY EXISTS (cloud-security-and-guardrails-guide) WHAT THIS MODULE ADDS
policy/
├── no-destroy-shipments.rego (M4.6) → policy/bedrock-least-privilege.rego
├── least-privilege-iam.rego (M4.7) (lesson 3 -- one more file,
└── no-public-buckets.rego (M4.7) same directory, same package main)
conftest 0.69.0 / OPA 1.19.0 (M4.3) → unchanged -- the binary is reused
Trivy 0.74.0 (M5.3) → unchanged -- the binary is reused
cosign v3.1.3, cosign.key/cosign.pub (M6.5) → unchanged -- the keypair is reused
.github/workflows/ci.yml
├── policy-check (M8.3) → no new job -- bedrock.tf enters
├── iac-scan (M8.3) the same plan/scan already running
└── verify-artifact (M8.3) → one more step, same job, also
verifies the extractor's .zip
Not a single new binary to install, not a different version to pin, not a new job to add to the pipeline. conftest --version still reports Conftest: 0.69.0 / OPA: 1.19.0 — the same version cloud-security-and-guardrails-guide, Module 4, lesson 3 already confirmed. trivy --version stays at 0.74.0. cosign version stays at v3.1.3, with the same cosign.key/cosign.pub generated in that guide, Module 6, lesson 5 — never a new keypair for this guide. If at any point in this module you see an installation command, that's a signal something went wrong: this module's hard discipline is that zero tools get installed again.
This module's map: the 8 lessons
M5 -- SECURING THE AI WORKLOAD
1 Introduction the gate already exists, this workload enters it (this lesson)
2 Least privilege for a model picks up M3.4's role, bedrock:* as antipattern
3 Hands-on: the new policy bedrock-least-privilege.rego, real PASS/FAIL
4 Why Bedrock doesn't need an API key contrast with most LLM APIs
5 Hands-on: Trivy trivy config over bedrock.tf + the new module
6 Hands-on: signing with cosign the extractor's .zip, signed and verified
7 STRIDE revisited two new rows in THREAT-MODEL.md
8 Project: the extended gate the 3 jobs, with the new material included, green end to end
| # | Lesson | What runs/practices |
|---|---|---|
| 1 | Introduction (this one) | What this module inherits from cloud-security-and-guardrails-guide, without reinstalling anything |
| 2 | Least privilege for a model, not for a service | Picks up BedrockManifestExtractorRole (M3.4); bedrock:* named as antipattern |
| 3 | Hands-on: bedrock-least-privilege.rego, added to policy/ | Executed: conftest test tfplan.json -p policy/bedrock-least-privilege.rego — real PASS on the correct role, real FAIL on bedrock:* |
| 4 | Why Bedrock doesn't need an API key | Conceptual — IAM signs the call, no new secret management in this guide |
| 5 | Hands-on: Trivy over the new Terraform | Executed: trivy config over bedrock.tf + modules/bedrock-guardrail/ |
| 6 | Hands-on: signing the extractor's artifact with cosign | Executed: real sign-blob/verify-blob, same keypair, zero reinstallation |
| 7 | STRIDE, revisited | Two new rows in THREAT-MODEL.md: TM-08 (prompt tampering), TM-09 (PII leakage) |
| 8 | Project: Andes Cargo's security gate, extended | Executed: the 3 existing jobs, act pull_request, green end to end, no new job |
Why "extend," not "rebuild," is this module's discipline
There's a real temptation, and it's worth naming before it shows up: someone arriving at this module, seeing that Bedrock is "different" — a non-deterministic model, a new API, a domain that feels special — might think they need their own CI job, their own scanning tool, their own signing flow. None of the three is true. policy-check doesn't care whether the resource it's evaluating is a bucket or a Bedrock role: it reads resource_changes from the plan, and applies rules against the JSON structure, whatever the resource's type is. iac-scan doesn't distinguish "AI Terraform" from "business Terraform": it scans any .tf file it finds in the project. verify-artifact doesn't verify "normal artifacts" differently from "AI artifacts": cosign verify-blob signs and verifies bytes, with no knowledge of what the code inside the .zip does.
This is, in practice, the strongest proof that a security gate is well designed: it generalizes to a domain no one had in mind when it was built. cloud-security-and-guardrails-guide never mentioned Bedrock, generative AI, or language models in any of its eight lessons — and yet its gate correctly evaluates this module's AI infrastructure without needing a single new line of code in its own machinery. Everything new in this module lives in the content that passes through the gate (bedrock.tf, the bedrock-least-privilege.rego policy, the extractor's .zip), never in the gate itself.
Common mistakes
Proposing a fourth job (bedrock-scan, ai-security-check) "because Bedrock is special" (over-engineering, the central mistake this module prevents). What happens: someone, used to every new module in this guide adding a new piece of infrastructure, assumes this module should also add a new piece of CI. How to spot it: if your plan for this module includes a new job in ci.yml, instead of a new step inside an already-existing job, or no change to ci.yml at all. How to fix it: this module's lesson 8 confirms, with a real act pull_request run, that the three existing jobs — with no fourth job — are enough to evaluate the new Terraform and artifact. If you feel the temptation for a new job, come back to this lesson: the whole point of the module is that the gate already generalizes.
Assuming "reusing the gate" means this module writes no new code at all (underestimating the real work). What happens: someone reads "don't rebuild anything" and concludes this module is pure review, with no new artifact to produce. How to spot it: if you finish this module without having written policy/bedrock-least-privilege.rego. How to fix it: "reusing the gate" means reusing the machinery — conftest, Trivy, cosign, the three ci.yml jobs — it doesn't mean there's nothing new for that gate to evaluate. Lesson 3 writes a real, new, Bedrock-specific Rego policy; lesson 6 signs a real, new artifact that never existed in previous guides. What doesn't get rebuilt is the engine; what does get built is what that engine examines.
Thinking that, because conftest/Trivy/cosign were already installed by another guide, there's no need to confirm they still work here (assuming without verifying). What happens: someone, trusting that "they were already installed in cloud-security-and-guardrails-guide," doesn't run conftest --version/trivy --version/cosign version again in this specific environment. How to spot it: if your first real run of conftest test in lesson 3 is also the first time you confirm the binary exists on your PATH. How to fix it: "reused, not reinstalled" means you won't download a new binary or pin a different version — it doesn't mean you skip verification. Every "hands-on" lesson in this module confirms, with the real command, that the tool responds before using it for something new.
Exercises
Exercise 1 — Without looking at the rest of this module, list the three jobs of the inherited security gate, in the exact order needs: chains them. Then check your answer against the diagram above.
See solution
policy-check (no needs:, runs first) → iac-scan (needs: policy-check) → verify-artifact (needs: iac-scan). The order isn't arbitrary: it follows the increasing-cost criterion cloud-security-and-guardrails-guide, Module 8, lesson 2 already established — evaluate the cheapest policy first, the cryptographic signature last, to fail fast when the problem is the most common and cheapest to detect.
Exercise 2 — Explain, in one sentence, why iac-scan (Trivy) doesn't need to know that aws_bedrock_guardrail is a new resource type in order to scan it. Think about how a configuration scanner works in general, not about Bedrock specifically.
See solution
Because Trivy doesn't keep a closed list of "resource types it knows how to scan" before trying — it parses any .tf file as valid HCL, and applies each rule in its checks bundle (AWS-0086, AWS-0132, etc.) against the resources it finds, regardless of whether that rule existed when the file was written. If no rule in the current bundle specifically knows aws_bedrock_guardrail, the result simply includes no finding for that resource type — not because Trivy ignored it, but because no one has written a matching rule yet. This module's lesson 5 confirms this with a real run.
Exercise 3 — Predict what would happen if bedrock.tf had an HCL syntax error (an unclosed brace, for example) by the time it reached the policy-check job. At exactly which step in the job would it fail, and what would happen to iac-scan and verify-artifact?
See solution
It would fail at the Terraform plan step (or even earlier, at Terraform init, depending on the exact nature of the error) — before conftest ever got to evaluate anything, because terraform show -json tfplan > tfplan.json would never produce a valid tfplan.json if the plan itself was never generated. With policy-check red, iac-scan and verify-artifact would never start, because both have needs: pointing, directly or transitively, to policy-check — the same "the gate cuts earlier, not later" discipline the previous guides already established. A syntax error in this module's new Terraform would be caught in the gate's first second, not its third.
Summary and next step
This lesson laid out the module's complete thesis: cloud-security-and-guardrails-guide's security gate — three jobs (policy-check, iac-scan, verify-artifact), three tools ($0, already installed), one policy library (policy/) — needs no change to its own machinery to correctly evaluate Andes Cargo's AI infrastructure. You saw the complete map of the 8 lessons, and the exact reason why "extend," not "rebuild," is the whole module's hard discipline: a good gate generalizes to domains no one had in mind when it was designed.
Before moving on you should be able to: name the three inherited tools that weren't reinstalled and their exact versions; explain why this module adds no new job to ci.yml; and anticipate what's genuinely new that you will build (a policy, a signed artifact, two rows of a document).
Lesson 2 picks up BedrockManifestExtractorRole from Module 3 and precisely names the exact antipattern that lesson 3's policy will automatically block.
Resources
ADR-001-llm-as-escalation-path.md(Module 1, lesson 8 of this guide) — the row that assigns this module its exact responsibility within the guide's complete arc.cloud-security-and-guardrails-guide, Module 8 — the capstone wherepolicy-check/iac-scan/verify-artifactwere first chained inci.yml, the same file this module extends.- Conftest — Official Documentation — reference for the gate's central tool, reused unchanged in this module.
- Sigstore —
cosignDocumentation — reference for the signing tool reused in lesson 6.