Infrastructure as Code: ARM vs Bicep vs Terraform
Choose and implement the right IaC tool. Compare ARM templates, Bicep, and Terraform for Azure infrastructure. Define IaC strategy including source control, testing, and configuration management.
Why Infrastructure as Code?
Think of building with LEGO instructions vs freestyling.
If you build a spaceship from LEGO instructions, you can rebuild it identically every time. If your friend follows the same instructions, they get the exact same spaceship. If you freestyle, every build is slightly different β and when it breaks, nobody knows how to fix it because there are no instructions.
Infrastructure as Code means writing instructions (code) for your cloud resources instead of clicking through the Azure portal. The code is your LEGO instructions β repeatable, shareable, version-controlled, and testable.
The Three IaC Tools for Azure
ARM Templates
Azure Resource Manager (ARM) templates are the native Azure IaC format β JSON files that define resources declaratively. Every Azure resource supports ARM because ARM is the underlying deployment engine.
// Simplified example β not complete
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-09-01",
"name": "claims-api",
"location": "[resourceGroup().location]",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'claims-plan')]"
}
}
]
ARM templates are verbose but universally supported. Every Azure resource type is available on day one because ARM is the deployment layer itself.
Bicep
Bicep is a domain-specific language (DSL) that compiles to ARM JSON. It provides a cleaner, more readable syntax while producing the same ARM deployment.
resource appService 'Microsoft.Web/sites@2022-09-01' = {
name: 'claims-api'
location: resourceGroup().location
properties: {
serverFarmId: plan.id
}
}
Bicep is not a separate deployment engine β it transpiles to ARM. This means every ARM feature is available in Bicep, and Bicep inherits ARMβs same-day resource support.
Terraform (with AzureRM Provider)
Terraform by HashiCorp is a multi-cloud IaC tool. The AzureRM provider enables Azure resource management using HCL (HashiCorp Configuration Language).
resource "azurerm_linux_web_app" "claims" {
name = "claims-api"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
service_plan_id = azurerm_service_plan.main.id
}
Terraform manages state in a state file that maps declared resources to real Azure resources. This state file is critical β lose it and Terraform cannot manage your existing infrastructure.
ARM vs Bicep vs Terraform
| Capability | ARM Templates | Bicep | Terraform |
|---|---|---|---|
| Language | JSON | Bicep DSL (compiles to ARM JSON) | HCL (HashiCorp Configuration Language) |
| Cloud support | Azure only | Azure only | Multi-cloud (Azure, AWS, GCP, 3000+ providers) |
| State management | Azure handles state (no state file) | Azure handles state (no state file) | External state file required (local, Azure Blob, Terraform Cloud) |
| New resource support | Day-one for all Azure resources | Day-one (compiles to ARM) | Depends on provider update cycle (can lag days to weeks) |
| Readability | Low β verbose JSON, repetitive | High β clean syntax, type safety | High β declarative HCL, familiar to multi-cloud teams |
| Modularity | Linked/nested templates (complex) | Modules with typed parameters | Modules with input/output variables |
| What-if / Plan | az deployment what-if | az deployment what-if (same as ARM) | terraform plan (detailed diff output) |
| Secret handling | secureString parameter type | Decorated with @secure() | sensitive = true hides from CLI output; values still stored in state file β encrypt and restrict access |
| Tooling | VS Code ARM extension | VS Code Bicep extension (IntelliSense, linting) | VS Code Terraform extension, TFLint, Checkov |
| Learning curve | Steep (JSON verbosity, expression syntax) | Gentle (if you know ARM concepts) | Moderate (new language, state concepts) |
| Destroy support | Complete deployment mode (dangerous) | Complete deployment mode (dangerous) | terraform destroy (shows plan first, supports -target) |
| Best for | Legacy templates, maximum compatibility | Azure-only teams wanting clean syntax | Multi-cloud or teams already invested in Terraform |
Terraform State Management
Terraform state is the most critical operational concern when using Terraform:
- Remote backend β store state in Azure Blob Storage (encrypted at rest, versioning for recovery)
- State locking β use blob lease locking to prevent concurrent modifications
- State encryption β Azure Blob Storage encrypts at rest; for additional security, use customer-managed keys
- State file contents β contains resource IDs, attributes, and potentially sensitive outputs. Treat it as confidential.
terraform {
backend "azurerm" {
resource_group_name = "tfstate-rg"
storage_account_name = "tfstatestorage"
container_name = "tfstate"
key = "prod.terraform.tfstate"
}
}
Scenario: Jordan selects the right IaC tool
βοΈ Jordan at Cloudstream Media faces a common decision. The company runs:
- Core platform β Azure-only (App Services, SQL, Redis, Storage)
- CDN and edge β Cloudflare (not Azure)
- Video processing β some AWS Lambda functions (legacy)
Jordan recommends a split strategy:
- Bicep for all Azure-only infrastructure (App Services, databases, networking) β cleaner syntax, day-one support, no state file to manage
- Terraform for the cross-cloud pieces (Cloudflare DNS, AWS Lambda) β multi-provider support in a single tool
For the exam, remember: if the scenario is Azure-only, recommend Bicep. If multi-cloud is involved, recommend Terraform. If maintaining legacy templates, ARM is acceptable but suggest migrating to Bicep.
IaC Strategy: Source Control, Testing, and Deployment
Source Control for IaC
- Store IaC templates in the same repository as application code (monorepo) or a dedicated infrastructure repository (if infra team is separate)
- Use pull requests for all IaC changes β peer review catches resource misconfigurations before deployment
- Branch protection β require at least one reviewer and passing CI checks before merging
- Tag releases for infrastructure versions (e.g.,
infra-v2.4.0)
Testing IaC
| Test Type | What It Validates | Tool |
|---|---|---|
| Linting | Syntax, style, best practices | Bicep linter, TFLint, ARM-TTK |
| Static analysis | Security and compliance rules | Checkov, tfsec, PSRule for Azure |
| What-If / Plan | Preview changes before applying | az deployment what-if, terraform plan |
| Policy validation | Azure Policy compliance | Azure Policy (deny effect), OPA/Conftest |
| Integration testing | Deploy to ephemeral environment, validate, destroy | Terratest (Go), Pester (PowerShell) |
Pipeline Deployment Pattern
Lint β Static Analysis β What-If/Plan β Manual Approval β Deploy β Smoke Test
For Bicep:
- task: AzureCLI@2
inputs:
azureSubscription: 'MyAzureConnection'
scriptType: 'bash'
inlineScript: |
az deployment group what-if \
--resource-group myRG \
--template-file main.bicep \
--parameters @params.json
For Terraform:
- script: |
terraform init
terraform plan -out=tfplan
displayName: 'Terraform Plan'
- script: terraform apply tfplan
displayName: 'Terraform Apply'
Exam tip: When to recommend which IaC tool
The exam presents scenarios and expects you to select the right tool:
| Scenario | Recommend |
|---|---|
| Azure-only, new project, clean start | Bicep |
| Multi-cloud (Azure + AWS or GCP) | Terraform |
| Existing ARM templates, no migration budget | ARM Templates (suggest Bicep migration roadmap) |
| Team already uses Terraform for other clouds | Terraform (consistency across clouds) |
| Need day-one support for preview Azure resources | Bicep (Terraform provider may lag) |
| Want to avoid managing state files | Bicep (ARM handles state) |
| Government/regulated requiring strict version control of infra state | Terraform (explicit state enables drift detection) |
| Configuration management of OS-level settings | Neither β use Azure Machine Configuration or Automation DSC (covered in Module 18) |
Jordan's team manages infrastructure across Azure and AWS. They want a single IaC tool with consistent workflow across both clouds. Which tool should Jordan recommend?
A team using Terraform accidentally deletes the state file from their local machine. They have real Azure resources running in production. What is the impact and recovery path?
Which IaC testing approach validates that a Bicep template will not create resources that violate organisational security policies (e.g., storage accounts must enforce HTTPS)?
π¬ Video coming soon
ARM vs Bicep vs Terraform
Next up: IaC in Practice: Desired State and Deployment Environments