Skip to content

Terraform Modules

infra/terraform/smb-ready-foundation/
├── azure.yaml # azd manifest (provider: terraform)
├── backend.tf # backend "azurerm" {} partial config
├── versions.tf # terraform >= 1.9 + provider pins
├── providers.tf # azurerm features block + data sources
├── variables.tf # Input surface with validation
├── locals.tf # Derived values (region short, suffix, tags)
├── main.tf # 17 module calls + root import block
├── outputs.tf # Wired to module outputs
├── modules/
│ ├── management-group/ # MG + subscription association
│ ├── policy-assignments-mg/ # 33 MG-scoped policy assignments
│ ├── resource-groups/ # 6 resource groups
│ ├── budget/ # Consumption budget (sub scope)
│ ├── defender/ # Defender for Cloud Free
│ ├── network-hub/ # Hub VNet, NSG, 4 subnets, PDZ
│ ├── network-spoke/ # Spoke VNet, NSG, optional NAT
│ ├── firewall/ # Azure Firewall Basic (conditional)
│ ├── route-tables/ # Spoke + gateway UDRs
│ ├── vpn-gateway/ # VPN Gateway VpnGw1AZ (conditional)
│ ├── peering/ # Hub↔spoke peering
│ ├── monitoring/ # Log Analytics Workspace
│ ├── backup/ # RSV + DefaultVMPolicy
│ ├── policy-backup-auto/ # Sub-scope DINE + role assignments
│ ├── migrate/ # Azure Migrate (azapi_resource)
│ ├── keyvault/ # Key Vault + PE + diag settings
│ └── automation/ # Automation Account + LAW link
├── hooks/ # pre/post-provision (bash + PowerShell)
├── scripts/ # bootstrap-tf-backend + remove
└── tests/
└── scenarios.tftest.hcl
ComponentPinRationale
terraform>= 1.9Required for import block + mock_provider
azurerm~> 4.04.x LTS-equivalent; ~> allows minor upgrades
azapi~> 2.0Needed for Azure Migrate (no azurerm support)
random~> 3.6Available for future SKU suffixing
null~> 3.2Required by terraform_data relay pattern

Unlike the Bicep track, the Terraform track uses raw azurerm_* / azapi_resource instead of AVM-TF registry modules. This is intentional — see ADR-0005 for rationale.

ModuleResourcesConditional
management-groupMG + subscription associationNo
policy-assignments-mg33 MG-scoped policy assignmentsNo
resource-groups6 resource groupsNo
budgetConsumption budgetNo
defender4 pricing tiers + auto-provisioningNo
network-hubVNet, NSG, 4 subnets, PDZNo
network-spokeVNet, NSG, 4 subnets, optional NATNAT conditional
firewallFirewall + policy + 2 rule groupsYes
route-tablesSpoke RT + optional gateway RTYes
vpn-gatewayVPN Gateway + PIPYes
peeringHub↔spoke peeringYes
monitoringLog Analytics WorkspaceNo
backupRSV + DefaultVMPolicyNo
policy-backup-autoDINE policy + 2 role assignmentsNo
migrateAzure Migrate (azapi)No
keyvaultKey Vault + PDZ + PE + diagNo
automationAutomation + LAW link + diagNo
CheckStatus
terraform fmt -check -recursive✅ Pass
terraform init -backend=false✅ Pass
terraform validate✅ Pass (3 cosmetic v5.0 deprecation warnings)
terraform test (6 plan-mode runs)✅ Pass
npm run validate:terraform✅ Pass
npm run validate:iac-security-baseline✅ Pass
AspectBicepTerraform
Scope splitTwo templates (MG + subscription)Single root composes both
AVMAVM-first (13 modules)Raw azurerm (1:1 parity simplifies review)
StateARM deployments (stateless)Remote state in Azure Storage
Unique suffixuniqueString(subscription().subscriptionId)substr(sha1(...), 0, 13)
MG importN/ARoot import block for idempotency