Skip to main content

OpenTofu

OpenTofu is the open-source infrastructure-as-code engine that plans and applies the platform's modules: it reads the configuration, compares it with the recorded state and the cloud, and changes only the difference. The Azure Enterprise Baseline and the Azure Web App and Data and ETL Blueprints pin OpenTofu 1.12.6 and run it through Terragrunt.

What it does​

A module is a folder of resources and variables. A provider is the plugin that talks to one API (Azure Resource Manager, Microsoft Graph, Databricks). A plan shows the changes a configuration would make; an apply makes them and records the result in state, kept in a backend with a lock so two runs cannot write at once. Version constraints pin the engine and every provider so a run tomorrow behaves like a run today.

How BuiltForProd uses it​

One engine version. Every root.hcl sets terraform_version_constraint = ">= 1.12.6, < 2.0.0", the workflows install 1.12.6 through the setup-opentofu action, and the Container Apps runner image carries the same version, checksum-verified.

Providers. root.hcl generates each unit's versions.tf, the only place providers are pinned:

ProviderConstraintUsed in
hashicorp/azurerm~> 5.7Every infrastructure repository
hashicorp/azuread~> 3.10Azure Enterprise Baseline: groups, Conditional Access, federated credentials
Azure/azapi~> 2.13Azure Enterprise Baseline: settings azurerm does not cover, such as DNSSEC
hashicorp/time~> 0.13Four Baseline modules, to wait for role assignments to propagate
hashicorp/random~> 3.7Web App Blueprint
hashicorp/helm~> 3.3Web App Blueprint: ArgoCD, cert-manager, External Secrets Operator
hashicorp/kubernetes~> 3.2Web App Blueprint: namespaces, NAP objects, issuers, the ArgoCD Application
databricks/databricks~> 1.135Data and ETL Blueprint: catalog, grants, job

A module ships its own versions.tf only when it uses a provider alias or a provider root.hcl does not pin, and then repeats the pins exactly; scripts/check-module-versions.py enforces it in pre-commit and CI.

Modules. Every module is local to its repository, thin and limited to one resource category; none comes from a registry, and tflint is told to lint only the repository's own code.

State. The azurerm backend keeps every unit's state as one blob in the storage account stacmeeus2roottfstate, container tfstate, in acme-core-root, locked with a blob lease and keyed by the unit's path. Access is Microsoft Entra only, with the GitHub OIDC token in CI. The Baseline identity and ACME_PlatformLeads write the whole container; the web app and ETL infrastructure identities write only below apps/app-blueprint/ and apps/etl-blueprint/ through the custom role acme-tfstate-prefix-contributor with a path condition; ACME_PlatformEngineers read; the code pipelines have no state access. See Azure Storage for the account's protection.

Terms you will see​

TermMeaning
ProviderThe plugin for one API, pinned in the generated versions.tf.
Version constraintThe allowed engine or provider versions, such as ~> 5.7.
StateOpenTofu's record of what it manages, one blob per unit.
Blob lease lockThe backend's lock that keeps two runs from writing one state.
Local moduleA module in the repository itself; no registry downloads.

Where to read more​