ADR-0002: Use Terraform for infrastructure as code¶
Status¶
Accepted
Context¶
Infrastructure needs to be provisioned consistently and reproducibly. Manual Azure portal changes are error-prone and not auditable. The main IaC options considered were:
- Terraform -- HashiCorp's multi-cloud IaC tool (HCL)
- Bicep -- Azure-native IaC (ARM template DSL)
- Pulumi -- IaC using general-purpose programming languages
- Azure CLI scripts -- Imperative shell scripts
Decision¶
Use Terraform (version >= 1.6.6) with the azurerm provider (~> 4.60) for all infrastructure provisioning.
Infrastructure is organized as:
terraform/
├── backend/ # State backend bootstrapping (local state)
├── modules/ # Reusable modules (postgres-flex, rbac, resource-group, swa)
└── envs/ # Environment root modules (shared, site)
Consequences¶
Positive¶
- Multi-cloud portability -- If the organization moves to AWS or GCP, Terraform skills and patterns transfer. Modules would need rewriting, but the workflow stays the same.
- State management -- Terraform tracks resource state, enabling safe plans and applies. Drift detection comes for free.
- Module system -- Reusable modules (
postgres-flex,swa, etc.) reduce duplication across environments. - Ecosystem -- Largest IaC ecosystem with extensive provider support and community modules.
- PR-based workflow --
terraform planon PRs,terraform applyon merge. Changes are reviewed before applying.
Negative¶
- HCL learning curve -- HCL is a domain-specific language, not a general-purpose language. Contributors need to learn it.
- State file management -- Remote state requires storage accounts and careful access control. State corruption can be difficult to recover from.
- Provider version management -- Provider updates can introduce breaking changes requiring module updates.
Neutral¶
- Terraform is not Azure-native (unlike Bicep), but the azurerm provider covers all services used by this organization.
- HashiCorp's licensing changes (BSL) don't affect this use case.