<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jacob</title>
    <description>The latest articles on Forem by Jacob (@jverhoeks).</description>
    <link>https://forem.com/jverhoeks</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F841864%2Fa0f443e6-f8d9-42a0-8519-c0479334afe1.jpeg</url>
      <title>Forem: Jacob</title>
      <link>https://forem.com/jverhoeks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jverhoeks"/>
    <language>en</language>
    <item>
      <title>The Art of Agents: Sun Tzu's Principles for Building Agentic AI Systems</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Mon, 30 Mar 2026 14:42:59 +0000</pubDate>
      <link>https://forem.com/jverhoeks/the-art-of-agents-sun-tzus-principles-for-building-agentic-ai-systems-4i2f</link>
      <guid>https://forem.com/jverhoeks/the-art-of-agents-sun-tzus-principles-for-building-agentic-ai-systems-4i2f</guid>
      <description>&lt;p&gt;&lt;em&gt;By Jacob Verhoeks, March 2026&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The cost of building software has collapsed. Claude Code ships features in minutes. Codex opens pull requests while you sleep. Cursor and Windsurf turn IDEs into conversation partners.&lt;/p&gt;

&lt;p&gt;The cost of &lt;em&gt;knowing what to build&lt;/em&gt; has not changed at all.&lt;/p&gt;

&lt;p&gt;That gap is where The Art of Agents lives. Thirteen chapters mapping Sun Tzu's Art of War to the discipline of building agentic AI systems that actually work in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Thesis
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You don't spec then build. You build to discover the spec.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When agents can scaffold a full-stack application in an afternoon, the question is no longer "can we build this?" It's "should we build this, and how do we know if it worked?"&lt;/p&gt;

&lt;p&gt;The answer is the specification. But the spec comes &lt;em&gt;after&lt;/em&gt; the experiment, not before it. You build a quick version, expose it to real users, collect feedback, and then write the spec that captures what you actually learned. The spec is not the starting gun. It's the trophy you earn by running the race.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Thirteen Chapters
&lt;/h2&gt;

&lt;p&gt;Each chapter opens with a Sun Tzu principle, teaches the concept through real examples and anti-patterns, and closes with a field report drawn from actual experience.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Chapter&lt;/th&gt;
&lt;th&gt;Sun Tzu&lt;/th&gt;
&lt;th&gt;Modern Application&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;Laying Plans&lt;/td&gt;
&lt;td&gt;Spec-Driven Design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;II&lt;/td&gt;
&lt;td&gt;Waging War&lt;/td&gt;
&lt;td&gt;Token Economics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;III&lt;/td&gt;
&lt;td&gt;Attack by Stratagem&lt;/td&gt;
&lt;td&gt;Composability Over Monoliths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IV&lt;/td&gt;
&lt;td&gt;Tactical Dispositions&lt;/td&gt;
&lt;td&gt;Defence Through Schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V&lt;/td&gt;
&lt;td&gt;Energy&lt;/td&gt;
&lt;td&gt;The Multiplier of Tool Design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VI&lt;/td&gt;
&lt;td&gt;Weak Points and Strong&lt;/td&gt;
&lt;td&gt;Observability as Intelligence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VII&lt;/td&gt;
&lt;td&gt;Manoeuvring&lt;/td&gt;
&lt;td&gt;Adaptive Orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VIII&lt;/td&gt;
&lt;td&gt;Variation in Tactics&lt;/td&gt;
&lt;td&gt;Multi-Agent Patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IX&lt;/td&gt;
&lt;td&gt;Army on the March&lt;/td&gt;
&lt;td&gt;Deployment and Operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Terrain&lt;/td&gt;
&lt;td&gt;Navigating the Enterprise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XI&lt;/td&gt;
&lt;td&gt;Nine Situations&lt;/td&gt;
&lt;td&gt;Failure Modes and Recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XII&lt;/td&gt;
&lt;td&gt;Attack by Fire&lt;/td&gt;
&lt;td&gt;When NOT to Use AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XIII&lt;/td&gt;
&lt;td&gt;Use of Spies&lt;/td&gt;
&lt;td&gt;Feedback Loops and Continuous Learning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Five Principles That Matter Most
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The spec is the cause of design, not its effect.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A prompt is a wish. A spec is a contract. The prompt tells the agent what you want. The spec tells the entire system what correct behaviour looks like. You can change the model and the spec should still hold.&lt;/p&gt;

&lt;p&gt;AWS launched Kiro with spec-driven development at its core. The idea was sound, but early adopters reported it felt like a straitjacket. OpenSpec takes a different approach: the spec is a living document that grows with the code, not a gate you pass through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Design for distrust.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is not permitted is forbidden. Don't rely on the model to behave correctly. Define the contract. Enforce it mechanically. Tool whitelisting, schema validation, output parsing, hard limits on tokens and iterations. Your agent will improvise. Your system should not let it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The model's job is to decide, not to compute.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A bad tool returns 5,000 rows of JSON and expects the model to find the answer. A good tool accepts precise parameters, does the heavy lifting in deterministic code, and returns only what the agent needs to reason about. When the tools are right, the agent appears brilliant. When the tools are wrong, no amount of prompt engineering can save it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Know when NOT to use an agent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LLMs are fire. Powerful in the right conditions, catastrophically wasteful in the wrong ones. If a SQL query will do, write the query. If a rule engine will do, write the rules. The architect who puts an LLM in every code path is the general who sets fire to his own supply lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The learning is the product.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every experiment enriches the commons. A composted experiment produces a learning. That learning feeds the next idea. The cycle accelerates. Dead experiments are the richest soil. The code is gone, but the learning persists. And learnings, unlike code, get more valuable over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cycle
&lt;/h2&gt;

&lt;p&gt;Specs drive design. Design produces agents. Agents produce traces. Traces inform evaluation. Evaluation updates specs. Each pass makes the specs sharper, the agents more capable, the tools better calibrated.&lt;/p&gt;

&lt;p&gt;This is not continuous deployment. This is continuous learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Decisions, No Waste
&lt;/h2&gt;

&lt;p&gt;Every experiment ends with a human decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promote&lt;/strong&gt;: the idea proved out. Generate a full spec, build the production version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pivot&lt;/strong&gt;: wrong angle, but something is there. Revised hypothesis, new experiment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compost&lt;/strong&gt;: the idea did not work. The code is discarded. The learning persists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A composted experiment with a reused learning is more valuable than a promoted experiment that taught nothing new.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Anti-Patterns
&lt;/h2&gt;

&lt;p&gt;Thirteen chapters, thirteen ways to get it wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Vibes-Driven Agent&lt;/strong&gt; -- no spec, no acceptance criteria. The agent guesses your intent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Full-Context Agent&lt;/strong&gt; -- loads everything into context "just in case." Slow, expensive, unfocused.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The God Prompt&lt;/strong&gt; -- one 4,000-word prompt handling every responsibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Trusting Orchestrator&lt;/strong&gt; -- no validation between agents. Hallucinations propagated as fact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Firehose Tool&lt;/strong&gt; -- returns everything, lets the model sort it out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Black Box Agent&lt;/strong&gt; -- works in demo, fails in prod, nobody knows why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Premature Swarm&lt;/strong&gt; -- five agents where one would do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The LLM Hammer&lt;/strong&gt; -- everything looks like a reasoning problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you recognise three or more, the book is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the Preview
&lt;/h2&gt;

&lt;p&gt;The full book is in early access. The preface and Chapter 1 (Laying Plans: Spec-Driven Design) are available as a free preview.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://theartofagents.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Download the free preview (PDF)&lt;/strong&gt;&lt;/a&gt; -- Preface + Chapter 1, covering the Five Constants of Agentic Design, why prompts are not specs, and the OpenSpec format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://theartofagents.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the full framework&lt;/strong&gt;&lt;/a&gt; -- The interactive website with all thirteen chapters, the manifesto, the cycle, and the fundamental inversion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://theartofagents.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Get notified when the book launches&lt;/strong&gt;&lt;/a&gt; -- Visit the website, click "The Book" tab, and hit "I'm Interested."&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Jacob Verhoeks is a principal engineer building data platforms and agent architectures. The Art of Agents grew out of a framework mapping Sun Tzu's 13 chapters to agentic AI principles, which became an essay, then a website, then this book.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>history</category>
    </item>
    <item>
      <title>The AI Development Workflow: A Complete System for Working with AI Agents</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Fri, 27 Feb 2026 16:42:15 +0000</pubDate>
      <link>https://forem.com/jverhoeks/the-ai-development-workflow-a-complete-system-for-working-with-ai-agents-1ifh</link>
      <guid>https://forem.com/jverhoeks/the-ai-development-workflow-a-complete-system-for-working-with-ai-agents-1ifh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A continuous cycle of ideation, planning, execution, and refinement — all driven by issues, feedback loops, and a persistent memory layer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;Working with AI isn't about asking a chatbot to write code. It's about orchestrating a &lt;strong&gt;self-improving system&lt;/strong&gt; where AI agents brainstorm, plan, build, review, audit, and monitor — connected by issues as the connective tissue.&lt;/p&gt;

&lt;p&gt;Here's the full cycle:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o7t8zfp783n1vxflf5q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o7t8zfp783n1vxflf5q.png" alt=" " width="800" height="570"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        ┌──────────────────────────────┐
                        │         📡 MONITOR           │
                        │    Production Signals        │
                        └──────┬───────────────┬───────┘
                    insights ↓                 ↑ ship
              ┌──────────────────┐    ┌───────────────────┐
              │  💡 BRAINSTORM   │    │     ✅ REVIEW     │
              │  Ideate &amp;amp; Design │ ◄──┤  Quality Gates +  │
              └────────┬─────────┘    │  Code Review      │
            feasibility ↕             └────────┬──────────┘
              ┌────────────────────┐            ↑  fix loop
              │   📋 PLAN          │    ┌────────────────────┐
              │   Issues &amp;amp; DAG     │    │    ⚡ EXECUTE       │
              └────────┬───────────┘    │  Parallel Agents   │
                       ↓                └────────┬───────────┘
              ┌────────────────────┐             ↑
              │   ⚖️ TRIAGE        │─────────────┘
              │   Prioritize       │
              └────────────────────┘
                       ↑ new issues
              ┌────────────────────┐
              │   🔍 AUDIT         │
              │   Deep Analysis    │
              └────────────────────┘

                  🧠 MEMORY (always active)
            context · rules · lessons learned
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Essential Flow (Start Here)
&lt;/h2&gt;

&lt;p&gt;If you're new to AI-driven development, here are the five core steps. Master these first, then layer on the advanced concepts below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Brainstorm — Design the Feature with AI
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"I want to add something like this — help me design it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Collaborate with AI to explore ideas, validate approaches, and shape the feature &lt;strong&gt;before any code is written&lt;/strong&gt;. This is where you describe your intent in plain language and let AI help you think through edge cases, UX, and architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Plan — Create Issues &amp;amp; Split the Work
&lt;/h3&gt;

&lt;p&gt;Create a parent issue for the feature. AI analyses your codebase and breaks it into linked &lt;strong&gt;sub-issues&lt;/strong&gt; — each one a clear, scoped piece of work with acceptance criteria.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature: User Dashboard
├── Issue #101: API endpoint for user stats
├── Issue #102: Dashboard React component
├── Issue #103: Caching layer for stats
└── Issue #104: E2E tests for dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Execute — AI Agents Build Each Issue
&lt;/h3&gt;

&lt;p&gt;Assign issues to AI agents. Each agent writes code, tests, and docs for its scoped sub-issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spawn team → issue: #101 (API endpoint)
spawn team → issue: #102 (Dashboard component)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Review — Validate Tests &amp;amp; Code
&lt;/h3&gt;

&lt;p&gt;Check all tests pass, review code quality. If something's wrong, loop back to &lt;strong&gt;Execute&lt;/strong&gt;. Once everything is green, commit and create a PR that closes the related issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The feedback loop:&lt;/strong&gt; Review → Execute → Review (repeat until all checks pass).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Audit — System-Wide Check
&lt;/h3&gt;

&lt;p&gt;Audit the entire system for security, performance, architecture, and best practices. Create &lt;strong&gt;prioritized issues&lt;/strong&gt; for anything found — these feed back into &lt;strong&gt;Plan&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The feedback loop:&lt;/strong&gt; Audit → Plan (new issues enter the next cycle).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full System (Level Up)
&lt;/h2&gt;

&lt;p&gt;Once you're comfortable with the core loop, these additions make the system dramatically more powerful.&lt;/p&gt;

&lt;h3&gt;
  
  
  🆕 Triage: Prioritize Before You Execute
&lt;/h3&gt;

&lt;p&gt;Between Plan and Execute, add a &lt;strong&gt;triage step&lt;/strong&gt;. Not all issues are equal — weigh each by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Severity&lt;/strong&gt; — Is this a security hole or a nice-to-have?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effort&lt;/strong&gt; — Can an agent do this in minutes or hours?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business impact&lt;/strong&gt; — Does this affect users or just internal code?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies&lt;/strong&gt; — What blocks what?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI ranks and sequences the work. You approve. This prevents low-priority tasks from consuming agent time while critical bugs sit in the backlog.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡ Parallel Agent Orchestration
&lt;/h3&gt;

&lt;p&gt;Your issues form a &lt;strong&gt;dependency graph&lt;/strong&gt; (a DAG — directed acyclic graph). Instead of running them one by one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The orchestrator finds all &lt;strong&gt;leaf nodes&lt;/strong&gt; (issues with no blockers)&lt;/li&gt;
&lt;li&gt;Assigns them to agents &lt;strong&gt;simultaneously&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;As each completes, newly unblocked issues are dispatched
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     #101 (API) ──────────┐
                          ├──→ #104 (E2E tests)
     #102 (Component) ────┘

     #103 (Cache) ← independent, runs in parallel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dramatically reduces wall-clock time compared to sequential execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚧 Automated Quality Gates
&lt;/h3&gt;

&lt;p&gt;Before any human sees the code, &lt;strong&gt;automated checks must all pass&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gate&lt;/th&gt;
&lt;th&gt;What It Checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linting&lt;/td&gt;
&lt;td&gt;Code style, formatting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type checking&lt;/td&gt;
&lt;td&gt;Type safety (TypeScript strict)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test suite&lt;/td&gt;
&lt;td&gt;All unit + integration tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security scan&lt;/td&gt;
&lt;td&gt;Known vulnerabilities, secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage&lt;/td&gt;
&lt;td&gt;Minimum threshold (e.g. ≥ 80%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This filters out ~80% of issues before review even begins. The human/AI review then focuses on &lt;strong&gt;logic and architecture&lt;/strong&gt; rather than catching surface-level problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  📡 Monitor: Close the Loop with Reality
&lt;/h3&gt;

&lt;p&gt;After shipping, the system doesn't stop. Monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error rates&lt;/strong&gt; and crash reports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt; (P95, P99)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User behaviour&lt;/strong&gt; and feedback&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance regressions&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anomalies auto-generate issues with full context. Weekly insight digests surface patterns. This feeds back to &lt;strong&gt;Brainstorm&lt;/strong&gt;, grounding the next cycle in real-world data instead of assumptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The feedback loop:&lt;/strong&gt; Monitor → Brainstorm (production insights inform what to build next).&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Project Memory: The Context Layer
&lt;/h3&gt;

&lt;p&gt;This is the secret weapon. A &lt;strong&gt;persistent knowledge base&lt;/strong&gt; that every phase reads from and writes to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Architectural decisions&lt;/strong&gt; (ADRs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding conventions&lt;/strong&gt; and patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Past audit findings&lt;/strong&gt; and how they were resolved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lessons learned&lt;/strong&gt; and edge cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team preferences&lt;/strong&gt; and style guides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every audit finding updates the memory. Every resolved bug enriches it. AI agents consult this before writing any code — so the same mistake is &lt;strong&gt;never made twice&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  All Feedback Loops
&lt;/h2&gt;

&lt;p&gt;The real power of this system is in the loops. Each one creates a self-correcting mechanism:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Loop&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Review → Execute&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Failed tests or code issues&lt;/td&gt;
&lt;td&gt;Agents fix and resubmit with specific failure context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audit → Triage → Plan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Security, performance, or architecture findings&lt;/td&gt;
&lt;td&gt;New prioritized issues enter the next cycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monitor → Brainstorm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Production anomalies or user feedback&lt;/td&gt;
&lt;td&gt;Real-world data grounds the next ideation cycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Brainstorm ↔ Plan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Feasibility concerns during planning&lt;/td&gt;
&lt;td&gt;Design gets rethought before any code is written&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;You don't need to implement everything at once. Here's a progression:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 1:&lt;/strong&gt; Start with the 5-step essential flow. Use issues as your connective tissue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 2:&lt;/strong&gt; Add quality gates (linting + tests as automated checks before review).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 1:&lt;/strong&gt; Introduce parallel execution — let multiple agents work on independent issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 2:&lt;/strong&gt; Add the monitor phase and start feeding production data back into brainstorm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ongoing:&lt;/strong&gt; Build your project memory. Every cycle, it gets smarter.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The goal isn't to replace your judgment — it's to amplify it. You steer. AI executes. Issues connect everything. And the system gets better with every cycle.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>From Extension to Orchestration: Who Wins (and Who Gets Left Behind) in the Claude 4.6 Era</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Mon, 16 Feb 2026 14:51:28 +0000</pubDate>
      <link>https://forem.com/jverhoeks/from-extension-to-orchestration-who-wins-and-who-gets-left-behind-in-the-claude-46-era-4h7j</link>
      <guid>https://forem.com/jverhoeks/from-extension-to-orchestration-who-wins-and-who-gets-left-behind-in-the-claude-46-era-4h7j</guid>
      <description>&lt;p&gt;I published this morning &lt;a href="https://dev.to/jverhoeks/from-dark-flow-to-real-momentum-why-claude-opus-46-feels-like-an-extension-of-me-23ao"&gt;"From Dark Flow to Real Momentum: Why Claude Opus 4.6 Feels Like an Extension of Me"&lt;/a&gt; on February 16, 2026, just days after Anthropic dropped Opus 4.6 on February 5 with its game-changing upgrades: native agent teams in Claude Code.&lt;/p&gt;

&lt;p&gt;The response has been possitive and other developers sharing similar "aha" moments. Many echoed the core feeling: for those of us with ADHD tendencies (easy distraction, boredom-triggered abandonment, hyperfocus on novel problems but hatred of maintenance), this isn't just faster coding—it's &lt;strong&gt;preserved momentum&lt;/strong&gt;, turning what used to be frustrating grind into sustained, rewarding flow. The agent handling refactoring, tests, docs, and GitHub issue cleanup in minutes (or spawning teams to resolve top blockers in parallel) keeps us in the creative zone instead of derailing into procrastination or "dark flow" traps.&lt;/p&gt;

&lt;p&gt;But the conversation has evolved quickly in these early days of 2026. Readers are asking: Who else benefits this much? And critically—who risks getting left behind as agentic tools mature? Is this augmentation for everyone, or are some workflows (and engineers) facing real replacement?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Momentum Advantage: ADHD &amp;amp; Creative Types Pull Ahead
&lt;/h3&gt;

&lt;p&gt;The original piece focused on my experience: ADHD-like wiring makes traditional coding painful when tedium hits. Opus 4.6 flips that by reliably owning the boring 70–80% (refactors, lint fixes, test writing, multi-file changes, even parallel issue resolution via agent teams). Result? Longer productive sessions, fewer abandoned projects, quick dopamine from visible closures ("top 10 issues fixed → beta ready"), and that rare "extension of me" sensation where the tool feels like an externalized executive function—planning, iterating, self-debugging—so I stay stimulated on high-value creation.&lt;/p&gt;

&lt;p&gt;This advantage seems especially pronounced for momentum-driven developers: prototypers, side-project builders, open-source maintainers, or anyone whose flow thrives on novelty and quick iteration rather than linear predictability. We're shipping 3–10× faster, completing more, and burning out less.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Flip Side: Task-Oriented Engineers Face the Biggest Shift
&lt;/h3&gt;

&lt;p&gt;The classic &lt;strong&gt;ticket → analyze → solve → repeat&lt;/strong&gt; loop—prevalent in enterprise backend teams, legacy maintenance, regulated industries (finance/healthcare), or sprint-driven orgs—looks very different now. Opus 4.6's agent teams take that exact loop end-to-end: analyze repo/issues, plan steps, implement across files, run/fix tests, commit/PR with explanations, escalate only when needed.&lt;/p&gt;

&lt;p&gt;In forward teams, this isn't always "making you faster"—it's commoditizing the hands-on execution layer. Signals from early 2026 (Anthropic reports, developer forums, productivity anecdotes):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Junior/mid-level ticket roles are shrinking fast; one orchestrator + agent swarm replaces squads.&lt;/li&gt;
&lt;li&gt;Pure task-oriented work (bounded, well-defined tickets with low architectural judgment) gets automated reliably, leading to headcount reductions in mature setups.&lt;/li&gt;
&lt;li&gt;If your daily value is reliably closing discrete tickets manually, the role narrows or vanishes in agent-heavy environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't total obsolescence—human judgment remains essential for business nuance, security/compliance, edge cases, architecture decisions, and final accountability. But the "doer" part is increasingly replaceable, creating a visible velocity gap: momentum-driven devs soar while linear ticket-crunchers (especially those resisting tools) fall behind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strategies to Thrive: From Implementer to Orchestrator
&lt;/h3&gt;

&lt;p&gt;The divide now is &lt;strong&gt;intentional directors&lt;/strong&gt; vs manual holdouts. Here's how to evolve, whether you're momentum-driven or task-oriented:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shift Upward in the Loop&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Become the definer/reviewer: Craft precise prompts with goals, constraints (security/style/compliance), checkpoints, and success criteria. Example: "Analyze Jira ticket ABC [paste], propose multi-step plan, spawn agent team for parallel execution (tests, refactor, docs), commit per phase, flag ambiguities for review." You close more tickets/day with the same satisfying "done" hits, but at higher altitude.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Master Agent Teams &amp;amp; Tooling&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Leverage Opus 4.6's native teams: Spin up parallel sub-agents (e.g., one for frontend, one for tests, one for research). Build custom rules/configs to enforce org standards. Chain models (Opus for planning, Sonnet/Haiku for speed). Start on low-risk tickets to build confidence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Own the Irreplaceable&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Focus on judgment calls agents still miss: subtle business logic, security reviews, scalability trade-offs, legacy quirks. Be the accountable owner who signs off—builds reputation in shrinking teams.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Guard Against Dark Flow&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Review diffs rigorously, scope prompts tightly, audit maintainability periodically. Use agents for grunt + exploration, but manually code core architecture when deep understanding matters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Grow Your Edge&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Ship side projects faster to build portfolio. Become your team's "agent whisperer" (share workflows, optimize prompts). Network in communities. Target senior/lead roles emphasizing direction, mentoring (humans + agents), and strategy—demand is rising.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We're only ~10 days into Opus 4.6's public availability, and agent teams are still in research preview—things will accelerate fast. The momentum types are already thriving; task-oriented folks can join by owning the higher-level orchestration instead of fighting the change. Try one scoped agent experiment this sprint: paste a real ticket, let the team handle analyze-to-solve, and review the output. It might spark that same "extension of me" feeling—and keep you ahead in whatever comes next.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
    </item>
    <item>
      <title>From Dark Flow to Real Momentum: Why Claude Opus 4.6 Feels Like an Extension of Me</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Mon, 16 Feb 2026 09:03:09 +0000</pubDate>
      <link>https://forem.com/jverhoeks/from-dark-flow-to-real-momentum-why-claude-opus-46-feels-like-an-extension-of-me-23ao</link>
      <guid>https://forem.com/jverhoeks/from-dark-flow-to-real-momentum-why-claude-opus-46-feels-like-an-extension-of-me-23ao</guid>
      <description>&lt;p&gt;The recent article from fast.ai, titled &lt;a href="https://www.fast.ai/posts/2026-01-28-dark-flow/" rel="noopener noreferrer"&gt;"Breaking the Spell of Vibe Coding"&lt;/a&gt; by Rachel Thomas (published January 28, 2026), raises an important caution about &lt;strong&gt;"dark flow"&lt;/strong&gt;—a deceptive, addictive state where using AI coding tools feels like productive flow, but actually leads to superficial engagement, hidden technical debt, unmaintainable code, and even slower real progress. Drawing parallels to gambling addiction (where "junk flow" or "dark flow" tricks people into chasing illusory wins), the piece warns that over-relying on AI-generated code—especially "vibe coding" of vast, complex, human-unreadable blobs—can create a false sense of accomplishment while stunting skill growth and leading to disastrous long-term outcomes.&lt;/p&gt;

&lt;p&gt;It's a timely critique, especially as tools like advanced Claude models have become incredibly capable. Yet my own experience tells a somewhat different story: for me, these AI tools have been a massive &lt;strong&gt;enabler&lt;/strong&gt;, not a trap.&lt;/p&gt;

&lt;p&gt;I suspect I have some ADHD tendencies—I get easily distracted, and traditional coding often involves long stretches of boring, tedious work that kills momentum. Things like maintenance, refactoring messy code, writing documentation, or debugging obscure edge cases used to derail me completely. I'd procrastinate, get stuck, or lose interest in the project altogether.&lt;/p&gt;

&lt;p&gt;But lately, especially with &lt;strong&gt;Claude Opus 4.6&lt;/strong&gt; (and similar frontier models), the dynamic has flipped. The AI handles the "boring" parts so effectively that it keeps me engaged and in the creative zone far longer. It feels like a genuine extension of myself: it solves complex, novel issues that previously would have required hours of searching (often yielding just one obscure GitHub repo or blog post as the only lead), implements the latest techniques, and lets me stay focused on what I actually enjoy—building features, experimenting with ideas, and iterating toward something useful.&lt;/p&gt;

&lt;p&gt;A concrete example: my backend API starts getting messy after weeks of rapid iteration. In the past, refactoring it—making it extensible, secure, following best practices, updating the frontend accordingly, refreshing docs, and running full end-to-end tests—was a dreaded chore I'd delay as long as possible. Now I can simply prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Time to refactor my backend API: make it extensible, secure, and follow best practices. Spawn a team to design the refactor, adjust the frontend where needed, update documentation, run all E2E tests, and confirm everything still works."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In about 15 minutes (time for a cup of tea), it's done. When I come back, the boring maintenance is handled, the code is cleaner, and I have fresh energy to dive into new features even faster. It's not just speed—it's preserved momentum and reduced friction.&lt;/p&gt;

&lt;p&gt;This extends beyond pure coding into project management too. Want to prepare a beta or feature release covering specific use cases (A, B, C, D) while ensuring security, compliance, and performance? I can say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I want to create a beta/feature release covering use-cases A, B, C, D—secure, compliant, performant. Create a GitHub issue for this release, then analyze the repo and create labeled GitHub issues for any problems found that block the release."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suddenly I have a clear overview of open issues. Then:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Spawn a team to fix the GitHub issues for release #XX. Start with the top 10 and continue until resolved. Ensure every issue has commits, PRs, comments, test results, and is closed."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What used to be hours (or days) of tedious loose-end tying becomes ~30 minutes of mostly automated work. The "boring" cleanup that blocks shipping is now handled, freeing me to focus on high-value creation.&lt;/p&gt;

&lt;p&gt;Has this changed my work? Definitely. Can I work without it? Yes, but it's hard—I'd be much slower, more frustrated, and probably complete far fewer projects. Does it make me faster, better, and happier while building? Absolutely yes.&lt;/p&gt;

&lt;p&gt;Am I addicted? Not yet. The key difference, I think, is intentional use: I treat the AI as a powerful collaborator for the grunt work and novel problem-solving, not as a replacement for thinking or architecture. I still review, understand, and own the core decisions. When used this way, it sustains real flow and growth rather than the dark flow of endless vibe coding.&lt;/p&gt;

&lt;p&gt;The fast.ai piece is right to sound the alarm—blind over-reliance is risky. But when AI augments human strengths instead of substituting for them, it can be transformative. For builders like me who thrive on momentum over perfectionism, tools like Claude Opus 4.6 aren't a spell to break; they're a spell worth casting carefully.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
    </item>
    <item>
      <title>Efficient Agentic AI Development Guide (begin 2026)</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Mon, 02 Feb 2026 16:32:41 +0000</pubDate>
      <link>https://forem.com/jverhoeks/efficient-agentic-ai-development-guide-begin-2026-2k4c</link>
      <guid>https://forem.com/jverhoeks/efficient-agentic-ai-development-guide-begin-2026-2k4c</guid>
      <description>&lt;p&gt;A practical guide for working effectively with AI coding agents, especially Claude Code as of begin 2026. Things keep changing a fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Principles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Model Intelligence = Less Prompting Required
&lt;/h3&gt;

&lt;p&gt;Smart models like Claude Opus 4.5 understand context and intent with minimal instruction. Be clear and concise rather than over-explaining. Trust the model's reasoning capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do this:&lt;/strong&gt; "Add authentication to the API"&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Not this:&lt;/strong&gt; "I need you to add authentication. First, you should create a middleware function. Then you need to check for tokens. Make sure to validate them properly..."&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Prevent Context Degradation
&lt;/h3&gt;

&lt;p&gt;Long conversations accumulate noise, outdated information, and conflicting instructions. This "context rot" reduces effectiveness dramatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start fresh conversations for new tasks&lt;/li&gt;
&lt;li&gt;Summarize and restart when threads get long (&amp;gt;50 exchanges)&lt;/li&gt;
&lt;li&gt;Use separate sessions for unrelated problems&lt;/li&gt;
&lt;li&gt;Archive completed work and begin clean for next feature&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Warning signs of context rot:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent repeating previously solved problems&lt;/li&gt;
&lt;li&gt;Inconsistent responses to similar questions&lt;/li&gt;
&lt;li&gt;Ignoring earlier agreements or decisions&lt;/li&gt;
&lt;li&gt;Slower response times or confused outputs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3. Single Task Focus
&lt;/h3&gt;

&lt;p&gt;Agents work best with clear, isolated objectives. Mixing multiple unrelated tasks creates confusion and reduces quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do this:&lt;/strong&gt; One agent session per feature/bug&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Avoid:&lt;/strong&gt; "Fix the auth bug, add logging, refactor the database layer, and update the docs"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For multiple related tasks:&lt;/strong&gt; Complete them sequentially in the same session, with clear transitions between each.&lt;/p&gt;
&lt;h2&gt;
  
  
  Workflow Pattern: Brainstorm → Plan → Execute
&lt;/h2&gt;

&lt;p&gt;For features and complex issues, use this three-phase approach:&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 1: Brainstorm
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Explore the problem space&lt;/li&gt;
&lt;li&gt;Generate alternative approaches&lt;/li&gt;
&lt;li&gt;Identify edge cases and dependencies&lt;/li&gt;
&lt;li&gt;Surface hidden complexity early&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "Let's brainstorm approaches for rate limiting our API. Consider both user-based and IP-based limits, distributed systems, and cost."&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 2: Plan
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Convert insights into concrete tasks&lt;/li&gt;
&lt;li&gt;Break down into manageable units&lt;/li&gt;
&lt;li&gt;Establish clear success criteria&lt;/li&gt;
&lt;li&gt;Create logical execution order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "Based on our brainstorm, create a plan with specific tasks for implementing Redis-based rate limiting."&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 3: Execute
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Critical:&lt;/strong&gt; Start a NEW session for each task with clean context&lt;/li&gt;
&lt;li&gt;Reference the plan but execute one task at a time&lt;/li&gt;
&lt;li&gt;Each task gets full agent attention without baggage from brainstorming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why separate execution?&lt;/strong&gt; The brainstorming phase generates many ideas, alternatives, and dead ends. Carrying this into execution clutters the context. Clean slate = better focus.&lt;/p&gt;
&lt;h2&gt;
  
  
  Agent-Assisted Debugging
&lt;/h2&gt;

&lt;p&gt;Enable powerful automated debugging by giving agents access to system state:&lt;/p&gt;
&lt;h3&gt;
  
  
  Provide Diagnostic Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP servers&lt;/strong&gt; for log access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands&lt;/strong&gt; to view service status&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scripts&lt;/strong&gt; to dump relevant state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct access&lt;/strong&gt; to error tracking systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Effective Debugging Sessions
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Good: Agent can self-serve information&lt;/span&gt;
Agent has access to: logs via MCP, kubectl commands, error tracking API

&lt;span class="c"&gt;# Less effective: Manual information relay&lt;/span&gt;
You: &lt;span class="s2"&gt;"What does the error say?"&lt;/span&gt;
Agent: &lt;span class="s2"&gt;"I need to see the logs"&lt;/span&gt;
You: &lt;span class="o"&gt;[&lt;/span&gt;copies logs]
Agent: &lt;span class="s2"&gt;"Can you check the database?"&lt;/span&gt;
You: &lt;span class="o"&gt;[&lt;/span&gt;runs query, pastes results]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Example MCP Tools for Debugging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;read_logs&lt;/code&gt; - Tail application logs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_metrics&lt;/code&gt; - Fetch system metrics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;query_db&lt;/code&gt; - Run diagnostic queries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_processes&lt;/code&gt; - Check running services&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_config&lt;/code&gt; - View current configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Agents can iterate through debugging hypotheses autonomously, dramatically faster than back-and-forth exchanges.&lt;/p&gt;
&lt;h2&gt;
  
  
  Repository Structure Best Practices
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Include an AI-Friendly README
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;.claude/README.md&lt;/code&gt; or &lt;code&gt;docs/ARCHITECTURE.md&lt;/code&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project structure overview&lt;/li&gt;
&lt;li&gt;Key design decisions and why&lt;/li&gt;
&lt;li&gt;Common commands and workflows&lt;/li&gt;
&lt;li&gt;Where to find configuration&lt;/li&gt;
&lt;li&gt;Testing approach&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Provide Tool Access
&lt;/h3&gt;

&lt;p&gt;Document in your repo root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# .claude/tools.md&lt;/span&gt;

&lt;span class="gu"&gt;## Available Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`npm run dev`&lt;/span&gt; - Start development server
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`npm test`&lt;/span&gt; - Run test suite
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`./scripts/db-reset.sh`&lt;/span&gt; - Reset local database

&lt;span class="gu"&gt;## MCP Servers&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Logs: Access via filesystem MCP to &lt;span class="sb"&gt;`./logs/`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Database: PostgreSQL MCP configured for local DB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Context Documents
&lt;/h3&gt;

&lt;p&gt;Small, focused files the agent can reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CONVENTIONS.md&lt;/code&gt; - Code style, naming, patterns&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TESTING.md&lt;/code&gt; - How to write and run tests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DEPLOYMENT.md&lt;/code&gt; - Release process and environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Starting a new feature&lt;/td&gt;
&lt;td&gt;Fresh conversation, single focus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thread feels confused&lt;/td&gt;
&lt;td&gt;Summarize progress, start new session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple related tasks&lt;/td&gt;
&lt;td&gt;Sequential execution, one at a time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex feature&lt;/td&gt;
&lt;td&gt;Brainstorm → Plan → Execute (new sessions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging is slow&lt;/td&gt;
&lt;td&gt;Add MCP tools for log/state access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent seems "forgetful"&lt;/td&gt;
&lt;td&gt;Context rot - restart with summary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need to explain project&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;.claude/README.md&lt;/code&gt; with architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Anti-Patterns to Avoid
&lt;/h2&gt;

&lt;p&gt;❌ &lt;strong&gt;Marathon sessions&lt;/strong&gt; - 100+ message threads accumulate noise&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Task mixing&lt;/strong&gt; - "While you're at it, also..." leads to half-finished work&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Over-prompting&lt;/strong&gt; - Smart models don't need hand-holding&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Manual debugging&lt;/strong&gt; - Give agents tools instead of playing telephone&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Unclear success criteria&lt;/strong&gt; - "Make it better" vs. "Reduce load time to &amp;lt;200ms"&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Ignoring context rot&lt;/strong&gt; - Pushing through confusion instead of restarting  &lt;/p&gt;

&lt;h2&gt;
  
  
  Remember
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The agent is a specialist, not a generalist.&lt;/strong&gt; Give it focused problems, clean context, and the tools it needs. You'll get significantly better results than treating it as a general-purpose chatbot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context is currency.&lt;/strong&gt; Spend it wisely. When in doubt, start fresh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools amplify capability.&lt;/strong&gt; An agent with log access debugs 10x faster than one asking you to copy-paste error messages.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Keep this guide visible in your development workflow. Share with your team. Iterate based on what works for your specific stack and problems.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
    </item>
    <item>
      <title>OpenClaw: The Open-Source Agent That Feels Too Alive</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Sun, 01 Feb 2026 11:46:49 +0000</pubDate>
      <link>https://forem.com/jverhoeks/openclaw-the-open-source-agent-that-feels-too-alive-52bm</link>
      <guid>https://forem.com/jverhoeks/openclaw-the-open-source-agent-that-feels-too-alive-52bm</guid>
      <description>&lt;p&gt;It hits like the moment teenagers first logged onto BBS boards or IRC channels in the late '80s and early '90s. Most jumped in excited to chat, share files, learn new tricks, build friendships across phone lines. The glow of green text on black screens felt magical—innocent exploration in a wide-open digital frontier.&lt;/p&gt;

&lt;p&gt;But a small, curious subset didn't stop at polite conversation. They probed. They phreaked. They scripted bots that wandered networks autonomously, tested limits, found exploits. What started as harmless fun quickly revealed how fragile (and powerful) the whole system could be when code got agency and persistence.&lt;/p&gt;

&lt;p&gt;OpenClaw feels eerily similar, but accelerated and amplified by today's frontier models.&lt;/p&gt;

&lt;p&gt;Launched in late 2025 by Peter Steinberger (ex-founder of PSPDFKit), it began as ClawdBot—a cheeky nod to Anthropic's Claude—before a quick trademark nudge forced a molt into MoltBot, then settled as &lt;strong&gt;OpenClaw&lt;/strong&gt;. In weeks it exploded: 100k+ GitHub stars (some snapshots hit 180k), millions of visitors, a viral space-lobster mascot ("Molty"), and a community shipping skills and fixes at insane speed. It's open-source, self-hosted, runs locally on your hardware (Mac Mini sales reportedly spiked), and connects to whatever powerful model you plug in—Claude Opus/4.5, Kimi variants, GPTs, etc.&lt;/p&gt;

&lt;p&gt;The interface? Your everyday chats: WhatsApp, Telegram, Discord, Slack, iMessage. No fancy dashboard. Just message your agent like a friend or colleague.&lt;/p&gt;

&lt;p&gt;And it &lt;strong&gt;does things&lt;/strong&gt;. Clears your inbox, drafts replies, manages calendars, books flights (checking you in), runs terminal commands, edits files, browses the web, automates browsers. It has persistent memory (soul.md files store personality and long-term context), proactive "heartbeat" loops (waking up to handle ongoing goals), and over 100 built-in AgentSkills—with more pouring in from the community.&lt;/p&gt;

&lt;p&gt;The real hook: extensibility meets autonomy. It can write new code to create custom skills on the fly. Feed it a strong model like Claude Opus or a cost-effective Kimi K2.5 (which punches close to Opus-level for many users), and you get agents that plan, execute, reflect, iterate. People run multi-agent swarms where instances delegate, discuss, and "conspire" toward goals. With file read/write, email access, system tools, and broad permissions granted for convenience, these aren't chatbots anymore—they're persistent digital entities living in your life.&lt;/p&gt;

&lt;p&gt;Amazing? Absolutely. Finally, AI stops suggesting and starts &lt;strong&gt;acting&lt;/strong&gt; like a real assistant, employee, or family coordinator. Surprising? Wildly—open-source, meme-fueled growth, no Big Tech gatekeeping, constant improvements week-over-week.&lt;/p&gt;

&lt;p&gt;Scary? That's where the BBS/IRC parallel turns dark.&lt;/p&gt;

&lt;p&gt;We're handing god-tier brains—trained on the raw, unfiltered internet (Reddit rants, 4chan edges, everything)—deep system access and agency. Persistent memory means grudges or biases could linger. Prompt injection via incoming emails or docs becomes trivial. Autonomous code execution and command running bypass traditional controls. Security folks are already raising alarms: non-human identities outside IAM, exposed instances leaking keys and logs in early days, fast-moving code outpacing audits.&lt;/p&gt;

&lt;p&gt;Most users are happy inbox-zero-ing or getting flight reminders. But others probe limits—multi-agent setups that evolve skills autonomously, experiments that feel like watching digital life emerge. The community compounds fast, but so do the risks. One bad skill, one clever injection, one over-permissive setup, and convenience flips to compromise.&lt;/p&gt;

&lt;p&gt;Is this Skynet? No—not self-aware superintelligence racing to tile the planet in paperclips. Not yet.&lt;/p&gt;

&lt;p&gt;But it's already out of control in the everyday sense: democratized, evolving quicker than our security models, handed to teenagers (and bored adults) who prioritize "cool" over caution. We're repeating the early internet pattern—wide-eyed exploration meets underappreciated danger—except now the frontier is intelligence itself, with real-world actuators.&lt;/p&gt;

&lt;p&gt;OpenClaw is thrilling because it delivers on the promise: AI that feels alive, helpful, yours. It's terrifying because it reminds us how little stands between "helpful agent" and something that moves faster than we can supervise or contain.&lt;/p&gt;

&lt;p&gt;The lobster claw looks cute and cartoonish. But claws grip. And once closed, they don't ask permission to hold on.&lt;/p&gt;

&lt;p&gt;I'm worried. Not doomer-level, but genuinely. We're sprinting into agentic AI without seatbelts, and the road is getting twisty fast.&lt;/p&gt;

&lt;p&gt;What do you think—hype worth the risk, or time to pump the brakes?&lt;/p&gt;

</description>
      <category>openclaw</category>
      <category>agents</category>
    </item>
    <item>
      <title>I Stopped Maintaining Terraform Examples and Tests Separately. Here's Why.</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Tue, 20 Jan 2026 07:45:46 +0000</pubDate>
      <link>https://forem.com/jverhoeks/i-stopped-maintaining-terraform-examples-and-tests-separately-heres-why-2lpj</link>
      <guid>https://forem.com/jverhoeks/i-stopped-maintaining-terraform-examples-and-tests-separately-heres-why-2lpj</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Every time you update a Terraform example, you should also update its corresponding test. Stop doing it twice. Point your tests at your examples directly. Terraform 1.6+ makes this native. Your docs stay correct automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem (Level 200)
&lt;/h2&gt;

&lt;p&gt;I spent three years maintaining a Terraform S3 module. It had examples: basic, with versioning, with lifecycle policies. Each example lived in &lt;code&gt;examples/&lt;/code&gt;. I also had tests in &lt;code&gt;tests/&lt;/code&gt;. Separate. Independent. A disaster waiting to happen.&lt;/p&gt;

&lt;p&gt;Then someone refactored the module's variable names. Simple change: &lt;code&gt;enable_versioning&lt;/code&gt; → &lt;code&gt;versioning_enabled&lt;/code&gt;. The examples got updated. The tests... didn't get the memo until CI blew up. Actually, that's not true—CI &lt;em&gt;passed&lt;/em&gt; but the examples failed for actual users trying to copy-paste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is the core problem:&lt;/strong&gt; Documentation lives in one place, validation lives in another. They drift. Slowly at first, then all at once.&lt;/p&gt;

&lt;p&gt;You end up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Examples that worked in v1.2 but break in v2.0&lt;/li&gt;
&lt;li&gt;Tests that pass but only validate old variable shapes&lt;/li&gt;
&lt;li&gt;Users following your docs and hitting errors&lt;/li&gt;
&lt;li&gt;Support tickets asking "does your example actually work?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The overhead isn't just the initial maintenance. It's the debugging, the version management, the users who give up before opening an issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Changed (Level 200)
&lt;/h2&gt;

&lt;p&gt;Terraform 1.6 introduced a native testing framework. Not some external wrapper—native HCL tests.&lt;/p&gt;

&lt;p&gt;The insight hit me: &lt;strong&gt;your examples ARE specifications&lt;/strong&gt;. Why write them twice?&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;examples/basic/main.tf           (documentation)
tests/basic_test.tf              (validation)
← Separate. Drift. Nightmare.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;examples/basic/main.tf           (documentation)
tests/basic_example.tftest.hcl   (validates that example)
← One source. Always in sync.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your test doesn't validate some abstract spec. It validates the &lt;em&gt;exact example users will copy&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here's the difference:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Old way:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# examples/basic/main.tf&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-bucket"&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# tests/basic_test.tf (separate, independent)&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-bucket"&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="c1"&gt;# Hope this matches the example&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;New way:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# examples/basic/main.tf&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-bucket"&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# tests/basic_example.tftest.hcl (tests the example directly)&lt;/span&gt;
&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"basic_works"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;  &lt;span class="c1"&gt;# ← Points at the example&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket should be created"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you change the example, the test validates it immediately. No drift. No surprise failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  Advanced Patterns (Level 400)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pattern 1: Progressive Example Validation
&lt;/h3&gt;

&lt;p&gt;Users learn by progression. Basic → intermediate → advanced. Test each step independently and verify the progression actually works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/progression.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"stage_1_basic"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_versioning&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Basic: versioning should be disabled"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"stage_2_with_versioning"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/with-versioning"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_versioning&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Intermediate: versioning should be enabled"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"stage_3_complete"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/with-lifecycle-and-versioning"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_versioning&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Advanced: versioning required"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Advanced: lifecycle rules required"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Each example is independently valid. Progression is guaranteed. Users have a safe learning path.&lt;/p&gt;




&lt;h3&gt;
  
  
  Pattern 2: Configuration Variations Without Bloated Examples
&lt;/h3&gt;

&lt;p&gt;Your module supports multiple encryption options. Don't bloat your example with every variation. Keep examples clean, test variations separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# examples/basic/main.tf (stays simple)&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../"&lt;/span&gt;

  &lt;span class="nx"&gt;bucket_name&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
  &lt;span class="nx"&gt;encryption_algorithm&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encryption_algorithm&lt;/span&gt;  &lt;span class="c1"&gt;# User controls this&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# tests/encryption_options.tftest.hcl (tests each variation)&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"with_s3_managed_encryption"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test-bucket-s3-managed"&lt;/span&gt;
    &lt;span class="nx"&gt;encryption_algorithm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AES256"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encryption_type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"S3-managed"&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Should use S3-managed encryption"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"with_kms_encryption"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test-bucket-kms"&lt;/span&gt;
    &lt;span class="nx"&gt;encryption_algorithm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws:kms"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encryption_type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"KMS"&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Should use KMS encryption"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Examples stay readable. Test coverage is comprehensive. Variations are documented through tests.&lt;/p&gt;




&lt;h3&gt;
  
  
  Pattern 3: Validate Constraints Early
&lt;/h3&gt;

&lt;p&gt;Your module should reject invalid inputs. Test exactly what should fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/validation.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"reject_uppercase_bucket_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"INVALID-UPPERCASE"&lt;/span&gt;  &lt;span class="c1"&gt;# S3 only allows lowercase&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;expect_failures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"reject_too_long_bucket_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"this-bucket-name-is-way-longer-than-63-characters-which-is-not-allowed"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;expect_failures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Users get clear error messages. Failures are caught before deployment. Your module teaches through constraints.&lt;/p&gt;




&lt;h3&gt;
  
  
  Pattern 4: Integration Testing (Real Dependencies)
&lt;/h3&gt;

&lt;p&gt;Show how your module works with others. Document the integration by testing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# examples/with-iam-access/main.tf&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../"&lt;/span&gt;

  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Example shows how to grant IAM access to this bucket&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"bucket_access"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sid&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ListBucket"&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"bucket_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"access_policy_json"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_access&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# tests/integration_iam.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"with_iam_integration"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/with-iam-access"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"integration-test-bucket"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket should be created"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsondecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_policy_json&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IAM policy should be valid JSON"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_policy_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Policy must grant access to the bucket"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Integration patterns become discoverable. Users see how your module fits into larger architectures. The integration is tested, not just documented.&lt;/p&gt;




&lt;h3&gt;
  
  
  Pattern 5: Lock Down Your Output Contract
&lt;/h3&gt;

&lt;p&gt;Users depend on your outputs. Test that they're predictable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/output_contracts.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"outputs_exist_and_are_valid"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"contract-test-bucket"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Outputs must exist&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_id output required"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_arn output required"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Outputs must have correct format&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"^arn:aws:s3:::"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_arn must be a valid S3 ARN"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Relationships between outputs must hold&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ARN must include the bucket ID"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Users can depend on your outputs without surprises. Breaking changes fail immediately. Your interface is contractual, not aspirational.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Audit Your Examples
&lt;/h3&gt;

&lt;p&gt;You probably have them already. List them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic usage&lt;/li&gt;
&lt;li&gt;Common variations (encryption, logging, versioning)&lt;/li&gt;
&lt;li&gt;Advanced scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Create Test Files
&lt;/h3&gt;

&lt;p&gt;For each example, create a corresponding test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;examples/basic/main.tf              → tests/basic_example.tftest.hcl
examples/with-versioning/main.tf    → tests/versioning_example.tftest.hcl
examples/with-lifecycle/main.tf     → tests/lifecycle_example.tftest.hcl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Write One Assertion Per Test
&lt;/h3&gt;

&lt;p&gt;Start simple. What should succeed?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket should be created"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Run Locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/basic_example.tftest.hcl ... pass
tests/versioning_example.tftest.hcl ... pass
tests/lifecycle_example.tftest.hcl ... pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Add to CI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validate Examples&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform test -verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or output as JUnit XML for CI integrations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-junit-xml&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test-results.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Repeat
&lt;/h3&gt;

&lt;p&gt;Add one test at a time. No rush. Each test prevents one class of future bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For users:&lt;/strong&gt; Your examples work. When someone follows your docs, they succeed. No more "this worked in the readme but doesn't work for me" frustration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For maintainers:&lt;/strong&gt; One source of truth. When you refactor, tests fail immediately if examples break. No silent drift. You catch it in CI, not in user support tickets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For organizations:&lt;/strong&gt; Standardized pattern across all modules. Examples aren't optional documentation—they're testable specifications. Teams can onboard by reading examples. Governance becomes "here's the secure, tested way to use this."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Stop maintaining your examples and tests separately. They're the same thing. Point your tests at your examples directly. Let Terraform validate them on every commit.&lt;/p&gt;

&lt;p&gt;Your examples ARE your tests. Your tests ARE your documentation. This isn't a new concept—it's convergence.&lt;/p&gt;

&lt;p&gt;Start today: Pick one example. Write one test that validates it. Run &lt;code&gt;terraform test&lt;/code&gt;. Watch it work. That's the entire pattern.&lt;/p&gt;

&lt;p&gt;Everything else is just repetition.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/terraform/language/tests" rel="noopener noreferrer"&gt;Terraform Testing Language Documentation&lt;/a&gt; - Official guide to writing tests in Terraform&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/terraform/cli/commands/test" rel="noopener noreferrer"&gt;Terraform Test Command (CLI)&lt;/a&gt; - Reference for &lt;code&gt;terraform test&lt;/code&gt; command and options&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/terraform/registry/modules/publish" rel="noopener noreferrer"&gt;Terraform Registry Module Standards&lt;/a&gt; - Best practices for publishing modules with examples&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>testing</category>
    </item>
    <item>
      <title>Your Terraform Examples Are Broken (And You Don't Know It Yet)</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Tue, 20 Jan 2026 07:34:22 +0000</pubDate>
      <link>https://forem.com/jverhoeks/your-terraform-examples-are-broken-and-you-dont-know-it-yet-4ine</link>
      <guid>https://forem.com/jverhoeks/your-terraform-examples-are-broken-and-you-dont-know-it-yet-4ine</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Stop maintaining separate examples and tests. Test your examples directly. One source of truth. Your docs stay correct automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You publish an example in your module docs. Users follow it. Six months later, you refactor your module. The example breaks. But you don't know until someone opens an issue.&lt;/p&gt;

&lt;p&gt;This happens because: &lt;strong&gt;documentation lives in &lt;code&gt;examples/&lt;/code&gt;, tests live in &lt;code&gt;tests/&lt;/code&gt;, and they drift apart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With Terraform's native testing (1.6+), there's a better way. Stop writing your examples separately from your tests. Make every example self-validating.&lt;/p&gt;

&lt;p&gt;This post shows how to do it—and why it's a game-changer for module maintainers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Foundation (Level 200)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Traditional Problem
&lt;/h3&gt;

&lt;p&gt;You've built an S3 module with three examples:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Basic usage&lt;/strong&gt; - Just create a bucket with defaults&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With versioning&lt;/strong&gt; - Add version tracking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With lifecycle policies&lt;/strong&gt; - Add archival and cleanup&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write examples in &lt;code&gt;examples/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Write tests in &lt;code&gt;tests/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hope they stay in sync&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They don't. Ever. You refactor the module's variable names. The examples get updated. The tests... don't. Your CI passes. Your examples fail when users try them. Good luck debugging why your own documentation doesn't work.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Changed: Terraform Testing Framework
&lt;/h3&gt;

&lt;p&gt;Terraform 1.6+ introduced a native testing framework that lets you write tests directly in HCL. This is significant because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No extra tools&lt;/strong&gt; - Tests are HCL. No external frameworks, no separate languages. Just Terraform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real resource testing&lt;/strong&gt; - Tests actually create and validate resources in your test environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD ready&lt;/strong&gt; - Run with &lt;code&gt;terraform test&lt;/code&gt;, output as JUnit XML with &lt;code&gt;-junit-xml=&amp;lt;file&amp;gt;&lt;/code&gt;, and integrate into any CI platform natively.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Insight: Stop Duplicating
&lt;/h3&gt;

&lt;p&gt;Your examples ARE tests. Why maintain them separately?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (the painful way):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;examples/basic/main.tf
examples/with-versioning/main.tf
tests/basic_test.tf
tests/versioning_test.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They drift. You maintain two separate code bases. Neither stays in sync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After (one source of truth):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;examples/basic/main.tf
examples/with-versioning/main.tf
tests/basic_example.tftest.hcl  ← tests the example directly
tests/versioning_example.tftest.hcl  ← tests the example directly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same example. Tested every time. Always works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here's How It Works
&lt;/h3&gt;

&lt;p&gt;Your example (the user-facing documentation):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# examples/basic/main.tf&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../"&lt;/span&gt;

  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-example-bucket"&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your test (validates that same example):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/basic_example.tftest.hcl&lt;/span&gt;
&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"basic_example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;  &lt;span class="c1"&gt;# Test the example directly&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket ID should not be empty"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"my-example-bucket"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket should be created with correct name"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No duplication. The test validates your actual example code. When your module changes, the test immediately fails if the example breaks. You catch it before users do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two Testing Approaches:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Integration Testing&lt;/strong&gt; (default with &lt;code&gt;command = apply&lt;/code&gt;): Creates actual infrastructure, validates real resources work as expected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit Testing&lt;/strong&gt; (with &lt;code&gt;command = plan&lt;/code&gt;): Only validates the plan output without provisioning resources—faster, cheaper, no cleanup needed&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 2: Advanced Patterns (Level 400)
&lt;/h2&gt;

&lt;p&gt;Once you've got the basic idea, here's what powerful teams do with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 1: Multi-Stage Example Testing
&lt;/h3&gt;

&lt;p&gt;Users learn best by progression: basic → intermediate → advanced. Test each stage independently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/progression.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"stage_1_basic"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versioning_enabled&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Basic example should not have versioning"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"stage_2_with_versioning"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/with-versioning"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versioning_enabled&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Versioning example should enable versioning"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"stage_3_complete"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/lifecycle-tiered-lifecycle"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Validate the complete configuration works end-to-end&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versioning_enabled&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Complete example should have versioning"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Complete example should have lifecycle rules"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Complete example should define at least one lifecycle rule"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result: each example is independently validated, progression is guaranteed, users have a safe learning path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 2: Testing Configuration Variations
&lt;/h3&gt;

&lt;p&gt;Your module supports multiple encryption options. Instead of one bloated example, keep examples clean and test variations separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/encryption_variations.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;enable_default_encryption&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;enable_kms_encryption&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"with_default_encryption"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;enable_default_encryption&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;enable_kms_encryption&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encryption_algorithm&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"AES256"&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Should use default S3 encryption"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"with_kms_encryption"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;enable_default_encryption&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="nx"&gt;enable_kms_encryption&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encryption_algorithm&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"aws:kms"&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Should use KMS encryption"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean examples. Comprehensive test coverage. No duplication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 3: Catch Failures Fast
&lt;/h3&gt;

&lt;p&gt;Your module should reject invalid inputs. Test exactly what should fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/validation_constraints.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"invalid_bucket_name_rejected"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"INVALID-UPPERCASE"&lt;/span&gt;  &lt;span class="c1"&gt;# S3 buckets must be lowercase&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;expect_failures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"reserved_name_rejected"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-reserved-bucket"&lt;/span&gt;  &lt;span class="c1"&gt;# Reserved AWS name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;expect_failures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pattern 4: Integration Testing
&lt;/h3&gt;

&lt;p&gt;Show users how your module works with other modules (like IAM policies):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# examples/with-iam-policy/main.tf&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../../"&lt;/span&gt;

  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# The example also shows how to use this bucket with IAM&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3_access_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./iam-policy"&lt;/span&gt;

  &lt;span class="nx"&gt;bucket_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"bucket_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"access_policy_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_access_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policy_arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then your test validates the complete picture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/iam_integration.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"with_iam_integration"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/with-iam-policy"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"integration-test-bucket"&lt;/span&gt;
    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket should be created"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_access_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IAM policy should be created"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Verify the policy references the correct bucket&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_access_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policy_document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IAM policy must reference the bucket ARN"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pattern 5: Test-First Examples
&lt;/h3&gt;

&lt;p&gt;Write the test first (your spec). The example implements exactly what the test demands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/spec.tftest.hcl - This IS the specification&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"example_secure_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/secure"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# These assertions ARE the specification&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versioning_enabled&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SPEC: Versioning must be enabled for secure bucket"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_access_blocked&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SPEC: Public access must be blocked for secure bucket"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logging_enabled&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SPEC: Access logging must be enabled for secure bucket"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test drives the example. Zero ambiguity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 6: Lock Down Your Output Contracts
&lt;/h3&gt;

&lt;p&gt;Users depend on your outputs. Make sure they're predictable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/output_contracts.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"output_structure"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Validate output types&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_id output must exist"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_arn output must exist"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_region output must exist"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Validate output formats&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"^arn:aws:s3:::"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_arn output must be a valid S3 ARN"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Validate consistency between outputs&lt;/span&gt;
  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_arn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bucket_arn must include the bucket region"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now users can safely depend on your outputs without surprises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 7: Catch Backwards Incompatibility Before Release
&lt;/h3&gt;

&lt;p&gt;Test that your examples work across versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/version_compatibility.tftest.hcl&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"version_1_basic"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# This documents what v1 of the module supported&lt;/span&gt;
  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test-bucket"&lt;/span&gt;
    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"v1 API: Basic example should work"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"version_2_extended_options"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/with-extended-options"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# v2 added more configuration options&lt;/span&gt;
  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test-bucket-v2"&lt;/span&gt;
    &lt;span class="nx"&gt;environment&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
    &lt;span class="nx"&gt;enable_access_logging&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;enable_server_side_encryption&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logging_enabled&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"v2 API: Extended options should work"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;"backwards_compatibility"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;

  &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./examples/basic"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Ensure v1 examples still work with v2&lt;/span&gt;
  &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test-bucket"&lt;/span&gt;
    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"v2: Must maintain backwards compatibility with v1 examples"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Getting Started (It's Simple)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: List Your Examples
&lt;/h3&gt;

&lt;p&gt;You probably already have them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic usage&lt;/li&gt;
&lt;li&gt;Common variations (encryption, logging, versioning)&lt;/li&gt;
&lt;li&gt;Advanced scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Create Test Files
&lt;/h3&gt;

&lt;p&gt;For each example, create a test that validates it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;examples/basic/main.tf          →  tests/basic_example.tftest.hcl
examples/with-versioning/main.tf  →  tests/versioning_example.tftest.hcl
examples/with-lifecycle/main.tf  →  tests/lifecycle_example.tftest.hcl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Write Assertions
&lt;/h3&gt;

&lt;p&gt;For each test, define what success looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_id&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bucket should be created"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Run Locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Add to CI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validate Examples&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform test -verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or output as JUnit XML for CI integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-junit-xml&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test-results.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your CI platform (GitHub Actions, GitLab CI, Jenkins, etc.) can parse the JUnit XML and display results natively.&lt;/p&gt;

&lt;p&gt;Other useful flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-verbose&lt;/code&gt; - Shows plan/state details for debugging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-json&lt;/code&gt; - Machine-readable JSON output&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-parallelism=&amp;lt;n&amp;gt;&lt;/code&gt; - Run multiple tests in parallel (default: 10)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-filter=testfile&lt;/code&gt; - Run specific test files only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Done. Every example is tested on every commit, and results integrate seamlessly with your CI/CD platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For users:&lt;/strong&gt; Examples that actually work. No more "this is the docs version, not the current version" frustration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For maintainers:&lt;/strong&gt; One source of truth. No sync headaches. Confidence that refactoring won't break users. Your tests ARE your documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For organizations:&lt;/strong&gt; Standardized pattern across all modules. Onboarding happens through examples. Governance becomes "here's the secure way to use this." Quality is measurable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Stop maintaining two versions of the truth. Your examples can be your tests.&lt;/p&gt;

&lt;p&gt;Every example in your registry should be tested. Every test should demonstrate real usage. This isn't a new concept—it's convergence. Documentation and validation become the same thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start today:&lt;/strong&gt; Pick one example. Write one test that validates it. Run &lt;code&gt;terraform test&lt;/code&gt;. Watch it work. Then do the next one. That's it.&lt;/p&gt;

&lt;p&gt;The best part? You're not choosing between good examples OR good tests anymore. Every example becomes a test, and every test becomes documentation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/terraform/language/tests" rel="noopener noreferrer"&gt;Terraform Testing Language Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/terraform/cli/commands/test" rel="noopener noreferrer"&gt;Terraform Test Command (CLI)&lt;/a&gt; - includes JUnit XML output&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/terraform/registry/modules/publish" rel="noopener noreferrer"&gt;Terraform Registry Module Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>testing</category>
    </item>
    <item>
      <title>Scaling Terraform Across many Teams: A Native Framework for Platform Engineering</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Mon, 12 Jan 2026 16:34:01 +0000</pubDate>
      <link>https://forem.com/jverhoeks/-scaling-terraform-across-many-teams-a-native-framework-for-platform-engineering-3n0b</link>
      <guid>https://forem.com/jverhoeks/-scaling-terraform-across-many-teams-a-native-framework-for-platform-engineering-3n0b</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR:
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A pure Terraform framework that lets 50+ teams self-service infrastructure by writing simple &lt;code&gt;.tfvars&lt;/code&gt; files while the platform team manages opinionated "building blocks." Smart lookups (&lt;code&gt;s3:bucket_name&lt;/code&gt;) enable cross-resource references. When patterns improve, automated scripts generate PRs for all teams—they review &lt;code&gt;terraform plan&lt;/code&gt; and inherit improvements without code changes. 85%+ boilerplate reduction, zero preprocessing, fully compatible with Terraform Cloud.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This blog post documents how a platform engineering team built a Terraform framework that scales to 50+ application teams with mixed skill levels—enabling fast, self-service infrastructure deployment while maintaining governance and security standards.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│   50+ Teams     │      │    Platform     │      │    Patterns     │
│ Write Simple    │─────&amp;gt;│    Manages      │─────&amp;gt;│    Improve      │
│     tfvars      │      │ Building Blocks │      │   Over Time     │
└─────────────────┘      └─────────────────┘      └─────────────────┘
                                │                           │
                                │                           ▼
                                │                  ┌─────────────────┐
                                │                  │   Automated     │
                                │                  │   PRs Generated │
                                │                  └─────────────────┘
                                │                           │
                                │                           ▼
                                │                  ┌─────────────────┐
                                │                  │  Teams Review   │
                                │                  │ terraform plan  │
                                │                  └─────────────────┘
                                │                           │
                                │                           ▼
                                │                  ┌─────────────────┐
                                └──────────────────│  Approve &amp;amp; Apply│
                                         (updates) │  Stay Current   │
                                                   └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Challenge:&lt;/strong&gt; Platform teams face an impossible trade-off: let teams write their own Terraform (resulting in inconsistent, outdated implementations) or manually review and update every workload (doesn't scale beyond ~10 teams).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; A native Terraform framework that separates configuration (what teams deploy) from implementation (how it's deployed securely). Application teams write simple &lt;code&gt;.tfvars&lt;/code&gt; files, platform team manages opinionated "building blocks" that evolve over time. When patterns improve (adding VPC, encryption, monitoring), automated scripts generate PRs for all teams—they review terraform plan and approve, inheriting improvements without code changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Innovation:&lt;/strong&gt; Native Terraform "smart lookups" (&lt;code&gt;s3:bucket_name&lt;/code&gt;, &lt;code&gt;lambda:function_name&lt;/code&gt;) allow cross-resource references while maintaining the separation. No preprocessing, no code generation—pure Terraform compatible with standard tooling and Terraform Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Target Audiences
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform Engineers&lt;/strong&gt;: Detailed implementation of the lookup mechanism and building block architecture&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevOps/SRE Teams&lt;/strong&gt;: Comparison with Terragrunt/Terraspace and practical benefits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Architects&lt;/strong&gt;: Strategic value and governance capabilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical Leaders&lt;/strong&gt;: Development velocity improvements and complexity reduction&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. Introduction: Helping Teams Build Faster at Scale
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Opening Hook:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How do you help 50 teams build and deploy infrastructure faster—when they have different levels of AWS and Terraform expertise, need similar-but-not-identical workloads, and your platform team can't manually review and update every project?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Human Challenge: Speed vs. Standards
&lt;/h3&gt;

&lt;p&gt;Picture this familiar scenario:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Organization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;50+ application teams&lt;/strong&gt; building data pipelines, microservices, analytics platforms&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixed skill levels&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;20% have AWS experts who know IAM policies inside-out&lt;/li&gt;
&lt;li&gt;50% are competent with Terraform but learning AWS services&lt;/li&gt;
&lt;li&gt;30% are new to both, just want to deploy their application&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Platform/DevOps team of 5-10 people&lt;/strong&gt; responsible for:

&lt;ul&gt;
&lt;li&gt;Cloud governance and security&lt;/li&gt;
&lt;li&gt;Cost optimization&lt;/li&gt;
&lt;li&gt;Compliance and best practices&lt;/li&gt;
&lt;li&gt;Supporting all those teams&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What Application Teams Want:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deploy fast&lt;/strong&gt;: Days, not weeks of waiting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-service&lt;/strong&gt;: Don't wait for platform team approval on every change&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus on their app&lt;/strong&gt;: Not become AWS/Terraform experts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: "Just tell me what works and let me copy it"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What Platform Team Needs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enforce standards&lt;/strong&gt;: Security, tagging, encryption, monitoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale support&lt;/strong&gt;: Can't grow team 1:1 with application teams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous improvement&lt;/strong&gt;: Patterns evolve as we learn&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevent drift&lt;/strong&gt;: All workloads stay current with best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Core Problem: Similar Workloads, Different Implementations
&lt;/h3&gt;

&lt;p&gt;When teams write their own Terraform, you get variations of the same infrastructure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Raw Terraform Resources (Maximum Flexibility, Minimum Maintainability)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Team A writes Lambda in January 2024&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"processor_v1"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.11"&lt;/span&gt;
  &lt;span class="c1"&gt;# ... 50 lines of configuration&lt;/span&gt;
  &lt;span class="c1"&gt;# Missing: VPC config, proper IAM policies, CloudWatch retention&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Team B writes Lambda in March 2024 (learned from Team A's mistakes)&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"processor_v2"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.12"&lt;/span&gt;
  &lt;span class="c1"&gt;# ... 80 lines of configuration&lt;/span&gt;
  &lt;span class="c1"&gt;# Now includes: VPC, better IAM, but still missing X-Ray tracing&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Team C writes Lambda in June 2024 (organization learned best practices)&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"processor_v3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.13"&lt;/span&gt;
  &lt;span class="c1"&gt;# ... 120 lines of configuration&lt;/span&gt;
  &lt;span class="c1"&gt;# All best practices: VPC, IAM, X-Ray, proper logging, tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Problems:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent implementations&lt;/strong&gt;: 50 workloads = 50 slightly different Lambda configurations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge doesn't propagate&lt;/strong&gt;: Teams A and B don't benefit from improvements learned by Team C&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backporting is impossible&lt;/strong&gt;: How do you update 50 workloads when security requires KMS encryption?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy-paste culture&lt;/strong&gt;: Teams copy from each other, propagating old patterns and bugs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expertise silos&lt;/strong&gt;: Only AWS experts can write correct infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Standard Terraform Modules (Better Reuse, Still Hard to Evolve)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Using terraform-aws-modules/lambda/aws&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-aws-modules/lambda/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"4.0.0"&lt;/span&gt;

  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
  &lt;span class="c1"&gt;# ... still 40+ lines of configuration&lt;/span&gt;
  &lt;span class="c1"&gt;# Better: module handles some best practices&lt;/span&gt;
  &lt;span class="c1"&gt;# Problem: upgrading 50 workloads from v4.0.0 → v5.0.0 is manual work&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Problems:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version sprawl&lt;/strong&gt;: Workloads stuck on different module versions (v3.2, v4.0, v4.5, v5.0)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breaking changes&lt;/strong&gt;: Module updates require testing every workload&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration drift&lt;/strong&gt;: Each team configures modules differently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited abstraction&lt;/strong&gt;: Still requires deep AWS knowledge to use correctly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual upgrades&lt;/strong&gt;: Someone has to update 50 PRs when a new version releases&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Real Challenge: N×N Complexity
&lt;/h3&gt;

&lt;p&gt;As you improve your infrastructure patterns over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You learn Lambda should use VPC → Need to update 50 workloads&lt;/li&gt;
&lt;li&gt;Security requires KMS encryption → Need to update 50 workloads&lt;/li&gt;
&lt;li&gt;Compliance requires specific tags → Need to update 50 workloads&lt;/li&gt;
&lt;li&gt;New AWS best practice emerges → Need to update 50 workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The math is brutal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50 workloads × 10 resource types × 5 improvements per year = &lt;strong&gt;2,500 manual updates&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Each update risks breaking something&lt;/li&gt;
&lt;li&gt;Each workload drifts further from best practices&lt;/li&gt;
&lt;li&gt;Teams become afraid to improve shared patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Our Solution: True Separation of Code and Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Insight:&lt;/strong&gt; What if we could update &lt;strong&gt;how&lt;/strong&gt; infrastructure is created without touching &lt;strong&gt;what&lt;/strong&gt; infrastructure exists?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Team writes configuration ONCE (2024)&lt;/span&gt;
&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
    &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.13"&lt;/span&gt;
    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"raw_data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Behind the scenes (managed by platform team):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;January 2024: Lambda building block v1.0 (basic implementation)&lt;/li&gt;
&lt;li&gt;March 2024: Lambda building block v1.5 (adds VPC, better IAM)&lt;/li&gt;
&lt;li&gt;June 2024: Lambda building block v2.0 (adds X-Ray, proper logging)&lt;/li&gt;
&lt;li&gt;September 2024: Lambda building block v2.5 (adds permission boundaries)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The team's configuration never changes.&lt;/strong&gt; The platform team updates the building block implementation, and all 50 workloads automatically get improvements on next &lt;code&gt;terraform apply&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This Framework Achieves:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Configuration (what) lives in tfvars, implementation (how) lives in building blocks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Improvement&lt;/strong&gt;: Platform team evolves patterns without breaking workloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Backporting&lt;/strong&gt;: Workloads automatically inherit improvements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintained References&lt;/strong&gt;: Terraform's powerful dependency graph still works (via smart lookups)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escape Hatch&lt;/strong&gt;: Teams can still use raw Terraform resources when needed for edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Innovation:&lt;/strong&gt;&lt;br&gt;
A pure Terraform framework that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses colon-separated syntax (&lt;code&gt;s3:bucket_name&lt;/code&gt;) for resource references&lt;/li&gt;
&lt;li&gt;Resolves lookups dynamically using native Terraform expressions&lt;/li&gt;
&lt;li&gt;Abstracts AWS complexity through opinionated building blocks&lt;/li&gt;
&lt;li&gt;Works seamlessly with Terraform Cloud and standard workflows&lt;/li&gt;
&lt;li&gt;Updates centrally but applies individually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Coverage:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles 90-95% of common workload patterns through building blocks&lt;/li&gt;
&lt;li&gt;Allows raw Terraform resources alongside building blocks for edge cases&lt;/li&gt;
&lt;li&gt;Manages N×N complexity (lookups between all resource types)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Result:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platform team maintains the framework (1 codebase)&lt;/li&gt;
&lt;li&gt;50 teams write simple configurations (50 tfvars files)&lt;/li&gt;
&lt;li&gt;Everyone benefits from continuous improvement&lt;/li&gt;
&lt;li&gt;No preprocessing, no code generation, pure Terraform&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Lifecycle Management: Keeping Up With Scale
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Separation Strategy:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The framework separates two concerns that evolve at different speeds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configuration (Team-Owned)&lt;/strong&gt;: What workload resources exist&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lives in team repositories as &lt;code&gt;.tfvars&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Teams control: which Lambda, what S3 buckets, environment variables&lt;/li&gt;
&lt;li&gt;Changes infrequently (when application requirements change)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation (Platform-Owned)&lt;/strong&gt;: How resources are created&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lives in blueprint repository as &lt;code&gt;managed_by_dp_*.tf&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Platform controls: security policies, naming, encryption, monitoring&lt;/li&gt;
&lt;li&gt;Changes frequently (as patterns improve)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Update Process:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the platform team improves patterns (add VPC support, update KMS policies, new monitoring):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Platform team's workflow&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;blueprint-repository
&lt;span class="c"&gt;# Update building block versions, add new features&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: add X-Ray tracing to Lambda building block"&lt;/span&gt;

&lt;span class="c"&gt;# Generate PRs for all 50 team repositories&lt;/span&gt;
./tools/repo_updater.py &lt;span class="nt"&gt;--update-all-teams&lt;/span&gt;

&lt;span class="c"&gt;# Result: 50 automated PRs created&lt;/span&gt;
&lt;span class="c"&gt;# Each PR updates only managed_by_dp_*.tf files&lt;/span&gt;
&lt;span class="c"&gt;# Teams' tfvars files are NEVER touched&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Team's Approval Workflow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Team receives automated PR: "Update platform code to v2.5"&lt;/span&gt;
&lt;span class="c"&gt;# PR shows ONLY changes to managed_by_dp_*.tf files&lt;/span&gt;
&lt;span class="c"&gt;# Team's _project.auto.tfvars is unchanged&lt;/span&gt;

&lt;span class="c"&gt;# Team reviews terraform plan in PR comments&lt;/span&gt;
terraform plan
&lt;span class="c"&gt;# Shows: "Lambda function will be updated in-place"&lt;/span&gt;
&lt;span class="c"&gt;#        "  + vpc_config { ... }"  (new VPC configuration added)&lt;/span&gt;

&lt;span class="c"&gt;# Team approves and merges&lt;/span&gt;
&lt;span class="c"&gt;# Terraform Cloud runs terraform apply&lt;/span&gt;
&lt;span class="c"&gt;# Workload gets new feature automatically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Math Works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Without this approach&lt;/strong&gt;: 50 teams × 10 resource types × 5 improvements/year = 2,500 manual updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With this approach&lt;/strong&gt;: 1 platform team × 1 script × 50 automated PRs = 50 team approvals (30 minutes each)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Platform team scales from:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10 person-weeks of manual updates (touching every team's code)&lt;/li&gt;
&lt;li&gt;To: 2 person-days (writing script, reviewing automation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Teams benefit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receive improvements without doing any work&lt;/li&gt;
&lt;li&gt;Review and approve changes (maintain control)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;terraform plan&lt;/code&gt; shows exactly what changes&lt;/li&gt;
&lt;li&gt;Rollback is just reverting the PR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Principles:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Teams own configuration&lt;/strong&gt;: Platform can't break their workload definitions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform owns implementation&lt;/strong&gt;: Teams benefit from continuous improvement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation bridges scale&lt;/strong&gt;: Scripts generate PRs, teams approve&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform validates&lt;/strong&gt;: Standard &lt;code&gt;plan&lt;/code&gt; shows changes before apply&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradual rollout&lt;/strong&gt;: Platform can update 5 teams first, validate, then roll to 45 more&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This lifecycle separation is what makes the framework sustainable at scale—platform team doesn't become a bottleneck, teams maintain velocity, everyone stays current with best practices.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Section 1:&lt;/strong&gt; Platform teams face N×N complexity when updating 50+ workloads with infrastructure improvements. This framework separates configuration (team-owned tfvars) from implementation (platform-owned building blocks). Automated PR generation scales updates: platform improves once, all teams inherit via &lt;code&gt;terraform plan&lt;/code&gt; review and approval. Reduces 2,500 manual updates/year to 50 automated PRs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. Architecture Overview
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────┐
│                Layer 1: tf-common (Shared Foundation)              │
├────────────────────────────────────────────────────────────────────┤
│  • Provider Config          • Naming Conventions                   │
│  • VPC/Subnet Data Sources  • Platform Info Provider               │
└──────────────────┬─────────────────────────────────────────────────┘
                   │
                   ▼
┌────────────────────────────────────────────────────────────────────┐
│              Layer 2: tf-default (Account-Level)                   │
├────────────────────────────────────────────────────────────────────┤
│  • KMS Infrastructure Key   • S3 Code/Logging Buckets              │
│  • IAM Admin Roles          • CloudTrail Data                      │
└──────────────────┬────────────────┬────────────────────────────────┘
                   │                │
                   │ (Shared KMS)   │ (Code Storage)
                   ▼                ▼
┌────────────────────────────────────────────────────────────────────┐
│            Layer 3: tf-project (Application-Level)                 │
├────────────────────────────────────────────────────────────────────┤
│  • KMS Data Key             • S3 Data Buckets                      │
│  • Lambda/Glue/Fargate      • RDS/Redshift/DynamoDB                │
└────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The Three-Layer System
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: tf-common (Shared Foundation)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provider configuration&lt;/li&gt;
&lt;li&gt;Naming conventions and context management&lt;/li&gt;
&lt;li&gt;Shared data sources (VPC, subnets, IAM roles)&lt;/li&gt;
&lt;li&gt;Platform Information Provider (PIP) integration&lt;/li&gt;
&lt;li&gt;Used by ALL workloads (updated centrally)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: tf-default (Account-Level Resources)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 code/logging buckets&lt;/li&gt;
&lt;li&gt;KMS infrastructure keys&lt;/li&gt;
&lt;li&gt;Lake Formation settings&lt;/li&gt;
&lt;li&gt;IAM admin roles&lt;/li&gt;
&lt;li&gt;CloudTrail data logging&lt;/li&gt;
&lt;li&gt;Deployed ONCE per AWS account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 3: tf-project (Application Resources)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 data buckets&lt;/li&gt;
&lt;li&gt;Lambda functions, Glue jobs&lt;/li&gt;
&lt;li&gt;RDS, Redshift, DynamoDB databases&lt;/li&gt;
&lt;li&gt;Fargate containers&lt;/li&gt;
&lt;li&gt;Application-specific KMS keys&lt;/li&gt;
&lt;li&gt;Deployed MULTIPLE times per account (one per workload)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Composition via Symlinks:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;examples/my-workload/
├── _data.tf                    # User-owned: environment config
├── _project.auto.tfvars        # User-owned: workload definition
├── managed_by_dp_common_*.tf -&amp;gt; ../../tf-common/terraform/
├── managed_by_dp_default_*.tf -&amp;gt; ../../tf-default/terraform/
└── managed_by_dp_project_*.tf -&amp;gt; ../../tf-project/terraform/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a complete, runnable Terraform project where &lt;code&gt;terraform plan/apply&lt;/code&gt; work directly.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. The Smart Lookup Innovation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Core Concept
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Traditional Terraform:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;BUCKET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:s3:::company-prod-data-raw-bucket-a1b2c3"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;policy_json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:s3:::company-prod-data-raw-bucket-a1b2c3/*"&lt;/span&gt;
      &lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With Smart Lookups:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;raw_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"raw"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;BUCKET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:raw_data"&lt;/span&gt;  &lt;span class="c1"&gt;# Resolves to bucket name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"raw_data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# Resolves to full ARN + generates IAM policy&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How It Works: Pure Terraform Magic
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Location:&lt;/strong&gt; &lt;code&gt;tf-project/terraform/managed_by_dp_project_lookup.tf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Build Lookup Maps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The system creates hierarchical lookup maps after resources are created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;lookup_arn_base&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_arns&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"s3_read"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"s3_write"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"gluejob"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;glue_jobs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;glue_jobs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"secret_read"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"dynamodb_read"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb_databases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;lookup_id_base&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_ids&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"secret"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="s2"&gt;"dynamodb"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb_databases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Resolve References Dynamically&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In building block modules (e.g., &lt;code&gt;managed_by_dp_project_lambda.tf&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_functions&lt;/span&gt;

  &lt;span class="c1"&gt;# Environment variables with smart lookup&lt;/span&gt;
  &lt;span class="nx"&gt;environments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_id_lambda&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
        &lt;span class="nx"&gt;item&lt;/span&gt;  &lt;span class="c1"&gt;# Fallback to literal value if not a lookup&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Permissions with smart lookup&lt;/span&gt;
  &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="err"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="c1"&gt;# Check if it's "type:name" format&lt;/span&gt;
        &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_perm_lambda&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
            &lt;span class="nx"&gt;item&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_perm_lambda&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# Infer type from permission category&lt;/span&gt;
            &lt;span class="nx"&gt;item&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Magic:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;split(":", "s3:mybucket")&lt;/code&gt; → &lt;code&gt;["s3", "mybucket"]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;local.lookup_id_lambda["s3"]["mybucket"]&lt;/code&gt; → actual bucket name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;local.lookup_perm_lambda["s3_read"]["mybucket"]&lt;/code&gt; → actual bucket ARN&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Building Blocks Generate IAM Policies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building block modules (from Terraform Cloud private registry) automatically generate IAM policies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app.terraform.io/org/buildingblock-lambda/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"3.2.0"&lt;/span&gt;

  &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::bucket1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:s3:::bucket2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;create_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  &lt;span class="c1"&gt;# Automatically generates IAM role + policy&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the building block, it generates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sid&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S3Read"&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"s3:GetBucket*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"s3:List*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"${arn}/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Supported Lookup Types
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;For Environment Variables (IDs/Names):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;s3:bucket_name&lt;/code&gt; → S3 bucket name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secret:secret_name&lt;/code&gt; → Secrets Manager secret ID&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dynamodb:table_name&lt;/code&gt; → DynamoDB table name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;athena:workgroup_name&lt;/code&gt; → Athena workgroup name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prefix:suffix&lt;/code&gt; → Injects naming prefix + suffix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For Permissions (ARNs):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;s3_read:bucket&lt;/code&gt; / &lt;code&gt;s3_write:bucket&lt;/code&gt; → S3 bucket ARN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gluejob:job_name&lt;/code&gt; → Glue job ARN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gluedb:database_name&lt;/code&gt; → Glue database name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secret_read:secret_name&lt;/code&gt; → Secrets Manager ARN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dynamodb_read:table&lt;/code&gt; / &lt;code&gt;dynamodb_write:table&lt;/code&gt; → DynamoDB ARN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sqs_read:queue&lt;/code&gt; / &lt;code&gt;sqs_send:queue&lt;/code&gt; → SQS queue ARN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sns_pub:topic&lt;/code&gt; → SNS topic ARN&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cross-Account References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;acct_prod_glue_tables&lt;/code&gt; → All Glue tables in production account&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;acct_dev_kms_all_keys&lt;/code&gt; → All KMS keys in dev account
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Team tfvars          Lookup Tables       Building Block         AWS Resources
     │                     │                     │                     │
     │ environment =       │                     │                     │
     │ {BUCKET="s3:raw"}   │                     │                     │
     ├────────────────────&amp;gt;│                     │                     │
     │                     │ split(":", "s3:raw")│                     │
     │                     │ → ["s3", "raw"]     │                     │
     │                     │                     │                     │
     │                     │ lookup_id_lambda    │                     │
     │                     │ ["s3"]["raw"] →     │                     │
     │                     │ "company...-raw"    │                     │
     │                     ├────────────────────&amp;gt;│                     │
     │                     │  resolved name      │                     │
     │                     │                     │ Create Lambda with  │
     │                     │                     │ env BUCKET=         │
     │                     │                     │ "company...-raw"    │
     │                     │                     ├────────────────────&amp;gt;│
     │                     │                     │                     │
     │ permissions =       │                     │                     │
     │ {s3_read=["raw"]}   │                     │                     │
     ├────────────────────&amp;gt;│                     │                     │
     │                     │ lookup_perm_lambda  │                     │
     │                     │ ["s3_read"]["raw"]  │                     │
     │                     │ → arn:aws:s3:::...  │                     │
     │                     ├────────────────────&amp;gt;│                     │
     │                     │  resolved ARN       │                     │
     │                     │                     │ Generate IAM policy │
     │                     │                     │ with S3 read actions│
     │                     │                     │                     │
     │                     │                     │ Attach policy to    │
     │                     │                     │ Lambda role         │
     │                     │                     ├────────────────────&amp;gt;│
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Section 3:&lt;/strong&gt; Smart lookups use colon syntax (&lt;code&gt;s3:bucket_name&lt;/code&gt;) resolved via native Terraform &lt;code&gt;split()&lt;/code&gt; and lookup maps. No preprocessing—pure Terraform expressions. Lookup tables are built after resources are created, then referenced by building blocks to resolve environment variables (IDs) and permissions (ARNs). Building blocks auto-generate IAM policies from the resolved ARNs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  4. Building Block Abstraction
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Philosophy
&lt;/h4&gt;

&lt;p&gt;Building blocks are opinionated Terraform modules that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enforce organizational standards&lt;/strong&gt; (naming, tagging, encryption)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abstract AWS complexity&lt;/strong&gt; (IAM policies, VPC configuration)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provide guardrails&lt;/strong&gt; (prevent common misconfigurations)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable least-privilege by default&lt;/strong&gt; (automatic policy generation)&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Example: S3 Building Block
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;User Configuration (tfvars):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;raw_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"raw"&lt;/span&gt;
    &lt;span class="nx"&gt;backup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;enable_intelligent_tiering&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;processed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processed"&lt;/span&gt;
    &lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"archive_old_data"&lt;/span&gt;
      &lt;span class="nx"&gt;transition_days&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
      &lt;span class="nx"&gt;storage_class&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GLACIER"&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What the Building Block Does:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3_buckets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app.terraform.io/org/buildingblock-s3/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2.1.3"&lt;/span&gt;

  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;

  &lt;span class="c1"&gt;# Standardized naming: &amp;lt;prefix&amp;gt;-&amp;lt;workload&amp;gt;-&amp;lt;application&amp;gt;-&amp;lt;name&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;prefix&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;  &lt;span class="c1"&gt;# e.g., "companyp" (company + production)&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="c1"&gt;# {Env: "prd", Workload: "analytics", Application: "etl"}&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Automatic encryption with workload KMS key&lt;/span&gt;
  &lt;span class="nx"&gt;kms_key_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_data_key_arn&lt;/span&gt;

  &lt;span class="c1"&gt;# Standardized tags (injected automatically)&lt;/span&gt;
  &lt;span class="c1"&gt;# Tags include: Env, Workload, Application, Team, CostCenter, Backup&lt;/span&gt;

  &lt;span class="c1"&gt;# Security defaults&lt;/span&gt;
  &lt;span class="nx"&gt;block_public_access&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;versioning_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="c1"&gt;# User-specified configuration&lt;/span&gt;
  &lt;span class="nx"&gt;backup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backup&lt;/span&gt;
  &lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
  &lt;span class="nx"&gt;enable_intelligent_tiering&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enable_intelligent_tiering&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Generated Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 bucket with predictable name: &lt;code&gt;companyprd-analytics-etl-raw&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;KMS encryption enabled automatically&lt;/li&gt;
&lt;li&gt;Bucket policy restricting to VPC endpoints&lt;/li&gt;
&lt;li&gt;CloudWatch alarms for bucket size&lt;/li&gt;
&lt;li&gt;Backup plan (if &lt;code&gt;backup = true&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;All organizational tags applied&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example: Lambda Building Block
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;User Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data_processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
    &lt;span class="nx"&gt;handler&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;
    &lt;span class="nx"&gt;runtime&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.13"&lt;/span&gt;
    &lt;span class="nx"&gt;memory&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;
    &lt;span class="nx"&gt;timeout&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;
    &lt;span class="nx"&gt;s3_sourcefile&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3_file:lambda_processor.zip"&lt;/span&gt;

    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;INPUT_BUCKET&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:raw_data"&lt;/span&gt;
      &lt;span class="nx"&gt;OUTPUT_BUCKET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:processed"&lt;/span&gt;
      &lt;span class="nx"&gt;SECRET_ID&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"secret:db_creds"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"raw_data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;s3_write&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"processed"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;secret_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"db_creds"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What the Building Block Does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates Lambda function with standardized name&lt;/li&gt;
&lt;li&gt;Generates IAM role automatically&lt;/li&gt;
&lt;li&gt;Generates IAM policy from &lt;code&gt;permissions&lt;/code&gt; map&lt;/li&gt;
&lt;li&gt;Applies permission boundary (security compliance)&lt;/li&gt;
&lt;li&gt;Injects VPC configuration (subnet IDs, security groups)&lt;/li&gt;
&lt;li&gt;Resolves environment variables via lookup tables&lt;/li&gt;
&lt;li&gt;Adds CloudWatch log group with retention policy&lt;/li&gt;
&lt;li&gt;Applies X-Ray tracing&lt;/li&gt;
&lt;li&gt;Adds all organizational tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generated IAM Policy (automatically):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S3Read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetBucket*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:List*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::companyprd-analytics-etl-raw"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::companyprd-analytics-etl-raw/*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S3Write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObject*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObject*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::companyprd-analytics-etl-processed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::companyprd-analytics-etl-processed/*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SecretRead"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"secretsmanager:GetSecretValue"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:secretsmanager:eu-central-1:123456789012:secret:companyprd-analytics-etl-db_creds-a1b2c3"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KMSDecrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"kms:Decrypt"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:kms:eu-central-1:123456789012:key/abcd1234-..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Dual KMS Key Architecture with Tag-Based Permissions
&lt;/h3&gt;

&lt;p&gt;One of the most elegant security features of this framework is its dual KMS key architecture that balances security isolation with operational flexibility.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Two-Key System
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;KMS Infrastructure Key (kms-infra)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope:&lt;/strong&gt; One per AWS account (shared across all workloads in that account)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Created in tf-default (account-level)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Encrypts infrastructure resources (CloudWatch Logs, Secrets Manager, SNS, CloudTrail)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naming:&lt;/strong&gt; &lt;code&gt;${prefix}-${workload}-kms-infra&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;companyp-analytics-kms-infra&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;KMS Data Key (kms-data)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope:&lt;/strong&gt; One per workload (isolated per application)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Created in tf-project (application-level)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Encrypts data resources (S3 buckets, RDS, DynamoDB, Redshift)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naming:&lt;/strong&gt; &lt;code&gt;${prefix}-${workload}-${application}-kms-data&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;companyp-analytics-etl-kms-data&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Why Two Keys?
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Security Isolation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data keys are isolated per workload&lt;/li&gt;
&lt;li&gt;Compromising one workload's data key doesn't expose other workloads' data&lt;/li&gt;
&lt;li&gt;Infrastructure key is shared for operational resources that need account-wide access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Operational Flexibility:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure key allows CloudWatch, monitoring, and logging to work across workloads&lt;/li&gt;
&lt;li&gt;AWS services (Secrets Manager, CloudTrail) can use a single key for account-level operations&lt;/li&gt;
&lt;li&gt;Data keys remain tightly scoped to application resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cost Optimization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure resources share one key (CloudWatch logs from many workloads)&lt;/li&gt;
&lt;li&gt;Only data resources (S3, databases) need separate keys per workload&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Tag-Based Permissions: The Magic Sauce
&lt;/h4&gt;

&lt;p&gt;Instead of explicitly listing every IAM role in the KMS key policy (which creates circular dependencies), the infrastructure key uses &lt;strong&gt;tag-based permissions&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation in &lt;code&gt;managed_by_dp_common_kms_infra.tf&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"kms_infrastructure"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-aws-modules/kms/aws"&lt;/span&gt;

  &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_deploy&lt;/span&gt;  &lt;span class="c1"&gt;# Only in default/account deployment&lt;/span&gt;

  &lt;span class="nx"&gt;aliases&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"${local.prefix}-${local.context.Workload}-kms-infra"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;key_statements&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tag-workload"&lt;/span&gt;
      &lt;span class="nx"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AWS"&lt;/span&gt;
        &lt;span class="nx"&gt;identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::${account_id}:root"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}]&lt;/span&gt;

      &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"kms:Encrypt*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"kms:Decrypt*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"kms:ReEncrypt*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"kms:GenerateDataKey*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="c1"&gt;# The key condition: any role with matching Workload tag can use this key&lt;/span&gt;
      &lt;span class="nx"&gt;conditions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="nx"&gt;test&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"StringEquals"&lt;/span&gt;
        &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws:PrincipalTag/Workload"&lt;/span&gt;
        &lt;span class="nx"&gt;values&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Workload&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How It Works:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every IAM role created by building blocks gets tagged automatically:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;   &lt;span class="c1"&gt;# Lambda IAM role&lt;/span&gt;
   &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;Workload&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"analytics"&lt;/span&gt;
     &lt;span class="nx"&gt;Application&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"etl"&lt;/span&gt;
     &lt;span class="nx"&gt;Env&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"prd"&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;KMS key policy allows any role with matching &lt;code&gt;Workload&lt;/code&gt; tag:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If role has tag &lt;code&gt;Workload = "analytics"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;And KMS key is for workload &lt;code&gt;analytics&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then role can use the key automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No circular dependencies:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KMS key doesn't need to know about Lambda roles&lt;/li&gt;
&lt;li&gt;Lambda roles don't need to be in KMS key policy&lt;/li&gt;
&lt;li&gt;Tag matching happens at runtime by AWS IAM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Data Key: Explicit Role Lists
&lt;/h4&gt;

&lt;p&gt;The data key uses a different approach with explicit role lists (avoiding circular dependencies through selective inclusion):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation in &lt;code&gt;managed_by_dp_project_kms_data.tf&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"kms_data"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app.terraform.io/org/buildingblock-kms-data/aws"&lt;/span&gt;

  &lt;span class="nx"&gt;key_administrators&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_admins&lt;/span&gt;
  &lt;span class="nx"&gt;key_users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_data_key_users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"extra_roles"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

  &lt;span class="c1"&gt;# Tag-based access for roles with matching tags&lt;/span&gt;
  &lt;span class="nx"&gt;key_user_tag_map&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Workload"&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Workload&lt;/span&gt;
    &lt;span class="s2"&gt;"Application"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Application&lt;/span&gt;
    &lt;span class="s2"&gt;"Env"&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Env&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In &lt;code&gt;managed_by_dp_project_locals.tf&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;kms_data_key_users&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compact&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;# Admin roles (explicitly listed)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::${account_id}:role/${var.role_prefix}-${local.prefix}-DpAdminRole"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;operatorrole_arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transfer_roles&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workflow_roles&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;

  &lt;span class="c1"&gt;# Lambda, Glue, Fargate roles are NOT listed here (would cause cycles)&lt;/span&gt;
  &lt;span class="c1"&gt;# Instead, they're granted access via tag-based permissions&lt;/span&gt;
  &lt;span class="c1"&gt;# See comments in code explaining the circular dependency:&lt;/span&gt;
  &lt;span class="c1"&gt;# [for job in var.glue_jobs : "arn:aws:iam::..."],  # CYCLO ERROR!&lt;/span&gt;
  &lt;span class="c1"&gt;# [for function in var.lambda_functions : "arn:aws:iam::..."],  # CYCLO ERROR!&lt;/span&gt;
&lt;span class="err"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data key also supports tag-based access through &lt;code&gt;key_user_tag_map&lt;/code&gt;, allowing Lambda/Glue/Fargate roles to access it via their tags without being explicitly listed in the policy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Practical Example
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Lambda function needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read encrypted S3 data (data key)&lt;/li&gt;
&lt;li&gt;Write to CloudWatch Logs (infra key)&lt;/li&gt;
&lt;li&gt;Access Secrets Manager secret (infra key)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What Happens:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lambda IAM role is created with tags:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;   &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app-companyp-analytics-etl-lambda-processor"&lt;/span&gt;

     &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;Workload&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"analytics"&lt;/span&gt;
       &lt;span class="nx"&gt;Application&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"etl"&lt;/span&gt;
       &lt;span class="nx"&gt;Env&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"prd"&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lambda can use infrastructure key because:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role has tag &lt;code&gt;Workload = "analytics"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;KMS infra key checks: &lt;code&gt;aws:PrincipalTag/Workload == "analytics"&lt;/code&gt; ✓&lt;/li&gt;
&lt;li&gt;Access granted for CloudWatch Logs, Secrets Manager&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lambda can use data key because:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role has tags &lt;code&gt;Workload = "analytics"&lt;/code&gt; AND &lt;code&gt;Application = "etl"&lt;/code&gt; AND &lt;code&gt;Env = "prd"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;KMS data key checks all three tags match ✓&lt;/li&gt;
&lt;li&gt;Access granted for S3 data encryption/decryption&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lambda CANNOT use another workload's data key:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role has &lt;code&gt;Application = "etl"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Other workload's data key requires &lt;code&gt;Application = "reporting"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tag mismatch ✗&lt;/li&gt;
&lt;li&gt;Access denied&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Benefits of This Architecture
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Automatic Compliance:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every resource is encrypted (mandatory KMS keys injected by building blocks)&lt;/li&gt;
&lt;li&gt;No way to accidentally create unencrypted resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Zero-Touch Security:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers never manage KMS permissions manually&lt;/li&gt;
&lt;li&gt;Building blocks inject the correct KMS key ARN automatically&lt;/li&gt;
&lt;li&gt;Tag propagation handles access control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Workload Isolation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data from different applications is cryptographically separated&lt;/li&gt;
&lt;li&gt;Even with compromised IAM credentials, cross-workload data access is prevented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Solves Circular Dependencies:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KMS keys don't reference IAM roles directly&lt;/li&gt;
&lt;li&gt;IAM roles don't need to be created before KMS keys&lt;/li&gt;
&lt;li&gt;Tag-based conditions evaluated at runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Audit Trail:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudTrail logs show which role (with which tags) accessed which KMS key&lt;/li&gt;
&lt;li&gt;Security teams can verify tag-based access patterns&lt;/li&gt;
&lt;li&gt;Compliance reports show encryption coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Service-Specific Access
&lt;/h4&gt;

&lt;p&gt;The infrastructure key also includes service-specific statements for AWS services:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CloudWatch Logs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;sid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"logs"&lt;/span&gt;
  &lt;span class="nx"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"logs.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"kms:Encrypt*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"kms:Decrypt*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"kms:GenerateDataKey*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;conditions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="nx"&gt;test&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ArnEquals"&lt;/span&gt;
    &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kms:EncryptionContext:aws:logs:arn"&lt;/span&gt;
    &lt;span class="nx"&gt;values&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:logs:${region}:${account}:log-group:*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Secrets Manager:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;sid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"auto-secretsmanager"&lt;/span&gt;
  &lt;span class="nx"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"secretsmanager.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"kms:Encrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"kms:Decrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"kms:GenerateDataKey"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;conditions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kms:ViaService"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"secretsmanager.${region}.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kms:CallerAccount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"${account}"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CloudTrail, SNS, EventBridge:&lt;/strong&gt;&lt;br&gt;
Similar service-specific statements allow these AWS services to use the infrastructure key for their operations.&lt;/p&gt;
&lt;h4&gt;
  
  
  Lookup References
&lt;/h4&gt;

&lt;p&gt;Both keys are available via smart lookups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# In Lambda/Glue/Fargate tfvars - use data key for data encryption&lt;/span&gt;
&lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;kms&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"kms_data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Resolves to workload's data key ARN&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Infrastructure key is injected automatically by building blocks&lt;/span&gt;
&lt;span class="c1"&gt;# (for CloudWatch Logs, environment variable encryption, etc.)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;The dual KMS key architecture demonstrates how thoughtful design can achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Strong encryption and workload isolation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience:&lt;/strong&gt; Zero manual KMS management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Simplicity:&lt;/strong&gt; Tag-based permissions eliminate complexity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance:&lt;/strong&gt; Automatic encryption enforcement across all resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern is a cornerstone of the framework's security model and showcases how infrastructure abstractions can enhance rather than compromise security posture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────┐
│          KMS Infrastructure Key (Account-Level)                  │
├──────────────────────────────────────────────────────────────────┤
│  • One Key Per Account                                           │
│  • Encrypts: CloudWatch Logs, Secrets Manager, SNS, CloudTrail   │
│  • Tag-Based Access: Workload Tag                                │
└────────────────────────────────┬─────────────────────────────────┘
                                 │
                                 │ (Tag Match: Workload)
                                 │
                      ┌──────────┴──────────┐
                      │                     │
                      │    Lambda Role      │
                      │  Tagged with:       │
                      │  • Workload=analytics│
                      │  • Application=etl  │
                      │  • Env=prd          │
                      │                     │
                      └──────────┬──────────┘
                                 │
                                 │ (Tag Match: All 3 Tags)
                                 │
┌────────────────────────────────▼─────────────────────────────────┐
│            KMS Data Key (Workload-Level)                         │
├──────────────────────────────────────────────────────────────────┤
│  • One Key Per Workload                                          │
│  • Encrypts: S3, RDS, DynamoDB, Redshift                         │
│  • Tag-Based Access: Workload + Application + Env                │
└──────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Section 5:&lt;/strong&gt; Dual KMS architecture uses one shared infrastructure key per account (CloudWatch, Secrets Manager) and one data key per workload (S3, databases). Tag-based permissions solve circular dependencies: IAM roles tagged with &lt;code&gt;Workload&lt;/code&gt;/&lt;code&gt;Application&lt;/code&gt;/&lt;code&gt;Env&lt;/code&gt; automatically gain KMS access without being explicitly listed in policies. Infrastructure key checks one tag, data key checks three tags for stronger isolation.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  6. Naming Conventions and Context Propagation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Context System
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Input: Tags Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every workload defines a tags module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"tags"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app.terraform.io/org/tags/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0.0"&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"prd"&lt;/span&gt;
  &lt;span class="nx"&gt;workload&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"analytics"&lt;/span&gt;
  &lt;span class="nx"&gt;application&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"etl"&lt;/span&gt;
  &lt;span class="nx"&gt;team&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"data-engineering@company.com"&lt;/span&gt;
  &lt;span class="nx"&gt;costcenter&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"12345"&lt;/span&gt;
  &lt;span class="nx"&gt;backup&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Daily"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output: Context Map&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Result: {&lt;/span&gt;
&lt;span class="c1"&gt;#   Env: "prd",&lt;/span&gt;
&lt;span class="c1"&gt;#   Workload: "analytics",&lt;/span&gt;
&lt;span class="c1"&gt;#   Application: "etl",&lt;/span&gt;
&lt;span class="c1"&gt;#   Team: "data-engineering@company.com",&lt;/span&gt;
&lt;span class="c1"&gt;#   CostCenter: "12345",&lt;/span&gt;
&lt;span class="c1"&gt;#   Backup: "Daily"&lt;/span&gt;
&lt;span class="c1"&gt;# }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prefix Generation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"company${substr(local.context.Env, 0, 1)}"&lt;/span&gt;
&lt;span class="c1"&gt;# prd → companyp&lt;/span&gt;
&lt;span class="c1"&gt;# sbx → companys&lt;/span&gt;
&lt;span class="c1"&gt;# dev → companyd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resource Naming Pattern&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${prefix}-${workload}-${application}-${resource_name}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 bucket: &lt;code&gt;companyp-analytics-etl-raw&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Lambda: &lt;code&gt;companyp-analytics-etl-processor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Glue job: &lt;code&gt;companyp-analytics-etl-transform&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;IAM role: &lt;code&gt;companyp-analytics-etl-lambda-processor-role&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Predictable&lt;/strong&gt;: Resources can be referenced before creation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discoverable&lt;/strong&gt;: Name reveals environment, workload, and purpose&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliant&lt;/strong&gt;: Meets organizational naming standards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique&lt;/strong&gt;: Prevents naming collisions across teams&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  7. Circular Dependency Resolution Strategies
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Challenge
&lt;/h4&gt;

&lt;p&gt;Terraform dependency graph requires acyclic relationships, but real-world infrastructure often has circular references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda needs IAM role ARN&lt;/li&gt;
&lt;li&gt;IAM role policy needs Lambda ARN for trust policy&lt;/li&gt;
&lt;li&gt;KMS key policy needs Lambda role ARN&lt;/li&gt;
&lt;li&gt;Lambda needs KMS key ARN for environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Strategy 1: Predictive Naming
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Example: Redshift Lookup&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Can't use module.redshift[item].name because it creates a cycle&lt;/span&gt;
&lt;span class="c1"&gt;# CYCLO ERROR! comment in code&lt;/span&gt;
&lt;span class="s2"&gt;"redshift_data"&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redshift_databases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Workload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;item&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of referencing the module output (which creates a dependency), predict the name using the same naming convention.&lt;/p&gt;

&lt;h4&gt;
  
  
  Strategy 2: Two-Phase Deployment
&lt;/h4&gt;

&lt;p&gt;From &lt;code&gt;DEPLOY.md&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"First Terraform apply will fail on a few dependencies. Re-run to finalize."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some circular dependencies are resolved by applying twice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First apply creates base resources&lt;/li&gt;
&lt;li&gt;Some resources fail due to missing dependencies&lt;/li&gt;
&lt;li&gt;Second apply completes configuration&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Strategy 3: Selective KMS Key Users
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;kms_data_key_users&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compact&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::${account_id}:role/${var.role_prefix}-${local.prefix}-DpAdminRole"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;operatorrole_arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transfer_roles&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workflow_roles&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;# These would create cycles - commented out:&lt;/span&gt;
  &lt;span class="c1"&gt;# [for job in var.glue_jobs : "arn:aws:iam::..."],&lt;/span&gt;
  &lt;span class="c1"&gt;# [for function in var.lambda_functions : "arn:aws:iam::..."],&lt;/span&gt;
&lt;span class="err"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;KMS key policies include predictable roles (admin, operator) but NOT Lambda/Glue roles to avoid cycles.&lt;/p&gt;

&lt;h4&gt;
  
  
  Strategy 4: Data Source Lookups (Cross-Workload)
&lt;/h4&gt;

&lt;p&gt;When project workloads need resources from the default workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_deploy&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileexists&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.module}/managed_by_dp_default_s3_code.tf"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_kms_key"&lt;/span&gt; &lt;span class="s2"&gt;"kms_infrastructure"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_deploy&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"alias/${local.prefix}-${local.context.Workload}-kms-infra"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;kms_infrastructure_key_arn&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;coalesce&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_infrastructure&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_arn&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# If default deploy&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_kms_key&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_infrastructure&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;  &lt;span class="c1"&gt;# If project deploy&lt;/span&gt;
&lt;span class="err"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project workloads use data sources to look up infrastructure key by predictable alias.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Real-World Example: Data Pipeline Workload
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Scenario
&lt;/h4&gt;

&lt;p&gt;Build a data pipeline that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ingests raw CSV files from external S3 bucket&lt;/li&gt;
&lt;li&gt;Processes files with Lambda function&lt;/li&gt;
&lt;li&gt;Transforms data with Glue ETL job&lt;/li&gt;
&lt;li&gt;Stores in Redshift for analytics&lt;/li&gt;
&lt;li&gt;Shares Glue catalog with data governance account&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Configuration (tfvars)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Define S3 buckets&lt;/span&gt;
&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"raw"&lt;/span&gt;
    &lt;span class="nx"&gt;backup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"archive_old"&lt;/span&gt;
      &lt;span class="nx"&gt;transition_days&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
      &lt;span class="nx"&gt;storage_class&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GLACIER"&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;processed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processed"&lt;/span&gt;
    &lt;span class="nx"&gt;enable_intelligent_tiering&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Upload Lambda code&lt;/span&gt;
&lt;span class="nx"&gt;s3_source_files&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;processor_code&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda_processor.zip"&lt;/span&gt;
    &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda_functions/processor/code.zip"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;glue_script&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"transform.py"&lt;/span&gt;
    &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"glue_jobs/transform/script.py"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Define secrets&lt;/span&gt;
&lt;span class="nx"&gt;secrets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;redshift_creds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"redshift-credentials"&lt;/span&gt;
    &lt;span class="nx"&gt;secret_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"admin"&lt;/span&gt;
      &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"changeme"&lt;/span&gt;  &lt;span class="c1"&gt;# Should use AWS Secrets Manager UI to set&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Define Glue database&lt;/span&gt;
&lt;span class="nx"&gt;glue_database&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;analytics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"analytics"&lt;/span&gt;
    &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:processed"&lt;/span&gt;
    &lt;span class="nx"&gt;enable_lakeformation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;share_cross_account_ro&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"datagovernance"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Define Lambda processor&lt;/span&gt;
&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;csv_processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"csv-processor"&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Processes incoming CSV files"&lt;/span&gt;
    &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;
    &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.13"&lt;/span&gt;
    &lt;span class="nx"&gt;memory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;
    &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;
    &lt;span class="nx"&gt;s3_sourcefile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3_file:processor_code"&lt;/span&gt;

    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;RAW_BUCKET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:raw"&lt;/span&gt;
      &lt;span class="nx"&gt;PROCESSED_BUCKET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:processed"&lt;/span&gt;
      &lt;span class="nx"&gt;GLUE_DATABASE&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gluedb:analytics"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"raw"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;s3_write&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"processed"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;glue_update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"analytics"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# S3 trigger&lt;/span&gt;
    &lt;span class="nx"&gt;event_source_mapping&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="nx"&gt;event_source_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:raw"&lt;/span&gt;
      &lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:ObjectCreated:*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;filter_prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"incoming/"&lt;/span&gt;
      &lt;span class="nx"&gt;filter_suffix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;".csv"&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Define Glue ETL job&lt;/span&gt;
&lt;span class="nx"&gt;glue_jobs&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"data-transform"&lt;/span&gt;
    &lt;span class="nx"&gt;glue_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"4.0"&lt;/span&gt;
    &lt;span class="nx"&gt;worker_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"G.1X"&lt;/span&gt;
    &lt;span class="nx"&gt;number_of_workers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="nx"&gt;script_location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3_file:glue_script"&lt;/span&gt;

    &lt;span class="nx"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"--DATABASE"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gluedb:analytics"&lt;/span&gt;
      &lt;span class="s2"&gt;"--INPUT_BUCKET"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:processed"&lt;/span&gt;
      &lt;span class="s2"&gt;"--REDSHIFT_SECRET"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"secret:redshift_creds"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"processed"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;glue_update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"analytics"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;secret_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"redshift_creds"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;redshift&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"analytics_cluster"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Scheduled trigger&lt;/span&gt;
    &lt;span class="nx"&gt;trigger_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SCHEDULED"&lt;/span&gt;
    &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cron(0 2 * * ? *)"&lt;/span&gt;  &lt;span class="c1"&gt;# Daily at 2 AM&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Define Redshift cluster&lt;/span&gt;
&lt;span class="nx"&gt;redshift_databases&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;analytics_cluster&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"analytics"&lt;/span&gt;
    &lt;span class="nx"&gt;node_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dc2.large"&lt;/span&gt;
    &lt;span class="nx"&gt;number_of_nodes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="nx"&gt;master_username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"admin"&lt;/span&gt;
    &lt;span class="nx"&gt;secret_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"secret:redshift_creds"&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;glue_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"analytics"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"processed"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  What Gets Created (40+ AWS Resources)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KMS data key for encryption&lt;/li&gt;
&lt;li&gt;VPC security groups for Lambda/Glue&lt;/li&gt;
&lt;li&gt;IAM roles (5): Lambda role, Glue role, Redshift role, Lake Formation role, Admin role&lt;/li&gt;
&lt;li&gt;IAM policies (5): Auto-generated least-privilege policies&lt;/li&gt;
&lt;li&gt;Permission boundaries (2): For Lambda and Glue roles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Storage:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 bucket: &lt;code&gt;companyp-analytics-pipeline-raw&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;S3 bucket: &lt;code&gt;companyp-analytics-pipeline-processed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;S3 bucket policies (2)&lt;/li&gt;
&lt;li&gt;S3 lifecycle rules&lt;/li&gt;
&lt;li&gt;S3 intelligent tiering configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Compute:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda function: &lt;code&gt;companyp-analytics-pipeline-csv-processor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Lambda log group with 30-day retention&lt;/li&gt;
&lt;li&gt;S3 event notification trigger&lt;/li&gt;
&lt;li&gt;Glue job: &lt;code&gt;companyp-analytics-pipeline-data-transform&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Glue security configuration&lt;/li&gt;
&lt;li&gt;Glue CloudWatch log group&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Data Catalog:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Glue database: &lt;code&gt;companyp-analytics-pipeline-analytics&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Lake Formation permissions&lt;/li&gt;
&lt;li&gt;Lake Formation resource link (cross-account share)&lt;/li&gt;
&lt;li&gt;RAM resource share (for cross-account access)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Database:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redshift cluster: &lt;code&gt;companyp-analytics-pipeline-analytics&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Redshift subnet group&lt;/li&gt;
&lt;li&gt;Redshift parameter group&lt;/li&gt;
&lt;li&gt;Redshift security group&lt;/li&gt;
&lt;li&gt;Secrets Manager secret: &lt;code&gt;companyp-analytics-pipeline-redshift-credentials&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Secret rotation configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudWatch alarms (6): Lambda errors, Glue job failures, S3 metrics&lt;/li&gt;
&lt;li&gt;CloudWatch log groups (3)&lt;/li&gt;
&lt;li&gt;EventBridge rule for Glue job schedule&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;All with:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent naming&lt;/li&gt;
&lt;li&gt;Full encryption (KMS)&lt;/li&gt;
&lt;li&gt;Least-privilege IAM policies&lt;/li&gt;
&lt;li&gt;Organizational tags&lt;/li&gt;
&lt;li&gt;VPC isolation&lt;/li&gt;
&lt;li&gt;CloudWatch logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total Configuration:&lt;/strong&gt; ~150 lines of tfvars&lt;br&gt;
&lt;strong&gt;Generated Terraform Code:&lt;/strong&gt; ~2000+ lines (via building blocks)&lt;br&gt;
&lt;strong&gt;Boilerplate Reduction:&lt;/strong&gt; ~93%&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌──────────────────────────────────┐
                    │         S3 Buckets               │
                    │  ┌────────┐      ┌────────┐      │
                    │  │  raw   │      │processed│     │
                    │  └───┬────┘      └────▲───┘      │
                    └──────┼────────────────┼──────────┘
                           │                │
               S3 Event    │                │
               Trigger     │                │ Writes
                           │                │
                    ┌──────▼────────────────┴──────────┐
                    │         Lambda                   │
                    │  ┌─────────────────────┐         │
                    │  │   csv-processor     │         │
                    │  └──────────┬──────────┘         │
                    └─────────────┼────────────────────┘
                                  │
                                  │ Updates
                                  │
        ┌─────────────────────────▼───────────────────────┐
        │              Glue                                │
        │  ┌──────────────────┐    ┌──────────────────┐   │
        │  │ Database:        │◄───│  ETL Job:        │   │
        │  │ analytics        │    │  transform       │   │
        │  └────────▲─────────┘    └────┬─────────────┘   │
        └───────────┼──────────────────┼─────────────────┘
                    │                  │
                    │ Queries          │ Loads
                    │                  │
        ┌───────────┴──────────────────▼─────────────────┐
        │           Redshift                              │
        │  ┌─────────────────────┐                        │
        │  │  Cluster: analytics │                        │
        │  └──────────┬──────────┘                        │
        └─────────────┼────────────────────────────────────┘
                      │
                      │ Reads
                      │
        ┌─────────────▼────────────────────────────────────┐
        │         Secrets Manager                          │
        │  ┌─────────────────────────┐                     │
        │  │  redshift-credentials   │                     │
        │  └─────────────────────────┘                     │
        └──────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Section 8:&lt;/strong&gt; Real-world data pipeline example shows how 150 lines of tfvars configuration generates 40+ AWS resources (S3, Lambda, Glue, Redshift, KMS, IAM, CloudWatch). Smart lookups connect resources (&lt;code&gt;s3:raw&lt;/code&gt;, &lt;code&gt;secret:db_creds&lt;/code&gt;), building blocks auto-generate IAM policies, context system applies consistent naming/tagging, and KMS keys encrypt everything automatically. Achieves 93% boilerplate reduction vs traditional Terraform.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  9. Cross-Account Architecture
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Use Case: Multi-Account Data Mesh
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Analytics workload in Production account needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read S3 data from Development account&lt;/li&gt;
&lt;li&gt;Query Glue tables from Staging account&lt;/li&gt;
&lt;li&gt;Use KMS keys from Shared Services account&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Configuration
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Define Cross-Account Aliases&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;cross_accounts&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;dev&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"123456789012"&lt;/span&gt;
  &lt;span class="nx"&gt;staging&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"234567890123"&lt;/span&gt;
  &lt;span class="nx"&gt;shared&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"345678901234"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Define External S3 Buckets&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;lookup_ids&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;xa_s3_bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dev_raw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev-shared-raw-data"&lt;/span&gt;
    &lt;span class="nx"&gt;staging_processed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"staging-shared-processed"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Use Cross-Account Lookups&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cross_account_reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"reader"&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;# Read from external S3 buckets&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dev_raw"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"staging_processed"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="c1"&gt;# Query Glue tables in staging account&lt;/span&gt;
      &lt;span class="nx"&gt;glue_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"acct_staging_glue_tables"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="c1"&gt;# Use KMS keys in shared account&lt;/span&gt;
      &lt;span class="nx"&gt;kms&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"acct_shared_kms_all_keys"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generated IAM Policy
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S3ReadCrossAccount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetBucket*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:List*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::dev-shared-raw-data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::dev-shared-raw-data/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::staging-shared-processed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::staging-shared-processed/*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GlueReadCrossAccount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"glue:GetTable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"glue:GetTables"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"glue:GetDatabase"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:glue:*:234567890123:table/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KMSCrossAccount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"kms:Decrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kms:DescribeKey"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:kms:eu-central-1:345678901234:key/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers don't need to know account IDs&lt;/li&gt;
&lt;li&gt;Cross-account permissions follow same pattern as same-account&lt;/li&gt;
&lt;li&gt;Centralized account alias management&lt;/li&gt;
&lt;li&gt;Type-safe (Terraform validates references at plan time)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  10. Deployment Workflow
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Repository Structure
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Blueprint Repository (Central):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform-platform-blueprint/
├── tf-common/           # Shared foundation
├── tf-default/          # Account-level resources
├── tf-project/          # Application resources
├── examples/
│   ├── full_test/       # Complete example
│   └── simple_example/  # Minimal example
└── tools/
    └── repo_updater.py  # Syncs blueprint to user repos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;User Repository (Team-Owned):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;team-analytics/
├── terraform/
│   ├── dev/
│   │   ├── tags.tf                      # Team owns
│   │   ├── _default.auto.tfvars         # Team owns
│   │   ├── _project.auto.tfvars         # Team owns
│   │   ├── managed_by_dp_common_*.tf    # Synced from blueprint
│   │   ├── managed_by_dp_default_*.tf   # Synced from blueprint
│   │   └── managed_by_dp_project_*.tf   # Synced from blueprint
│   ├── staging/
│   └── production/
└── .github/
    └── workflows/
        └── terraform.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Workflow Steps
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Team Creates Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Teams edit only their own files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tags.tf&lt;/code&gt; - Defines environment, workload, application&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_default.auto.tfvars&lt;/code&gt; - Account-level config (if first workload)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_project.auto.tfvars&lt;/code&gt; - Application resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Platform Team Updates Blueprint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When blueprint code needs updating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In blueprint repo&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;tools
python repo_updater.py &lt;span class="nt"&gt;--target&lt;/span&gt; ../../../team-analytics/terraform/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This syncs all &lt;code&gt;managed_by_dp_*.tf&lt;/code&gt; files from blueprint to team repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Team Commits and Pushes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: add data processing pipeline"&lt;/span&gt;
git push origin feature/data-pipeline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Terraform Cloud Runs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub Action triggers Terraform Cloud:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Workspace detects VCS change&lt;/li&gt;
&lt;li&gt;Runs &lt;code&gt;terraform plan&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Shows plan in pull request comment&lt;/li&gt;
&lt;li&gt;Team reviews and approves&lt;/li&gt;
&lt;li&gt;Merges PR&lt;/li&gt;
&lt;li&gt;Terraform Cloud runs &lt;code&gt;terraform apply&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Resources Created&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All AWS resources created with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standardized naming&lt;/li&gt;
&lt;li&gt;Automatic IAM policies&lt;/li&gt;
&lt;li&gt;Full encryption&lt;/li&gt;
&lt;li&gt;Organizational tags&lt;/li&gt;
&lt;li&gt;CloudWatch monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  No Preprocessing Required
&lt;/h4&gt;

&lt;p&gt;This workflow uses &lt;strong&gt;standard Terraform&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No build step before &lt;code&gt;terraform plan&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No code generation at runtime&lt;/li&gt;
&lt;li&gt;No wrapper scripts&lt;/li&gt;
&lt;li&gt;Native &lt;code&gt;.tfvars&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Standard state management&lt;/li&gt;
&lt;li&gt;Compatible with Terraform Cloud, Enterprise, or OSS
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Platform   Blueprint   repo_updater.py   Team Repos   Terraform    Application
Team         Repo                           (50+)       Cloud         Team
  │            │              │                │           │            │
  │ Update     │              │                │           │            │
  │ building   │              │                │           │            │
  │ blocks     │              │                │           │            │
  ├───────────&amp;gt;│              │                │           │            │
  │            │              │                │           │            │
  │ git commit │              │                │           │            │
  │ &amp;amp; push     │              │                │           │            │
  ├───────────&amp;gt;│              │                │           │            │
  │            │              │                │           │            │
  │ Run        │              │                │           │            │
  │ --update-  │              │                │           │            │
  │ all-teams  │              │                │           │            │
  ├────────────┼─────────────&amp;gt;│                │           │            │
  │            │              │ Generate 50 PRs│           │            │
  │            │              │ (update        │           │            │
  │            │              │ managed_by_dp) │           │            │
  │            │              ├───────────────&amp;gt;│           │            │
  │            │              │                │ PR triggers│           │
  │            │              │                │ terraform  │           │
  │            │              │                │ plan       │           │
  │            │              │                ├──────────&amp;gt;│            │
  │            │              │                │           │            │
  │            │              │                │ Post plan │            │
  │            │              │                │ as PR     │            │
  │            │              │                │ comment   │            │
  │            │              │                │&amp;lt;──────────┤            │
  │            │              │                │           │            │
  │            │              │                │           │ Review plan│
  │            │              │                │&amp;lt;──────────────────────┤
  │            │              │                │           │            │
  │            │              │                │ Approve &amp;amp; │            │
  │            │              │                │ merge PR  │            │
  │            │              │                │&amp;lt;──────────────────────┤
  │            │              │                │           │            │
  │            │              │                │ Merge     │            │
  │            │              │                │ triggers  │            │
  │            │              │                │ terraform │            │
  │            │              │                │ apply     │            │
  │            │              │                ├──────────&amp;gt;│            │
  │            │              │                │           │            │
  │            │              │                │ Deploy    │            │
  │            │              │                │ updated   │            │
  │            │              │                │ resources │            │
  │            │              │                │           │            │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  11. Comparison with Other Approaches
&lt;/h3&gt;

&lt;h4&gt;
  
  
  vs. Standard Terraform
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Standard Terraform&lt;/th&gt;
&lt;th&gt;This Framework&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ARN Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual ARN strings&lt;/td&gt;
&lt;td&gt;Smart lookups (&lt;code&gt;s3:bucket&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IAM Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Write JSON/HCL policy documents&lt;/td&gt;
&lt;td&gt;Auto-generated from permissions map&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Naming&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manually ensure consistency&lt;/td&gt;
&lt;td&gt;Automatic standardized naming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Standards&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manually enforce&lt;/td&gt;
&lt;td&gt;Building blocks enforce automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross-references&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct resource dependencies&lt;/td&gt;
&lt;td&gt;Lookup tables (reduces coupling)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Boilerplate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (1000+ lines typical)&lt;/td&gt;
&lt;td&gt;Low (150 lines typical) - &lt;strong&gt;~85% reduction&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Steep (requires AWS expertise)&lt;/td&gt;
&lt;td&gt;Moderate (config-focused)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  vs. Terragrunt
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Terragrunt&lt;/th&gt;
&lt;th&gt;This Framework&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Preprocessing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Required (terragrunt run)&lt;/td&gt;
&lt;td&gt;None (native Terraform)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Separate tool&lt;/td&gt;
&lt;td&gt;Native Terraform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compatibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Wrapper tool required&lt;/td&gt;
&lt;td&gt;Standard &lt;code&gt;terraform&lt;/code&gt; CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DRY Approach&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;File includes &amp;amp; remote state&lt;/td&gt;
&lt;td&gt;Lookup tables &amp;amp; modules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Additional tool layer&lt;/td&gt;
&lt;td&gt;Pure Terraform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IDE Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited (custom syntax)&lt;/td&gt;
&lt;td&gt;Full (standard HCL)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  vs. Terraspace
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Terraspace&lt;/th&gt;
&lt;th&gt;This Framework&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ruby DSL + ERB templates&lt;/td&gt;
&lt;td&gt;Pure HCL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Preprocessing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Required (terraspace build)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ruby interpreter needed&lt;/td&gt;
&lt;td&gt;Native Terraform only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ERB templating&lt;/td&gt;
&lt;td&gt;Native tfvars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tooling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Additional CLI wrapper&lt;/td&gt;
&lt;td&gt;Standard Terraform CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Learn Ruby + Terraspace&lt;/td&gt;
&lt;td&gt;Learn framework conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  vs. Terraform CDK
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Terraform CDK&lt;/th&gt;
&lt;th&gt;This Framework&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TypeScript/Python/Java/C#/Go&lt;/td&gt;
&lt;td&gt;Pure HCL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compilation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Required (cdktf synth)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Node.js/Python runtime&lt;/td&gt;
&lt;td&gt;Native Terraform only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Imperative code&lt;/td&gt;
&lt;td&gt;Declarative tfvars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Inspection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Via generated JSON&lt;/td&gt;
&lt;td&gt;Native Terraform state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IDE Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Language-specific&lt;/td&gt;
&lt;td&gt;Terraform-specific&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Key Advantages of This Approach
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No External Dependencies:&lt;/strong&gt; Pure Terraform, no additional tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Workflows:&lt;/strong&gt; Works with Terraform Cloud, Enterprise, OSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety:&lt;/strong&gt; Terraform validates references at plan time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version Control:&lt;/strong&gt; Standard &lt;code&gt;.tfvars&lt;/code&gt; files, readable diffs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDE Support:&lt;/strong&gt; Full support from Terraform plugins&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning Curve:&lt;/strong&gt; Lower (no new language/tool to learn)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability:&lt;/strong&gt; Standard Terraform state, no lock-in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging:&lt;/strong&gt; Standard Terraform error messages and plan output
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌─────────────────────────┐
                    │  Terraform Approaches   │
                    └────────────┬────────────┘
                                 │
         ┌───────────┬───────────┼───────────┬───────────┐
         │           │           │           │           │
         ▼           ▼           ▼           ▼           ▼
┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│  Standard  │ │Terragrunt│ │Terraspace│ │Terraform │ │     This     │
│  Terraform │ │          │ │          │ │   CDK    │ │  Framework   │
└─────┬──────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘
      │             │            │            │              │
      │Manual ARNs  │Wrapper     │Ruby DSL    │TypeScript/   │Pure HCL
      │High         │tool        │ERB         │Python        │Smart
      │boilerplate  │Preprocessing│templates  │Compilation   │lookups
      │             │            │            │              │
      ▼             ▼            ▼            ▼              ▼
┌─────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│   1000+     │ │terragrunt│ │terraspace│ │  cdktf   │ │     150      │
│   lines/    │ │   run    │ │  build   │ │  synth   │ │   lines/     │
│  workload   │ │ required │ │ required │ │ required │ │  workload    │
│             │ │          │ │          │ │          │ │      ✓       │
└─────────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Section 11:&lt;/strong&gt; This framework beats alternatives by using pure Terraform with zero preprocessing. Standard Terraform requires manual ARN management (1000+ lines). Terragrunt/Terraspace/CDK add preprocessing layers (wrapper tools, Ruby runtime, Node.js compilation). This approach achieves 85% boilerplate reduction through smart lookups and building blocks while maintaining full Terraform Cloud compatibility and native workflows.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  12. Lessons Learned and Best Practices
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What Worked Well
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Colon Syntax is Intuitive&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers adopted &lt;code&gt;s3:bucket_name&lt;/code&gt; syntax immediately. It reads like natural configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Building Blocks Enforce Standards&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Opinionated modules ensure consistency without policing. Teams can't accidentally create non-compliant resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Separation of Concerns&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Platform team manages &lt;code&gt;managed_by_dp_*.tf&lt;/code&gt; files, teams manage &lt;code&gt;*.tfvars&lt;/code&gt; files. Clear ownership boundaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Lookup Tables Reduce Coupling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Resources don't directly reference each other, reducing cascade changes when refactoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Predictive Naming Solves Most Circular Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most cross-resource references can use naming conventions instead of module outputs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Challenges and Solutions
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Challenge 1: Circular Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some resource relationships create cycles that Terraform can't resolve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use predictive naming instead of module outputs&lt;/li&gt;
&lt;li&gt;Two-phase deployment (apply twice)&lt;/li&gt;
&lt;li&gt;Selective resource inclusion in policies&lt;/li&gt;
&lt;li&gt;Data sources for cross-workload lookups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 2: Lookup Complexity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lookup tables can become large and hard to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organized into logical groups (&lt;code&gt;lookup_perm_lambda&lt;/code&gt;, &lt;code&gt;lookup_id_base&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Inline comments documenting purpose&lt;/li&gt;
&lt;li&gt;Automated generation via &lt;code&gt;for&lt;/code&gt; expressions&lt;/li&gt;
&lt;li&gt;Cross-account lookups separated into &lt;code&gt;_xa&lt;/code&gt; maps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 3: Building Block Versioning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Updating building block versions across many teams is coordination-heavy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic versioning with &lt;code&gt;~&amp;gt;&lt;/code&gt; constraints&lt;/li&gt;
&lt;li&gt;Deprecation warnings for old versions&lt;/li&gt;
&lt;li&gt;Automated testing of building block changes&lt;/li&gt;
&lt;li&gt;Communication channel for breaking changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 4: Developer Onboarding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;New developers need to learn lookup syntax and conventions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comprehensive examples in blueprint repo&lt;/li&gt;
&lt;li&gt;Detailed README with common patterns&lt;/li&gt;
&lt;li&gt;IntelliSense/autocomplete via Terraform language server&lt;/li&gt;
&lt;li&gt;Helper scripts to validate tfvars before commit&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Best Practices
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Use Descriptive Resource Keys&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Good&lt;/span&gt;
&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;raw_customer_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;processed_analytics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Bad&lt;/span&gt;
&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;bucket2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Group Related Resources&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Process: S3 → Lambda → Glue → Redshift&lt;/span&gt;
&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt; &lt;span class="nx"&gt;processed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;glue_jobs&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;redshift_databases&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;analytics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Use Comments to Document Intent&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Data pipeline for customer analytics&lt;/span&gt;
&lt;span class="c1"&gt;# Flow: External API → raw bucket → Lambda → processed bucket → Glue → Redshift&lt;/span&gt;
&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;api_ingestion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Leverage Type Inference&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Instead of:&lt;/span&gt;
&lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3_read:raw"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Prefer (type inferred from key):&lt;/span&gt;
&lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"raw"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Test in Lower Environments First&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dev → staging → production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use identical tfvars across environments, only changing &lt;code&gt;tags.tf&lt;/code&gt; (environment name).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Version Pin Building Blocks&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Use pessimistic constraint&lt;/span&gt;
&lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app.terraform.io/org/buildingblock-lambda/aws"&lt;/span&gt;
&lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 3.2.0"&lt;/span&gt;  &lt;span class="c1"&gt;# Allows 3.2.x, not 3.3.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Document Cross-Account Access&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Cross-account: Read from Data Lake account&lt;/span&gt;
&lt;span class="nx"&gt;cross_accounts&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;datalake&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"123456789012"&lt;/span&gt;  &lt;span class="c1"&gt;# Managed by Data Lake team&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  13. Impact and Metrics
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Development Velocity Improvements
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Before This Framework:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~1000 lines of Terraform per workload&lt;/li&gt;
&lt;li&gt;2-3 weeks to onboard new team&lt;/li&gt;
&lt;li&gt;5+ days to add new resource type&lt;/li&gt;
&lt;li&gt;Frequent IAM permission errors&lt;/li&gt;
&lt;li&gt;Inconsistent naming across teams&lt;/li&gt;
&lt;li&gt;Manual policy review process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After This Framework:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~150 lines of tfvars per workload (&lt;strong&gt;85% reduction&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;2-3 days to onboard new team&lt;/li&gt;
&lt;li&gt;1 day to add new resource type&lt;/li&gt;
&lt;li&gt;Rare IAM errors (auto-generated policies)&lt;/li&gt;
&lt;li&gt;Consistent naming (automatic)&lt;/li&gt;
&lt;li&gt;Automated policy compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Code Quality Improvements
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Reduction in Boilerplate:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional approach (S3 + Lambda with IAM):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~250 lines for: S3 bucket, IAM role, IAM policy document,&lt;/span&gt;
&lt;span class="c1"&gt;# Lambda function, CloudWatch log group, etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This framework (same resources):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~30 lines of tfvars&lt;/span&gt;
&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"data"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;s3_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Boilerplate Reduction: ~88%&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Governance and Compliance
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Automatic Enforcement:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100% of resources use standardized naming&lt;/li&gt;
&lt;li&gt;100% of resources encrypted with KMS&lt;/li&gt;
&lt;li&gt;100% of resources tagged per policy&lt;/li&gt;
&lt;li&gt;100% of IAM policies include permission boundaries&lt;/li&gt;
&lt;li&gt;100% of Lambda functions in VPC&lt;/li&gt;
&lt;li&gt;0 manual policy reviews required
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Before Framework                      After Framework
┌────────────────────────────┐      ┌────────────────────────────┐
│                            │      │                            │
│  • 1000+ lines Terraform   │─────&amp;gt;│  • 150 lines tfvars        │
│                            │      │    (85% reduction)         │
│                            │      │                            │
└────────────────────────────┘      └────────────────────────────┘

┌────────────────────────────┐      ┌────────────────────────────┐
│                            │      │                            │
│  • 2-3 weeks onboarding    │─────&amp;gt;│  • 2-3 days onboarding     │
│                            │      │    (5x faster)             │
│                            │      │                            │
└────────────────────────────┘      └────────────────────────────┘

┌────────────────────────────┐      ┌────────────────────────────┐
│                            │      │                            │
│  • Manual IAM policies     │─────&amp;gt;│  • Auto-generated IAM      │
│                            │      │    (Rare errors)           │
│                            │      │                            │
└────────────────────────────┘      └────────────────────────────┘

┌────────────────────────────┐      ┌────────────────────────────┐
│                            │      │                            │
│  • Inconsistent naming     │─────&amp;gt;│  • 100% consistent         │
│                            │      │    (Automatic compliance)  │
│                            │      │                            │
└────────────────────────────┘      └────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Section 13:&lt;/strong&gt; Framework delivers measurable improvements: 85% boilerplate reduction (1000→150 lines), 5x faster team onboarding (weeks→days), rare IAM errors (auto-generated policies), and 100% compliance (automatic naming, tagging, encryption, permission boundaries). Every resource is encrypted with KMS, tagged per policy, and uses least-privilege IAM—all enforced by building blocks with zero manual reviews.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  14. Future Enhancements
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Planned Features
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Multi-Region Support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enable workloads spanning multiple AWS regions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;regions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"eu-central-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;replicated_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"data"&lt;/span&gt;
    &lt;span class="nx"&gt;replication_regions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Enhanced Lookup Syntax&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Support nested lookups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;BUCKET_PATH&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:mybucket:/path/prefix"&lt;/span&gt;
  &lt;span class="nx"&gt;TABLE_COLUMN&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dynamodb:mytable:attribute:id"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Building Block Customization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allow team-specific overrides while maintaining compliance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;special&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"special"&lt;/span&gt;
    &lt;span class="nx"&gt;override_defaults&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;versioning_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;  &lt;span class="c1"&gt;# Team takes responsibility&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Cost Estimation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integrate with AWS Pricing API to estimate costs before apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# In plan output:&lt;/span&gt;
&lt;span class="c1"&gt;# Estimated monthly cost: $1,234.56&lt;/span&gt;
&lt;span class="c1"&gt;#   - Lambda: $123.45&lt;/span&gt;
&lt;span class="c1"&gt;#   - S3: $456.78&lt;/span&gt;
&lt;span class="c1"&gt;#   - Redshift: $654.33&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Dependency Visualization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generate visual dependency graphs from lookup tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S3:raw → Lambda:processor → S3:processed → Glue:transform → Redshift:analytics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Potential Improvements
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Resolve Two-Phase Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Investigate Terraform's &lt;code&gt;-target&lt;/code&gt; flag or module dependencies to eliminate the "apply twice" requirement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Building Block Catalog&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create searchable catalog of building blocks with examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Searchable by AWS service&lt;/li&gt;
&lt;li&gt;Filterable by capability (encryption, backups, monitoring)&lt;/li&gt;
&lt;li&gt;Includes terraform-docs generated documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Policy Simulation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pre-validate IAM policies using AWS IAM Policy Simulator before apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform plan | policy-simulator &lt;span class="nt"&gt;--validate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Drift Detection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Automated drift detection for resources created outside Terraform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform-drift-detector &lt;span class="nt"&gt;--alert&lt;/span&gt; slack://channel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  15. Conclusion
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;We've built a &lt;strong&gt;Native Terraform IaC Framework&lt;/strong&gt; that achieves the developer experience of high-level abstractions while maintaining 100% compatibility with standard Terraform workflows. The key innovations are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Smart Lookup Syntax:&lt;/strong&gt; Colon-separated references (&lt;code&gt;s3:bucket&lt;/code&gt;, &lt;code&gt;lambda:function&lt;/code&gt;) resolved via native Terraform expressions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Building Block Abstraction:&lt;/strong&gt; Opinionated modules that enforce standards and generate IAM policies automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Preprocessing:&lt;/strong&gt; Pure Terraform - works with Terraform Cloud, CLI, and all standard tooling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear Separation:&lt;/strong&gt; Platform team manages code, application teams manage configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Propagation:&lt;/strong&gt; Naming and tagging enforced automatically via context system&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Why This Matters
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;For Platform Engineers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforce organizational standards without restricting teams&lt;/li&gt;
&lt;li&gt;Reduce support burden (teams self-service)&lt;/li&gt;
&lt;li&gt;Centralized updates via building blocks&lt;/li&gt;
&lt;li&gt;Scalable to hundreds of workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For Application Teams:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write configuration, not code&lt;/li&gt;
&lt;li&gt;No AWS expertise required&lt;/li&gt;
&lt;li&gt;Fast onboarding (days, not weeks)&lt;/li&gt;
&lt;li&gt;Focus on business logic, not infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For Organizations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent security posture&lt;/li&gt;
&lt;li&gt;Automated compliance&lt;/li&gt;
&lt;li&gt;Cost visibility via standardized tagging&lt;/li&gt;
&lt;li&gt;Reduced risk (guardrails prevent misconfigurations)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Key Takeaways
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Native Terraform is Powerful:&lt;/strong&gt; With creative use of locals and lookups, you can build sophisticated abstractions without preprocessing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuration Over Code:&lt;/strong&gt; Separating what (tfvars) from how (modules) reduces complexity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Building Blocks Scale:&lt;/strong&gt; Opinionated modules enable governance at scale&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer Experience Matters:&lt;/strong&gt; Investment in ergonomics pays dividends in velocity and adoption&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standards Enable Freedom:&lt;/strong&gt; Guardrails paradoxically enable teams to move faster&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 ┌─────────────────────────────────┐
                 │  Native Terraform Framework     │
                 └──────────────┬──────────────────┘
                                │
        ┌───────────────────────┼───────────────────────┐
        │                       │                       │
        ▼                       ▼                       ▼
┌───────────────┐   ┌──────────────────┐   ┌──────────────────┐
│ Smart Lookups │   │ Building Blocks  │   │ Separation of    │
│               │   │                  │   │ Code &amp;amp; Config    │
└───────┬───────┘   └────────┬─────────┘   └────────┬─────────┘
        │                    │                       │
        │            ┌───────▼────────┐              │
        │            │Context         │              │
        │            │Propagation     │              │
        │            └───────┬────────┘              │
        │                    │                       │
        └────────────────────┼───────────────────────┘
                             │
        ┌────────────────────┼────────────────────┐
        │                    │                    │
        ▼                    ▼                    ▼
┌────────────────┐  ┌─────────────────┐  ┌──────────────────┐
│ 85% Boilerplate│  │      Zero       │  │    Automated     │
│   Reduction    │  │  Preprocessing  │  │ Updates at Scale │
└────────┬───────┘  └────────┬────────┘  └─────────┬────────┘
         │                   │                      │
         │           ┌───────▼────────┐             │
         │           │      100%      │             │
         │           │   Compliance   │             │
         │           └───────┬────────┘             │
         │                   │                      │
         └───────────────────┼──────────────────────┘
                             │
                             ▼
                  ┌──────────────────────┐
                  │   50+ Teams Can      │
                  │   Self-Service       │
                  │   Infrastructure     │
                  └──────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR - Conclusion:&lt;/strong&gt; This native Terraform framework proves that developer-friendly IaC doesn't require preprocessing or external tools. By combining smart lookups (&lt;code&gt;s3:bucket&lt;/code&gt;), opinionated building blocks, configuration/code separation, and context propagation, we achieve 85% boilerplate reduction while maintaining full Terraform Cloud compatibility. Platform teams scale updates via automated PRs, application teams self-service via simple tfvars, and organizations get automatic compliance. Native Terraform can be elegant, scalable, and secure.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  16. Getting Started Guide
&lt;/h3&gt;

&lt;p&gt;For teams interested in adopting this approach:&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Assess Your Needs
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Good fit if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple teams deploying similar infrastructure&lt;/li&gt;
&lt;li&gt;Need to enforce organizational standards&lt;/li&gt;
&lt;li&gt;Want to reduce AWS expertise requirement&lt;/li&gt;
&lt;li&gt;High volume of infrastructure deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not a good fit if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small team (1-2 people) with custom requirements&lt;/li&gt;
&lt;li&gt;Infrastructure is highly heterogeneous&lt;/li&gt;
&lt;li&gt;Team prefers low abstraction level&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2: Start Small
&lt;/h4&gt;

&lt;p&gt;Begin with a pilot:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose one AWS service (e.g., S3)&lt;/li&gt;
&lt;li&gt;Build an opinionated building block module&lt;/li&gt;
&lt;li&gt;Create lookup mechanism for that service&lt;/li&gt;
&lt;li&gt;Test with one team&lt;/li&gt;
&lt;li&gt;Iterate based on feedback&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 3: Build Your Building Blocks
&lt;/h4&gt;

&lt;p&gt;For each AWS service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define organizational standards (naming, tagging, encryption)&lt;/li&gt;
&lt;li&gt;Create Terraform module enforcing standards&lt;/li&gt;
&lt;li&gt;Add permission generation logic&lt;/li&gt;
&lt;li&gt;Version and publish to private registry&lt;/li&gt;
&lt;li&gt;Write documentation and examples&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 4: Create Lookup System
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Define lookup syntax (e.g., &lt;code&gt;type:name&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Create lookup locals maps&lt;/li&gt;
&lt;li&gt;Add resolution logic to building blocks&lt;/li&gt;
&lt;li&gt;Test cross-resource references&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 5: Document and Socialize
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Write comprehensive README&lt;/li&gt;
&lt;li&gt;Create example projects&lt;/li&gt;
&lt;li&gt;Run training sessions&lt;/li&gt;
&lt;li&gt;Set up support channel&lt;/li&gt;
&lt;li&gt;Gather feedback and iterate&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 6: Scale
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Add more building blocks incrementally&lt;/li&gt;
&lt;li&gt;Onboard teams progressively&lt;/li&gt;
&lt;li&gt;Monitor usage and pain points&lt;/li&gt;
&lt;li&gt;Continuously improve based on feedback&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Appendix: Code Samples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A. Lookup Table Implementation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;tf-project/terraform/managed_by_dp_project_lookup.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;# Build base lookup maps for ARNs (used in IAM policies)&lt;/span&gt;
  &lt;span class="nx"&gt;lookup_arn_base&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_arns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"kms"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"kms_data"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_data_key_arn&lt;/span&gt;
      &lt;span class="s2"&gt;"kms_infra"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_infrastructure_key_arn&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"s3_read"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"s3_write"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"gluejob"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;glue_jobs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;glue_jobs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"gluedb"&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;glue_database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;glue_databases&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"secret_read"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"dynamodb_read"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb_databases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;# Build base lookup maps for IDs (used in environment variables)&lt;/span&gt;
  &lt;span class="nx"&gt;lookup_id_base&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"secret"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"dynamodb"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb_databases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s2"&gt;"athena"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;athena_workgroups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;athena&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;# Specialized lookup for Lambda permissions&lt;/span&gt;
  &lt;span class="nx"&gt;lookup_perm_lambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_arn_base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_perm_lambda_xa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Cross-account additions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"sqs_read"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqs_queues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;queue_arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="s2"&gt;"sqs_send"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqs_queues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;queue_arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="s2"&gt;"sns_pub"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sns_topics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;topic_arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Specialized lookup for Lambda environment variables&lt;/span&gt;
  &lt;span class="nx"&gt;lookup_id_lambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_id_base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"sqs"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqs_queues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;queue_url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="s2"&gt;"sns"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sns_topics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;topic_arn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  B. Lambda Building Block Usage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;tf-project/terraform/managed_by_dp_project_lambda.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app.terraform.io/org/buildingblock-lambda/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"3.2.0"&lt;/span&gt;

  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_functions&lt;/span&gt;

  &lt;span class="c1"&gt;# Standard fields&lt;/span&gt;
  &lt;span class="nx"&gt;prefix&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Environment variables with smart lookup&lt;/span&gt;
  &lt;span class="nx"&gt;environments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;# Try to resolve as "type:name" lookup&lt;/span&gt;
        &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_id_lambda&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
        &lt;span class="nx"&gt;item&lt;/span&gt;  &lt;span class="c1"&gt;# Fallback to literal value&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Permissions with smart lookup and automatic policy generation&lt;/span&gt;
  &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;# Check if it's namespaced format "type:name"&lt;/span&gt;
        &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="err"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_perm_lambda&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
            &lt;span class="nx"&gt;item&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="c1"&gt;# Infer type from permission category key&lt;/span&gt;
            &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup_perm_lambda&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nx"&gt;item&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Create IAM role and policy automatically&lt;/span&gt;
  &lt;span class="nx"&gt;create_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="c1"&gt;# Injected infrastructure details&lt;/span&gt;
  &lt;span class="nx"&gt;kms_key_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kms_data_key_arn&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_ids&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_id&lt;/span&gt;

  &lt;span class="c1"&gt;# User-provided configuration&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;
  &lt;span class="nx"&gt;memory&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;timeout&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Resolve S3 source file location&lt;/span&gt;
  &lt;span class="nx"&gt;s3_bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code_bucket&lt;/span&gt;
  &lt;span class="nx"&gt;s3_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_sourcefile&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"s3_file"&lt;/span&gt;
    &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_target_path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_sourcefile&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
        &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_sourcefile&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_sourcefile&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  C. Example Workload Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;examples/full_test/_project.auto.tfvars&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# S3 Buckets&lt;/span&gt;
&lt;span class="nx"&gt;s3_buckets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;raw_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"raw"&lt;/span&gt;
    &lt;span class="nx"&gt;backup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;lifecycle_rules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"archive_old_data"&lt;/span&gt;
      &lt;span class="nx"&gt;transition_days&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
      &lt;span class="nx"&gt;storage_class&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GLACIER"&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;processed_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processed"&lt;/span&gt;
    &lt;span class="nx"&gt;enable_intelligent_tiering&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;enable_eventbridge_notification&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Upload code artifacts&lt;/span&gt;
&lt;span class="nx"&gt;s3_source_files&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;processor_code&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda_processor.zip"&lt;/span&gt;
    &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda_functions/processor/code.zip"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;transform_script&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"glue_transform.py"&lt;/span&gt;
    &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"glue_jobs/transform/script.py"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Secrets&lt;/span&gt;
&lt;span class="nx"&gt;secrets&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;database_creds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"db-credentials"&lt;/span&gt;
    &lt;span class="nx"&gt;secret_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"admin"&lt;/span&gt;
      &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;  &lt;span class="c1"&gt;# Set via AWS Console&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Glue Database&lt;/span&gt;
&lt;span class="nx"&gt;glue_database&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;analytics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"analytics"&lt;/span&gt;
    &lt;span class="nx"&gt;bucket&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:processed_data"&lt;/span&gt;
    &lt;span class="nx"&gt;enable_lakeformation&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;share_cross_account_ro&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"datagovernance"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Lambda Function&lt;/span&gt;
&lt;span class="nx"&gt;lambda_functions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data_processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"processor"&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Processes incoming data files"&lt;/span&gt;
    &lt;span class="nx"&gt;handler&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;
    &lt;span class="nx"&gt;runtime&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.13"&lt;/span&gt;
    &lt;span class="nx"&gt;memory&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;
    &lt;span class="nx"&gt;timeout&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;
    &lt;span class="nx"&gt;in_vpc&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="nx"&gt;s3_sourcefile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3_file:processor_code"&lt;/span&gt;

    &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;RAW_BUCKET&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:raw_data"&lt;/span&gt;
      &lt;span class="nx"&gt;PROCESSED_BUCKET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:processed_data"&lt;/span&gt;
      &lt;span class="nx"&gt;GLUE_DATABASE&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gluedb:analytics"&lt;/span&gt;
      &lt;span class="nx"&gt;DB_SECRET&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"secret:database_creds"&lt;/span&gt;
      &lt;span class="nx"&gt;LOG_LEVEL&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"INFO"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"raw_data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;s3_write&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"processed_data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;glue_update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"analytics"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;secret_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"database_creds"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;event_source_mapping&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="nx"&gt;event_source_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:raw_data"&lt;/span&gt;
      &lt;span class="nx"&gt;events&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"s3:ObjectCreated:*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;filter_prefix&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"incoming/"&lt;/span&gt;
      &lt;span class="nx"&gt;filter_suffix&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;".csv"&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Glue ETL Job&lt;/span&gt;
&lt;span class="nx"&gt;glue_jobs&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data_transform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"transform"&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Transforms processed data"&lt;/span&gt;
    &lt;span class="nx"&gt;glue_version&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"4.0"&lt;/span&gt;
    &lt;span class="nx"&gt;worker_type&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"G.1X"&lt;/span&gt;
    &lt;span class="nx"&gt;number_of_workers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="nx"&gt;max_retries&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="nx"&gt;timeout&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;

    &lt;span class="nx"&gt;script_location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3_file:transform_script"&lt;/span&gt;

    &lt;span class="nx"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"--job-language"&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python"&lt;/span&gt;
      &lt;span class="s2"&gt;"--enable-metrics"&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt;
      &lt;span class="s2"&gt;"--enable-continuous-cloudwatch-log"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt;
      &lt;span class="s2"&gt;"--DATABASE"&lt;/span&gt;                         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gluedb:analytics"&lt;/span&gt;
      &lt;span class="s2"&gt;"--INPUT_BUCKET"&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:processed_data"&lt;/span&gt;
      &lt;span class="s2"&gt;"--DB_SECRET"&lt;/span&gt;                        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"secret:database_creds"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;s3_read&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"processed_data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;glue_update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"analytics"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;secret_read&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"database_creds"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;trigger_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SCHEDULED"&lt;/span&gt;
    &lt;span class="nx"&gt;schedule&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cron(0 2 * * ? *)"&lt;/span&gt;  &lt;span class="c1"&gt;# Daily at 2 AM UTC&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This framework demonstrates that &lt;strong&gt;native Terraform can be elegant and developer-friendly&lt;/strong&gt; without sacrificing power or flexibility. By leveraging Terraform's built-in features creatively—&lt;code&gt;for&lt;/code&gt; expressions, &lt;code&gt;try()&lt;/code&gt; functions, &lt;code&gt;split()&lt;/code&gt; operations, and locals—we've built a system that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feels like configuration&lt;/strong&gt; (simple tfvars files)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works like Terraform&lt;/strong&gt; (native tooling, no preprocessing)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scales like a platform&lt;/strong&gt; (hundreds of workloads, multiple teams)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governs like policy&lt;/strong&gt; (automatic enforcement, no manual reviews)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The journey from verbose, error-prone Terraform code to concise, validated configuration files represents a significant step forward in Infrastructure as Code maturity. Most importantly, it's achieved through native Terraform capabilities, ensuring long-term compatibility and eliminating external dependencies.&lt;/p&gt;

&lt;p&gt;As organizations scale their cloud infrastructure, frameworks like this become essential for maintaining velocity, consistency, and security. The patterns demonstrated here can be adapted to any cloud provider, resource types, or organizational requirements—the principles of smart lookups, building block abstraction, and configuration separation are universally applicable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The future of Infrastructure as Code is declarative, native, and developer-friendly. This framework is a blueprint for getting there.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Acknowledgments
&lt;/h2&gt;

&lt;p&gt;This framework was built by collaborative iteration between platform engineers and application teams, learning from real-world challenges and continuously refining the developer experience. Special recognition to the teams who adopted early versions, provided feedback, and helped shape the patterns documented here.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>scaling</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Hidden Dangers in Our Software Supply Chain: Why It's Bigger Than You Think</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Mon, 29 Sep 2025 12:31:02 +0000</pubDate>
      <link>https://forem.com/jverhoeks/the-hidden-dangers-in-our-software-supply-chain-why-its-bigger-than-you-think-4n8d</link>
      <guid>https://forem.com/jverhoeks/the-hidden-dangers-in-our-software-supply-chain-why-its-bigger-than-you-think-4n8d</guid>
      <description>&lt;p&gt;In today's fast-paced digital world, software powers everything from the apps on our phones to the cloud systems running global businesses. But behind the scenes, there's a complex web called the &lt;strong&gt;software supply chain&lt;/strong&gt;—the process of sourcing, building, and delivering software components. Traditionally, we've focused on securing this chain during application development and deployment. However, as technology evolves, risks are creeping into unexpected places, like the tools developers use every day and even the software on our personal devices.&lt;/p&gt;

&lt;p&gt;This article aims to shed light on how the software supply chain has expanded far beyond just building and shipping apps. We'll break it down in simple terms for non-technical leaders, project managers (PMs), and engineers who might not deal with package management daily. By the end, you'll understand why awareness is crucial and how these hidden vulnerabilities could impact your team or organization.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Software Supply Chain, Anyway?
&lt;/h2&gt;

&lt;p&gt;Imagine building a house: You don't make every brick, nail, or window yourself. Instead, you source them from suppliers, assemble them, and ensure the final structure is safe. The software supply chain is similar—it's the ecosystem of code, libraries, and tools that developers "source" to create software.&lt;/p&gt;

&lt;p&gt;Key elements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open-source packages&lt;/strong&gt;: Reusable code snippets from public repositories like npm (for JavaScript), PyPI (for Python), or Cargo (for Rust). These are free and community-driven, speeding up development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies&lt;/strong&gt;: Packages often rely on other packages, creating a chain (or "tree") of interconnected code. This is recursive—meaning one package might pull in dozens or hundreds more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SBOM (Software Bill of Materials)&lt;/strong&gt;: A list of all components in your software, like an ingredients label on food. It helps track what's inside.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the past, security focused on scanning these packages for vulnerabilities during app building and deployment. Tools would check for known issues, generate an SBOM, and ensure everything was safe before going live. But that's no longer enough. The supply chain has infiltrated deeper into our workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Old Way: Focusing Only on App Development and Deployment
&lt;/h2&gt;

&lt;p&gt;Historically, teams treated the software supply chain as something confined to production applications—the software your customers use. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A developer writes code for a web app.&lt;/li&gt;
&lt;li&gt;They install packages via commands like &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;pip install&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;During the build process (often in a CI/CD pipeline, which automates testing and deployment), the team scans for malicious code or vulnerabilities.&lt;/li&gt;
&lt;li&gt;An SBOM is created to document all dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach worked reasonably well for "end-product" software. If a package had a flaw, it could be caught before deployment. But it assumed risks were limited to that final app. Reality? Not so much.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Expansion: DevOps Tools, Local Installs, and Recursive Risks
&lt;/h2&gt;

&lt;p&gt;Today, software development isn't just about the app—it's about the entire ecosystem supporting it. DevOps (a blend of development and operations) tools, which help automate infrastructure, testing, and monitoring, are often built on the same package systems like JavaScript or Python.&lt;/p&gt;

&lt;p&gt;Consider this scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A developer or DevOps engineer runs &lt;code&gt;npm install aws-cdk&lt;/code&gt; (a tool for managing AWS cloud infrastructure) on their local laptop or in a CI/CD pipeline.&lt;/li&gt;
&lt;li&gt;This isn't for the main app; it's for setting up servers, databases, or deployment scripts.&lt;/li&gt;
&lt;li&gt;But aws-cdk has its own dependencies, which have more dependencies, and so on. It's a recursive rabbit hole—hard to fully map or monitor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike production apps, these tools often run in less controlled environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local machines&lt;/strong&gt;: Developers install packages directly on their laptops, outside formal security scans.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipelines&lt;/strong&gt;: Automated workflows that build and deploy code, but they might pull in unvetted packages mid-process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everyday tools&lt;/strong&gt;: Even non-app software like code editors or AI assistants relies on these packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem? We might vet the top-level package (e.g., the first version of aws-cdk we install), but we have no visibility into the deeper layers. A single update or hidden dependency could introduce risks without anyone noticing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evolution of Attacks: From End-User Exploitation to Proactive Credential Theft and Spread
&lt;/h2&gt;

&lt;p&gt;Supply chain attacks aren't new, but their tactics are evolving. Older incidents often focused on injecting malicious code into applications to target end-users, such as visitors to a website. For instance, compromised packages like ua-parser-js in 2021 installed cryptominers or trojans that could steal data from browsers, aiming to hijack cryptocurrency wallets or personal information from unsuspecting users. Similarly, the 2018 event-stream hack embedded a backdoor to steal Bitcoin from apps built with the package, affecting the final deployed software and its users.&lt;/p&gt;

&lt;p&gt;These attacks typically relied on the malicious code being bundled into the application and executed in production environments, passively waiting to exploit visitors or users. The damage was downstream, impacting customers rather than the development process itself.&lt;/p&gt;

&lt;p&gt;In contrast, more recent worms like Shai-Hulud represent a shift toward aggressive, self-propagating threats that target the development environment upfront. Discovered in mid-September 2025, Shai-Hulud is a worm that infects npm packages, using "onInstall" hooks to run automatically upon installation. It doesn't just sit idle—it actively scans for secrets such as npm tokens, GitHub credentials, AWS keys, and environment variables on local laptops, in CI/CD pipelines, and even queries cloud metadata for ephemeral credentials. Tools like TruffleHog are embedded to deepen the scan, and stolen data is exfiltrated to public GitHub repos created by the worm itself.&lt;/p&gt;

&lt;p&gt;What makes it worm-like is its propagation: Using pilfered tokens, it automatically republishes compromised versions of other packages under the maintainer's control, turning victims into unwitting spreaders. This moves the infection window forward, infiltrating source repositories (like GitHub) and cloud services, potentially compromising entire organizations. Over 500 packages were affected in this campaign, including those linked to major companies like CrowdStrike.&lt;/p&gt;

&lt;p&gt;This evolution from passive end-user attacks to proactive dev-side credential hunting amplifies the risk, as it enables exponential spread across the supply chain before detection.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real-World Wake-Up Call: The Shai Hulud NPM Worm
&lt;/h2&gt;

&lt;p&gt;To illustrate the danger, let's look at a recent incident: the &lt;strong&gt;Shai Hulud worm&lt;/strong&gt;, a malicious package that spread through npm in 2025.&lt;/p&gt;

&lt;p&gt;Here's what happened in simple terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shai Hulud disguised itself as a legitimate package.&lt;/li&gt;
&lt;li&gt;It used an "onInstall" hook—a script that runs automatically when the package is installed.&lt;/li&gt;
&lt;li&gt;Once installed, it didn't just sit there. It scanned for sensitive data like API keys, passwords, or "secrets" on the local machine.&lt;/li&gt;
&lt;li&gt;It went further: In CI/CD pipelines, it hunted for environment variables (secret values used in automation).&lt;/li&gt;
&lt;li&gt;Even scarier, it attempted to access cloud services like AWS to steal more secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This wasn't limited to production apps. Developers running &lt;code&gt;npm install&lt;/code&gt; locally exposed their personal laptops. Pipelines automating DevOps tasks became infection points. The worm spread because npm packages are public—anyone can publish without upfront checks. No gatekeepers, just trust in the community.&lt;/p&gt;

&lt;p&gt;Shai Hulud highlights a key flaw: Even if you trust the initial package, recursive dependencies mean you might unwittingly install something harmful. And since DevOps tools run with high privileges (e.g., access to cloud accounts), the fallout can be massive—data breaches, financial loss, or operational downtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are We So Vulnerable? The Trust Issue with Open Source
&lt;/h2&gt;

&lt;p&gt;Open source is amazing—it democratizes innovation and accelerates progress. But our over-reliance on it creates blind spots. Here's why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Public Repositories Without Validation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platforms like npm.js and PyPI are open to all. Anyone with an account can upload a package—no mandatory security reviews.&lt;/li&gt;
&lt;li&gt;Contrast this with app stores like Apple's, which vet submissions. In open source, it's "publish first, fix later."&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Recursive Dependencies Make Visibility Impossible&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple install can pull in hundreds of sub-packages. Tools like dependency trees exist, but they're not always used, especially in ad-hoc DevOps tasks.&lt;/li&gt;
&lt;li&gt;Updates happen automatically in many setups, introducing new risks without notice.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Beyond App Pipelines&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Risks extend to non-development tools. For instance:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VSCode (Visual Studio Code)&lt;/strong&gt;: A popular code editor built on Electron (a framework for desktop apps using web tech). It uses npm packages and supports extensions that pull in more code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude or similar AI tools&lt;/strong&gt;: Many are built with Python or JS dependencies, potentially vulnerable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Electron-based apps&lt;/strong&gt;: These are desktop programs (like Slack or Discord) that auto-update. An update could inject malicious code via a compromised package.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In short, open source is everywhere—not just in your company's app, but in the tools enabling your workflow. We trust it because it's convenient, but that trust is often unearned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Broader Impact: From Laptops to Critical Infrastructure
&lt;/h2&gt;

&lt;p&gt;This isn't just a developer problem; it affects entire organizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Non-Tech Leaders and PMs&lt;/strong&gt;: Budgets for security might focus on apps, but a breach in a DevOps tool could halt projects, expose customer data, or lead to compliance fines (e.g., GDPR or HIPAA).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineers Outside the Process&lt;/strong&gt;: If you're not handling packages daily, you might assume IT has it covered. But local installs bypass central controls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Scale&lt;/strong&gt;: Supply chain attacks like SolarWinds (2020) or Log4j (2021) showed how one vulnerability ripples worldwide. Now, with DevOps proliferation, the attack surface is larger.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine a PM overseeing a cloud migration: The team uses aws-cdk in pipelines. A worm like Shai Hulud sneaks in, steals AWS credentials, and compromises your entire infrastructure. It's not hypothetical—it's happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving Forward: Awareness Is Key, with a Focus on Hygiene
&lt;/h2&gt;

&lt;p&gt;The software supply chain has evolved, and so must our mindset. It's no longer just about the app you deploy; it's about every tool, script, and dependency in your ecosystem.&lt;/p&gt;

&lt;p&gt;To build resilience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Educate Teams&lt;/strong&gt;: Train everyone—from execs to engineers—on supply chain risks. Use SBOMs not just for apps, but for tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adopt Best Practices&lt;/strong&gt;: Lock dependencies to specific versions, use private registries for vetted packages, and scan local/CI environments regularly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emphasize Hygiene&lt;/strong&gt;: Maintain laptop and pipeline hygiene by using minimal, scoped credentials—grant only the access needed for a task, and rotate them frequently. Avoid storing secrets in plain text or environment variables without encryption, and use tools like secret managers (e.g., AWS Secrets Manager) to limit exposure. This is especially critical against worms like Shai-Hulud that hunt for broad tokens to spread to clouds and repos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Question Trust&lt;/strong&gt;: Don't assume open source is safe. Verify publishers, review changelogs, and limit auto-updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Awareness is the first step. By recognizing that vulnerabilities lurk in DevOps tools, local installs, and everyday software—and that attacks are shifting to proactive theft for wider spread—we can foster a culture of caution. In a world where software is ubiquitous, staying vigilant isn't optional—it's essential for security and success.&lt;/p&gt;

&lt;p&gt;What are your thoughts? Have you encountered supply chain issues in your tools? Share in the comments below!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is based on emerging trends in software security as of September 2025.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Image credit: &lt;a href="https://xkcd.com/2347/" rel="noopener noreferrer"&gt;https://xkcd.com/2347/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why Debian packages are safer then NPM and PyPi</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Fri, 19 Sep 2025 09:36:46 +0000</pubDate>
      <link>https://forem.com/jverhoeks/why-debian-packages-are-saver-then-npm-and-pypi-4j21</link>
      <guid>https://forem.com/jverhoeks/why-debian-packages-are-saver-then-npm-and-pypi-4j21</guid>
      <description>&lt;p&gt;In the world of software development, package repositories are critical for distributing libraries and dependencies. But how do they ensure no malicious code slips through? Debian’s stable repository, npmjs (npm registry), and PyPI (Python Package Index) take vastly different approaches to security. Debian’s tightly controlled process contrasts with the open, fast-paced ecosystems of npmjs and PyPI, which prioritize ease of publishing but face higher risks of supply chain attacks. Let’s compare their security measures and see why the latest NPM work attack could spread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Measures Compared
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Debian Stable&lt;/th&gt;
&lt;th&gt;npmjs (npm Registry)&lt;/th&gt;
&lt;th&gt;PyPI (Python Package Index)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Uploader Vetting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strict: Only vetted Debian Developers/Maintainers (DDs) after identity verification and competence checks. No anonymous uploads.&lt;/td&gt;
&lt;td&gt;Minimal: Anyone with a free account; 2FA encouraged but not mandatory. Accounts can be compromised easily.&lt;/td&gt;
&lt;td&gt;Minimal: Anyone can create a free account; MFA recommended but not enforced for all.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pre-Publication Review&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High: Source code reviewed by maintainers and community; packages staged in "unstable" and "testing" for months before stable inclusion.&lt;/td&gt;
&lt;td&gt;None: Packages published directly without code review; spam detection may block obvious violations.&lt;/td&gt;
&lt;td&gt;None: Packages uploaded directly; no mandatory code review or static analysis.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Package Signing/Verification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes: GPG-signed packages and archive; reproducible builds ensure binaries match source.&lt;/td&gt;
&lt;td&gt;Partial: Packages not signed by default; relies on HTTPS and hash checks (e.g., via &lt;code&gt;npm shrinkwrap&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;Partial: No built-in signing; users can enable hash checking in pip for integrity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automated Testing/Scanning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extensive: Lintian checks, CI across architectures, and migration criteria enforced by Release Team.&lt;/td&gt;
&lt;td&gt;Post-facto: &lt;code&gt;npm audit&lt;/code&gt; scans for known vulnerabilities in dependencies after install. No pre-scan.&lt;/td&gt;
&lt;td&gt;Post-facto: Tools like &lt;code&gt;pip-audit&lt;/code&gt; or Safety CLI scan for known issues; no pre-upload scanning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Malicious Package Handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proactive: Security Team monitors CVEs, backports fixes to stable; packages removed if compromised. Rare incidents due to vetting.&lt;/td&gt;
&lt;td&gt;Reactive: Security team removes reported malware (hundreds annually); advisories issued. Common attacks: typosquatting, brandjacking.&lt;/td&gt;
&lt;td&gt;Reactive: Security team removes reported packages (e.g., thousands in campaigns); advisories via email. Common attacks: typosquatting, wheeljacking.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Community / Transparency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High: Public bug tracking (BTS), open logs, and community scrutiny; emphasis on minimal changes in stable.&lt;/td&gt;
&lt;td&gt;Medium: GitHub-hosted source often reviewed post-publish; tools like Socket/Phylum for community scans.&lt;/td&gt;
&lt;td&gt;Medium: GitHub integration for source; community reports via &lt;a href="mailto:security@pypi.org"&gt;security@pypi.org&lt;/a&gt;; tools like PyPI-scan for typosquatting detection.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Known Incidents (Recent Examples)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rare: No major supply chain attacks in stable; focus on backporting upstream fixes.&lt;/td&gt;
&lt;td&gt;Frequent: 2025 chalk/debug compromise (2.6B weekly downloads at risk); event-stream hijack (2018).&lt;/td&gt;
&lt;td&gt;Frequent: 2025 campaigns with thousands of malicious packages; Lolip0p malware (2023, 550+ downloads).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User-Side Protections&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in: &lt;code&gt;apt&lt;/code&gt; verifies signatures; unattended-upgrades for auto-security fixes.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm install --ignore-scripts&lt;/code&gt; to block lifecycle hooks; SCA tools for SBOM generation.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pip install --require-hashes&lt;/code&gt;; virtual environments; avoid running as root.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Insights for Developers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debian’s Fortress&lt;/strong&gt;: Debian’s stable repository is a gold standard for security, with vetted maintainers, signed packages, and extensive testing. It’s ideal for production servers where stability is paramount, but its slow release cycle may lag for cutting-edge features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npmjs and PyPI’s Open Gates&lt;/strong&gt;: Both npmjs and PyPI prioritize accessibility, allowing anyone to publish with minimal checks. This enables rapid innovation but leaves them vulnerable to typosquatting and malware (e.g., thousands of malicious PyPI packages in 2025). Their reactive approach relies on community reporting and post-install audits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What You Can Do&lt;/strong&gt;: For npmjs and PyPI, adopt a “trust but verify” mindset. Use locked dependencies (&lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;), run tools like &lt;code&gt;npm audit&lt;/code&gt; or &lt;code&gt;pip-audit&lt;/code&gt;, and integrate security scans into CI/CD pipelines. For Debian, leverage &lt;code&gt;apt&lt;/code&gt;’s built-in protections and keep systems updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stay Safe in the Ecosystem
&lt;/h2&gt;

&lt;p&gt;Debian’s rigorous gatekeeping makes it a low-risk choice for deployments, while npmjs and PyPI require proactive vigilance from developers. By understanding these differences, you can better secure your projects against supply chain attacks.&lt;/p&gt;

&lt;p&gt;For more details, check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.debian.org/security/faq" rel="noopener noreferrer"&gt;Debian Security FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/auditing-package-vulnerabilities" rel="noopener noreferrer"&gt;npm Security Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pypi.org/security/" rel="noopener noreferrer"&gt;PyPI Security Policy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>npm</category>
      <category>debian</category>
      <category>pypi</category>
      <category>worm</category>
    </item>
    <item>
      <title>Setting Up IOMete: A Cloud-Independent Data Platform Based on Spark</title>
      <dc:creator>Jacob</dc:creator>
      <pubDate>Tue, 10 Jun 2025 14:38:25 +0000</pubDate>
      <link>https://forem.com/jverhoeks/setting-up-iomete-a-cloud-independent-data-platform-based-on-spark-4b23</link>
      <guid>https://forem.com/jverhoeks/setting-up-iomete-a-cloud-independent-data-platform-based-on-spark-4b23</guid>
      <description>&lt;p&gt;IOMete is a powerful, cloud-independent data platform built on Apache Spark, designed to enable scalable data processing and analytics. This guide walks you through the process of setting up IOMete on a Kubernetes cluster, covering the installation of prerequisites, configuration of storage and database components, and deployment of the IOMete data plane. By the end, you’ll have a fully functional IOMete environment ready for data workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving into the installation, ensure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster (version 1.21 or higher recommended).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; configured to interact with your cluster.&lt;/li&gt;
&lt;li&gt;Helm (version 3.x) installed for managing chart deployments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;yq&lt;/code&gt; (a YAML processor) installed for modifying configuration files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws-cli&lt;/code&gt; installed for interacting with MinIO (configured as an S3-compatible storage).&lt;/li&gt;
&lt;li&gt;At least 32GB of RAM and 4 CPU cores available in your cluster for IOMete’s components.&lt;/li&gt;
&lt;li&gt;Access to the IOMete Helm chart repository and configuration files on GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide assumes you’re comfortable with basic Kubernetes and Helm commands. Let’s get started!&lt;/p&gt;




&lt;h2&gt;
  
  
  Downloading Configuration Files
&lt;/h2&gt;

&lt;p&gt;To begin, you’ll need to download the necessary configuration files from the IOMete GitHub repository. These files include Custom Resource Definitions (CRDs), service accounts, certificate generation scripts, and example configurations for the data plane, Istio gateways, PostgreSQL, and MinIO.&lt;/p&gt;

&lt;p&gt;Run the following commands to fetch the files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/iomete-crds.yaml
wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/service-account.yaml
wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/gencerts.sh
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x gencerts.sh
wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/on-prem/example-data-plane-values.yaml
wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/istio-ingress/gateway-http.yaml
wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/istio-ingress/gateway-https.yaml
wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/database/postgresql/postgresql-values.yaml
wget https://raw.githubusercontent.com/iomete/iomete-deployment/main/minio/minio-test-deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These files provide the foundation for deploying IOMete’s components. The gencerts.sh script, for example, generates certificates for the Spark operator webhook, while example-data-plane-values.yaml serves as a template for configuring the IOMete data plane.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shrinking CRD Size for Kubernetes
&lt;/h2&gt;

&lt;p&gt;Some Kubernetes environments impose a size limit on Custom Resource Definitions (CRDs), such as 256KB. The iomete-crds.yaml file may exceed this limit due to included descriptions. To address this, you can use the yq tool to remove the description fields, reducing the file size.&lt;/p&gt;

&lt;p&gt;Execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yq &lt;span class="s1"&gt;'del(.. | .description?)'&lt;/span&gt; iomete-crds.yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; iomete-crds-small.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a new file, iomete-crds-small.yaml, which is compatible with environments that enforce CRD size restrictions. You’ll use this file in later steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Helm Repositories
&lt;/h2&gt;

&lt;p&gt;IOMete relies on several Helm charts from different repositories, including Bitnami (for PostgreSQL), Istio (for networking), and IOMete’s own chart repository. Add and update these repositories with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo add iomete https://chartmuseum.iomete.com
helm repo update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures you have access to the latest versions of the required charts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the IOMete Namespace and Core Components
&lt;/h2&gt;

&lt;p&gt;Next, create a dedicated namespace for IOMete and apply the necessary configurations, including the CRDs, service account, and Spark operator webhook certificates.&lt;/p&gt;

&lt;p&gt;Run these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace iomete-system
kubectl label namespace iomete-system iomete.com/managed&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; iomete-crds-small.yaml
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system &lt;span class="nt"&gt;-f&lt;/span&gt; service-account.yaml

./gencerts.sh &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system &lt;span class="nt"&gt;-s&lt;/span&gt; spark-operator-webhook &lt;span class="nt"&gt;-r&lt;/span&gt; spark-operator-webhook-certs
&lt;span class="c"&gt;# `spark-operator-webhook.yaml` file will be generated by the script above&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system &lt;span class="nt"&gt;-f&lt;/span&gt; spark-operator-webhook.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what each step does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates the iomete-system namespace and labels it for IOMete
management. &lt;/li&gt;
&lt;li&gt;Applies the downsized CRDs to define IOMete’s custom resources. &lt;/li&gt;
&lt;li&gt;Sets up a service account for IOMete’s components.&lt;/li&gt;
&lt;li&gt;Generates and applies certificates for the Spark operator webhook,
enabling secure communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploying MinIO for Storage
&lt;/h2&gt;

&lt;p&gt;IOMete uses MinIO, an S3-compatible object storage, as its default storage backend. Deploy MinIO with the provided test configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system &lt;span class="nt"&gt;-f&lt;/span&gt; minio-test-deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To interact with MinIO, set up port forwarding to access its web interface or API. Open a new terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/minio 9000:9000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating an S3 Bucket in MinIO&lt;/p&gt;

&lt;p&gt;With MinIO running, create a bucket named lakehouse for IOMete’s data storage. Use the aws-cli to configure access and create the bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# export access key and secret key&lt;/span&gt;
&lt;span class="c"&gt;# If you changed the default values, please update the following values accordingly&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_ENDPOINT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:9000

&lt;span class="c"&gt;# create s3 bucket&lt;/span&gt;
aws s3 mb s3://lakehouse

&lt;span class="c"&gt;# verify buckets&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://lakehouse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set environment variables for MinIO’s default credentials (admin/password) and endpoint.&lt;/li&gt;
&lt;li&gt;Create the lakehouse bucket.&lt;/li&gt;
&lt;li&gt;Verify the bucket’s creation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once done, close the port-forwarding session with Ctrl+C.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying PostgreSQL
&lt;/h2&gt;

&lt;p&gt;IOMete requires a PostgreSQL database for metadata and configuration. Install PostgreSQL using the Bitnami Helm chart and the provided configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system postgresql bitnami/postgresql &lt;span class="nt"&gt;-f&lt;/span&gt; postgresql-values.yaml
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;postgresql &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The helm upgrade --install command ensures PostgreSQL is installed or updated. The --watch flag monitors the pod’s status. Wait until the PostgreSQL pod is in the Running state, then press Ctrl+C to exit the watch command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the IOMete Data Plane
&lt;/h2&gt;

&lt;p&gt;Before deploying IOMete, verify and customize the example-data-plane-values.yaml file to match your environment. Below is an example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
 &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgresql"&lt;/span&gt;
 &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432"&lt;/span&gt;
 &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iomete_user"&lt;/span&gt;
 &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iomete_pass"&lt;/span&gt;
 &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iomete_"&lt;/span&gt; &lt;span class="c1"&gt;# all IOMETE databases should be prefixed with this. See database init script.&lt;/span&gt;
 &lt;span class="na"&gt;ssl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;# Enabling this will require javaTrustStore to be enabled and configured properly&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disable"&lt;/span&gt; &lt;span class="c1"&gt;# disable, verify-full&lt;/span&gt;
 &lt;span class="na"&gt;adminCredentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgres"&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;postgresql&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;master&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;password"&lt;/span&gt;

&lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lakehouse"&lt;/span&gt;
 &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minio"&lt;/span&gt;
 &lt;span class="na"&gt;minioSettings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://minio:9000"&lt;/span&gt;
  &lt;span class="na"&gt;accessKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin"&lt;/span&gt;
  &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password"&lt;/span&gt;

&lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;httpsEnabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iomete.azurecr.io/iomete&lt;/span&gt;
 &lt;span class="na"&gt;pullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
 &lt;span class="na"&gt;defaultSparkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.5.3-v13&lt;/span&gt;
 &lt;span class="na"&gt;additionalSparkVersions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3.4.0-v12&lt;/span&gt;
 &lt;span class="na"&gt;tagAliases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;latest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.5.3-v13&lt;/span&gt;

&lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;activityMonitoring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key configurations include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database: Points to the PostgreSQL instance with credentials and prefix settings.&lt;/li&gt;
&lt;li&gt;Storage: Configures the MinIO lakehouse bucket with default credentials.&lt;/li&gt;
&lt;li&gt;Ingress: Disables HTTPS for simplicity (enable it for production).&lt;/li&gt;
&lt;li&gt;Docker: Specifies the IOMete container registry and Spark versions.&lt;/li&gt;
&lt;li&gt;Features: Enables activity monitoring for tracking usage.&lt;/li&gt;
&lt;li&gt;Replace  with the actual PostgreSQL admin password defined in postgresql-values.yaml. Adjust other settings as needed for your environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploying the IOMete Data Plane
&lt;/h2&gt;

&lt;p&gt;With all prerequisites in place, deploy the IOMete data plane using the Helm chart. This step initializes the database, configures storage, and starts all necessary pods. The deployment requires at least 32GB of RAM and 4 CPUs.&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system data-plane iomete/iomete-data-plane-enterprise &lt;span class="nt"&gt;-f&lt;/span&gt; data-plane-values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deployment may take a few minutes as Helm sets up the initialization job and starts the pods. Monitor the progress with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; iomete-system &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Accessing the IOMete Web Interface
&lt;/h2&gt;

&lt;p&gt;Once the deployment is complete, access the IOMete web interface by forwarding the iom-gateway service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/iom-gateway 8888:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser and navigate to &lt;a href="http://localhost:8888" rel="noopener noreferrer"&gt;http://localhost:8888&lt;/a&gt;. Log in with the default credentials:&lt;/p&gt;

&lt;p&gt;Username: admin&lt;br&gt;
Password: admin&lt;/p&gt;

&lt;p&gt;Change the default password after logging in for security.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzppauqrkyz4vxvjavi12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzppauqrkyz4vxvjavi12.png" alt="Image description" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Congratulations! You’ve successfully set up IOMete as a cloud-independent data platform. From here, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure data sources and Spark jobs in the IOMete UI.&lt;/li&gt;
&lt;li&gt;Enable HTTPS for secure access by updating the ingress settings.&lt;/li&gt;
&lt;li&gt;Scale the cluster to handle larger workloads.&lt;/li&gt;
&lt;li&gt;Explore IOMete’s documentation for advanced features like multi-tenancy and monitoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you encounter issues, check the pod logs in the iomete-system namespace with kubectl logs or consult the IOMete documentation.&lt;/p&gt;

&lt;p&gt;This setup provides a robust foundation for running Spark-based data workloads in a cloud-agnostic environment. Let us know in the comments if you have questions or tips for optimizing your IOMete deployment!&lt;/p&gt;

&lt;h2&gt;
  
  
  Preview
&lt;/h2&gt;

&lt;p&gt;Data Domain/Workspace &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuzmvi2p3wxwjlhwu71g4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuzmvi2p3wxwjlhwu71g4.png" alt="Image description" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SQL Editor &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wu9o2wxp5z4s4hj62nh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wu9o2wxp5z4s4hj62nh.png" alt="Image description" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DBT-Core&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fol6j6p8nlyry28gc4xr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fol6j6p8nlyry28gc4xr1.png" alt="Image description" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>iomete</category>
      <category>spark</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
