Skip to content

Infrastructure as Code · Platforms as Code

One pull request. An entire landing zone.

Terraform is the visible ten percent. The package is a separately versioned module repo, thin per-environment deployments, pipelines on whichever CI you already run, and the custom scripts that make the whole thing tick: firewall rules from a spreadsheet, peering that generates itself, version bumps that open their own pull requests.

Tooling
Terraform · Terragrunt
Clouds
AWS · Azure · GCP
Pipelines
GitHub · ADO · CodePipeline
modules separate repo network/ firewall/ compute/ v2.4.1 ci / cd test · tag · bump plan · approve · apply dev terragrunt.hcl → v2.4.1 staging terragrunt.hcl → v2.4.1 prod terragrunt.hcl → v2.4.1 landing zone released pipelined versioned per env applied

Stack configurator

Pick a cloud. Pick a pipeline. The package writes itself.

This is not a menu of things we can do. It is one coherent system that reshapes itself around your choices: the same module structure, the same release cycle, the same validation, whichever provider or CI you already use.

Cloud
CI / CD
Environments

scroll sideways →

Pipeline stages

    tree -L 3
     

    Release flow

    Modules ship like software. Environments follow automatically.

    The module repo has its own release cycle: tests, semantic versions, a changelog. When a version lands, tooling opens the version-bump pull requests in every deployment repo for you. Nobody edits forty terragrunt files by hand, and nobody forgets one.

    scroll sideways →

    Module PR network: add NAT option Tests unit + integration Release semver from commits Bump PRs deployment repos v2.4.1 modules dev plan · gate · apply staging plan · gate · apply prod plan · gate · apply bump PRs → live repo
    1. 01 Module PR

      PR #142 opened against modules/network

    2. 02 Tests

      terraform test · 14 passed · integration: real VNet built and destroyed

    3. 03 Release

      feat: → minor bump · tagged v2.4.1 · CHANGELOG generated

    4. 04 Bump PRs

      3 PRs opened in live repo: network → v2.4.1 (dev, staging, prod)

    5. 05 Plan

      dev: 2 to add, 1 to change, 0 to destroy · posted to PR

    6. 06 Approval

      staging + prod held on environment protection rule · approved by reviewer

    7. 07 Apply

      apply dev 38s ✓ · staging 41s ✓ · prod 44s ✓ · drift: none

    loops continuously · one human decision per release, everything else is the pipeline's problem

    The parts nobody shows you

    Terraform is the easy bit. This is what makes it tick.

    Every conference talk stops at `terraform apply`. The work that keeps a platform honest for years is the glue around it: validation, generation, versioning and the scripts that turn a folder of HCL into something a team can actually run.

    Firewall rules as a spreadsheet

    01

    Security reviews a CSV, not HCL. CI rejects overlapping ports, missing owners and any rule without a ticket reference before it can reach a plan.

    # config/firewall-rules.csvenv,name,direction,priority,src,dst,port,proto,owner,refprod,allow-web-in,Inbound,200,Internet,web-subnet,443,Tcp,platform,CHG0042prod,allow-app-db,Inbound,210,app-subnet,db-subnet,5432,Tcp,data,CHG0042✓ validate: 118 rules · 0 conflicts · 0 missing refs

    Peering that generates itself

    02

    One YAML file describes which networks talk. The module emits both directions of every peering, route tables included. Add a network, the mesh updates. Remove one, it is cleanly torn down.

    # config/peering.yamlhub: prod-hubspokes: [prod-app, prod-data, staging-app]mesh: [prod-app, prod-data]→ 8 peerings · 8 route tables · 0 hand-written

    Version bumps you never type

    03

    Terragrunt tooling watches module releases and opens the pull requests in the deployment repos, environment by environment, with the plan attached. You review, you do not chase.

    # staging/network/terragrunt.hclterraform { source = "git::…/modules//network?ref=- v2.3.0"+ v2.4.1" # PR opened by bump-modules}

    Drift you hear about first

    04

    A nightly plan against every environment. Someone clicked in the portal? You get the diff in the morning, not a surprise at the next release.

    $ terragrunt run-all plan -detailed-exitcodeprod/compute: 0 to add, 0 to change, 0 to destroyprod/firewall: 0 to add, 1 to change, 0 to destroy ~ rule allow-rdp-in priority 100 → 4096 (portal edit)→ drift notice posted · owner: platform

    Modules that document themselves

    05

    Inputs, outputs and examples are generated from the code on every release. The README is never out of date because nobody writes it.

    # modules/network/README.md (generated)| Name | Type | Default | Required || address_space | list(string) | n/a | yes || enable_nat | bool | false | no |✓ docs in sync with v2.4.1

    State and secrets, done properly

    06

    Remote state with locking from day one. Secrets come from a key store at plan time and never touch the repo, the pipeline logs or the state file.

    # terragrunt.hcl (root)remote_state { backend = "azurerm" … use_azuread_auth = true }inputs = { db_password = get_env("DB_PASSWORD") # from Key Vault} ✓ 0 secrets in git · 0 in state · 0 in logs

    From portal to code

    You don't rebuild. You take control of what's already there.

    We made this transition ourselves, from clicking in portals to running everything through pipelines. The route that works is incremental: nothing is destroyed, every step leaves you better off than before, and you can stop at any of them.

    1. 01

      Audit

      inventory · dependency map

      We map what exists: every subscription, account or project, what talks to what, what nobody remembers creating. You get the inventory even if you go no further.

    2. 02

      Import

      state · zero-diff plans

      Existing resources are brought under state, not rebuilt. Nothing is destroyed to prove a point. Plans read as zero changes before we touch anything.

    3. 03

      Modularise

      module repo v1.0.0

      The imported sprawl is refactored into the module repo: tested, versioned, documented. Environments become thin terragrunt trees pointing at versions.

    4. 04

      Pipeline

      CI/CD · drift checks

      Plans on every PR, approvals where they matter, applies you can watch. Portal write access gets turned off, and nobody misses it.

    5. 05

      Hand over

      your team, your keys

      Your engineers ship a change end to end with us watching, then without. Docs generate themselves; the runbook is the pipeline.

    Questions we get asked

    Before you ask

    The honest answers, including the ones that involve saying 'it depends'.

    We're already on Bicep, CloudFormation or Pulumi. Do we have to switch? +

    No. Terraform and Terragrunt are our default because they cover all three clouds with one workflow, but the package is the idea, not the syntax: a separately versioned module repo, thin per-environment deployments, validation in CI, and generated glue. We have connected that pattern to existing Bicep and CloudFormation estates, and where switching does make sense we import rather than rebuild.

    Who owns the code? +

    You do, from the first commit. Everything lives in your repositories, runs on your pipelines and uses your cloud identities. There is no Black Mesa-hosted component, no licence and nothing that stops working if we are not around. The hand-over step exists precisely so that your team can run it without us.

    Can one platform span AWS, Azure and GCP? +

    Yes. The module repo is organised per provider with shared conventions, and the deployment tree simply has more branches. The pipeline, the CSV-driven firewall rules, the peering generator and the version-bump tooling are provider-agnostic; only the modules underneath change. Pick a cloud in the configurator above and watch what stays the same.

    How are secrets handled? +

    They never enter the repository or the state file. Pipelines authenticate with workload identity or OIDC (no long-lived keys), and secrets are fetched from Key Vault, Secrets Manager or Secret Manager at plan time. State is remote, encrypted and locked; access to it is scoped per environment.

    How long does it take? +

    A greenfield landing zone with pipelines is typically weeks, not quarters, and you see a working plan in the first few days. Migrating an existing estate depends on its size and how much of it nobody remembers creating, which is why the first step is an audit you keep regardless.

    What happens when something breaks at 3am? +

    The infrastructure side is boring by design: every apply is logged, every version is tagged, and rolling back is a pull request that pins the previous module version. For the rest, this is where the other services close the loop: monitoring that tells you before customers do, and automation that runs the fix without waking anyone.

    Next step

    Tell us what your cloud is doing that it shouldn't.

    Portal sprawl, a Terraform repo nobody dares touch, a pipeline that only one person understands. A short conversation is enough to know whether the package fits.