ADR 0004 — Bicep over Terraform as primary IaC (for now; Terraform path planned)¶
Context and Problem Statement¶
CSA-in-a-Box provisions Azure landing zones (DMLZ + DLZ), data services, networking, and governance policies. We need a single primary IaC language for the core modules (deploy/bicep/DMLZ/, deploy/bicep/DLZ/, deploy/bicep/gov/). Federal and CCoE teams tend to standardize on either Bicep or Terraform, and the choice affects contributor velocity, API coverage, and multi-cloud readiness.
Decision Drivers¶
- First-party Azure API coverage — new Azure resource types and API versions are available in Bicep on day one via ARM; Terraform's AzureRM provider lags by weeks to months.
- Azure Government parity — Bicep uses the ARM control plane that is identical across Commercial, Gov, and sovereign clouds.
- Microsoft CAE/CCoE alignment — the Enterprise-Scale Landing Zone reference (see
deploy/bicep/landing-zone-alz/) is authored in Bicep; adopting Terraform would require maintaining a fork. - Contributor skill pool — our primary contributors are Azure-native platform engineers; Bicep authoring is lower friction than HCL for this audience.
- Escape hatch — we must not paint ourselves into a corner; a Terraform path should remain viable for customers with a Terraform-primary CCoE.
Considered Options¶
- Bicep (chosen) — ARM-native, day-one API coverage, CAE-aligned, no state file to manage.
- Terraform (AzureRM + AzAPI providers) — Multi-cloud, large community, mature module registry, but state-file management and provider lag.
- Pulumi — General-purpose languages, multi-cloud, but small Azure community and another binary in the toolchain.
- Azure CLI scripts — No IaC benefits; rejected on day one.
Decision Outcome¶
Chosen: Option 1 — Bicep for all core modules. A Terraform path is planned (not implemented) and will be opened once the module surface is stable, via either a Bicep-to-Terraform generator or a parallel Terraform-authored module set that consumes the same parameter contracts.
Consequences¶
- Positive: Day-one Azure API coverage, including preview features needed for Purview, Unity Catalog, and Fabric.
- Positive: No state-file custody problem — ARM is the state store; reduces ATO surface area.
- Positive: Aligns with the Enterprise-Scale Landing Zone canonical pattern (
deploy/bicep/landing-zone-alz/). - Positive: Low contributor friction for Azure-native engineers;
what-ifis built in. - Negative: Not multi-cloud; explicitly locks core IaC to Azure.
- Negative: Ecosystem is smaller than Terraform's — fewer public modules to borrow from.
- Negative: Linting/testing tooling (Bicep linter, PSRule) is less mature than Terraform's (tflint, checkov, terratest).
- Neutral: A Terraform path remains open; customers with a Terraform-primary CCoE are not blocked from contributing a parallel module tree.
Pros and Cons of the Options¶
Option 1 — Bicep¶
- Pros: ARM-native; day-one API coverage; no state file; Gov parity; CAE aligned; low authoring friction for Azure engineers;
what-ifbuilt in. - Cons: Azure-only; smaller ecosystem; less mature test tooling.
Option 2 — Terraform¶
- Pros: Multi-cloud; huge module registry; mature testing (terratest); mature policy-as-code (Sentinel / OPA).
- Cons: Provider lag behind ARM; state-file custody (storage, locking, encryption) is a compliance burden; AzAPI required for preview features adds complexity.
Option 3 — Pulumi¶
- Pros: Real programming languages; multi-cloud; strong type system.
- Cons: Small Azure user base; extra runtime in the toolchain; state-file issues similar to Terraform.
Option 4 — Azure CLI scripts¶
- Pros: Zero tooling overhead.
- Cons: No idempotency; no drift detection; not IaC in any meaningful sense.
Validation¶
We will know this decision is right if:
- New vertical examples can stand up a landing zone in <90 minutes using only Bicep modules.
- Azure preview features required for Purview / Unity Catalog / Fabric land in our modules within one release cycle of GA.
- If more than one enterprise customer blocks adoption on Terraform-only CCoE policy, accelerate the Terraform path to parity.
References¶
- Decision tree: n/a (no dedicated decision tree; see architecture matrix)
- Related code:
deploy/bicep/DMLZ/main.bicep,deploy/bicep/DLZ/main.bicep,deploy/bicep/gov/main.bicep,deploy/bicep/bicepconfig.json,deploy/bicep/landing-zone-alz/ - Framework controls: NIST 800-53 CM-2 (baseline configuration via versioned IaC), CM-3 (change control through PR review), CM-6 (configuration settings enforced in code), SA-10 (developer configuration management). See
governance/compliance/nist-800-53-rev5.yaml. - Discussion: CSA-0087