Skip to main content

Terragrunt

Terragrunt is a thin wrapper around OpenTofu that generates the repetitive parts of every configuration, wires units together through their outputs and runs many of them in dependency order. The GCP Enterprise Baseline and the GCP Web App and Data and ETL Blueprints pin Terragrunt 1.1.6 and use its Stacks layout.

What it does​

A unit is one terragrunt.hcl: one module, one state, its inputs. A stack file (terragrunt.stack.hcl) lists units, or other stack templates, with values, and terragrunt stack generate writes the units into a .terragrunt-stack/ folder. A dependency block reads another unit's outputs; mock outputs stand in for them during validate and plan before that unit exists. generate blocks write files such as backend.tf and provider.tf into every unit, and run --all runs a command over a whole tree in dependency order.

How BuiltForProd uses it​

Layout. Every environments/<group>/<name>/<region or global>/ folder holds one stack file, and the units it lists come from units/. Generated units land in .terragrunt-stack/, which is git-ignored and never edited.

RepositoryTemplates and unitsA stage file holds
GCP Enterprise Baseline32 unit definitions; stacks/plat-project for each stage project, stacks/includes/project-common.stack.hcl for each core projectThe units of each core project; the template for each plat project
Web App Blueprintstacks/webapp-stage, 11 units in shared-infra/ and blueprint-app/Only values: GKE zones and limits, Cloud Armor preview, data-store protection, ArgoCD sync and HA
Data and ETL Blueprintstacks/etl-stage, 5 units in shared-infra/ and blueprint-etl/Only values: lake location, soft delete, CMEK, discovery, Spark sizing

Switch files. The Baseline's feature switches live in four files, each switch on one line with its price: environments/core/security/security.hcl, environments/core/network/us-west1/network.hcl, environments/core/identity/identity.hcl and environments/plat/plat.hcl.

Identities in root.hcl. The generated providers impersonate the target project's deployer sa-acme-terraform-deployer in CI, and locally when TG_IMPERSONATE=1 is set; otherwise engineers run with their own credentials. Units marked by an org-scoped.hcl file act on the organization, the folders or several projects, which a per-project deployer cannot reach, so they never impersonate and run in CI as sa-acme-baseline-ci:

GCP/acme-gcp-platform-baseline/root.hcl (lines 98-104)
is_ci = get_env("CI", "false") == "true"
is_org_scoped = fileexists("${get_terragrunt_dir()}/org-scoped.hcl")
use_chain = !local.is_org_scoped && (local.is_ci || get_env("TG_IMPERSONATE", "0") == "1")
deployer_sa = "sa-${local.namespace}-terraform-deployer@${local.target_project_id}.iam.gserviceaccount.com"
impersonate_sa = local.use_chain ? local.deployer_sa : ""
# The provider.tf line (with its leading newline) that switches the chain on; empty without a chain.
impersonate_attr = local.impersonate_sa == "" ? "" : "\n impersonate_service_account = \"${local.impersonate_sa}\""

Each generated provider.tf also declares one alias per core project (google.root, google.host, google.network, google.dns, google.auto, google.security, google.audit, google.artifacts), each impersonating that project's own deployer. The blueprints generate aliases for the core projects they write into, all impersonating the stage deployer; see service accounts.

Project identities. The organizations unit writes org_projects.hcl with the organization, folder and project IDs and numbers after every apply, through scripts/write-org-projects.py; the file is committed and root.hcl reads it in every clone and in CI, with a deterministic naming fallback. Nothing in root.hcl calls gcloud.

Dependencies. Every dependency carries complete mock outputs, which scripts/check-mock-outputs.py enforces, so a new environment plans end to end before its dependencies exist; an apply always uses real outputs.

Terms you will see​

TermMeaning
UnitOne module with its inputs and its own state.
Stack templateA reusable stack such as plat-project or webapp-stage.
Generated tree.terragrunt-stack/, written by stack generate, never edited.
Organization-scoped unitA unit marked by org-scoped.hcl that runs without impersonation.
Switch fileOne of the four files that hold the Baseline's feature switches.

Where to read more​