You are viewing a free preview of this lesson.
Subscribe to unlock all 10 lessons in this course and every other course on LearningBro.
Adopting Infrastructure as Code is not just about choosing a tool — it requires disciplined practices around code organisation, testing, security, CI/CD integration, and governance. This lesson consolidates best practices for running IaC on Azure in production.
| Scenario | Recommended tool |
|---|---|
| Azure-only, Microsoft-native | Bicep |
| Multi-cloud or existing Terraform expertise | Terraform |
| One-off automation tasks | Azure CLI / PowerShell |
| General-purpose language preference | Pulumi |
| Configuration management (post-provisioning) | Ansible |
Tip: Standardise on one primary IaC tool per team to reduce cognitive overhead and simplify CI/CD.
infrastructure/
main.bicep # Entry point
parameters/
dev.bicepparam # Dev parameters
staging.bicepparam # Staging parameters
prod.bicepparam # Production parameters
modules/
networking.bicep # VNet, subnets, NSGs
compute.bicep # VMs, VMSS, App Service
storage.bicep # Storage accounts
database.bicep # SQL, Cosmos DB
monitoring.bicep # Log Analytics, App Insights
infrastructure/
main.tf # Entry point
variables.tf # Input variables
outputs.tf # Outputs
providers.tf # Provider configuration
backend.tf # Remote state configuration
environments/
dev.tfvars # Dev variable values
staging.tfvars # Staging variable values
prod.tfvars # Production variable values
modules/
networking/
main.tf
variables.tf
outputs.tf
compute/
main.tf
variables.tf
outputs.tf
Use consistent naming for Azure resources:
<type>-<workload>-<environment>-<region>-<instance>
Examples:
| Resource | Name |
|---|---|
| Resource group | rg-webapp-prod-uksouth |
| Virtual network | vnet-webapp-prod-uksouth |
| Storage account | stwebappproduksouth (no hyphens) |
| App Service | app-webapp-prod-uksouth |
| Key Vault | kv-webapp-prod-uksouth |
Never use local state in a team environment.
Bicep does not have a state file — ARM manages state. However, use deployment stacks for lifecycle management.
Store state in Azure Blob Storage with locking:
backend "azurerm" {
resource_group_name = "rg-terraform-state"
storage_account_name = "stterraformstate"
container_name = "tfstate"
key = "webapp.terraform.tfstate"
}
Protect the state storage account:
name: Deploy Infrastructure
on:
push:
branches: [main]
paths: ['infrastructure/**']
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: What-If
run: |
az deployment group what-if \
--resource-group rg-webapp-prod \
--template-file infrastructure/main.bicep \
--parameters @infrastructure/parameters/prod.bicepparam
- name: Deploy
run: |
az deployment group create \
--resource-group rg-webapp-prod \
--template-file infrastructure/main.bicep \
--parameters @infrastructure/parameters/prod.bicepparam
name: Terraform Deploy
on:
push:
branches: [main]
paths: ['infrastructure/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: terraform init
working-directory: infrastructure
- name: Terraform Plan
run: terraform plan -var-file=environments/prod.tfvars -out=tfplan
working-directory: infrastructure
- name: Terraform Apply
run: terraform apply -auto-approve tfplan
working-directory: infrastructure
Subscribe to continue reading
Get full access to this lesson and all 10 lessons in this course.