✓Azure subscription, Terraform CLI >= 1.5, Azure CLI >= 2.40, basic knowledge of HCL syntax, familiarity with Azure resource types (Resource Groups, VNets, App Services, SQL Database), access to create service principals
✦ Definition~90s read
What is Terraform on Azure?
Microsoft Azure — Terraform on Azure is a core Azure service that handles terraform in the Microsoft cloud ecosystem.
★
Terraform on Azure is like having a specialized tool that handles terraform in the Microsoft cloud — you manage the configuration, Azure handles the infrastructure.
Plain-English First
Terraform on Azure is like having a specialized tool that handles terraform in the Microsoft cloud — you manage the configuration, Azure handles the infrastructure.
Azure is Microsoft's cloud computing platform offering over 200 services. This article covers terraform on azure with production-ready configurations, best practices, and hands-on examples.
Why Terraform on Azure?
Terraform is the de facto standard for infrastructure as code (IaC) on Azure. Unlike ARM templates or Bicep, Terraform provides a cloud-agnostic workflow, state management, and a mature module ecosystem. For teams managing multi-cloud or hybrid environments, Terraform reduces cognitive overhead by using a single language (HCL) across providers. Azure's native tools are powerful but lock you into Microsoft's ecosystem. Terraform gives you portability without sacrificing depth—AzureRM provider supports virtually every Azure resource. Production teams choose Terraform for its plan/apply cycle, drift detection, and integration with CI/CD pipelines. If you're already using Terraform for AWS or GCP, adding Azure is straightforward. If you're Azure-only, Terraform still wins on flexibility and community modules.
Always pin provider versions to avoid unexpected breaking changes. Use >= for minimum and lock with a lock file.
📊 Production Insight
We once had a provider upgrade that changed the default SKU for a VMSS, causing a 20-minute outage. Pin versions and test upgrades in a non-prod environment first.
🎯 Key Takeaway
Terraform offers cloud-agnostic IaC with deep Azure support, making it ideal for multi-cloud or Azure-only teams.
thecodeforge.io
Azure Terraform
Setting Up Authentication for Azure
Terraform needs to authenticate to Azure. The recommended approach for production is service principal authentication with a client secret or certificate. Avoid using interactive login or managed identities for local development—they don't work well in CI/CD. Create a service principal with az ad sp create-for-rbac and assign it Contributor or custom role at the subscription or resource group scope. Store secrets in a vault (Azure Key Vault, HashiCorp Vault, or CI/CD secrets). For local dev, use environment variables: ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_SUBSCRIPTION_ID, ARM_TENANT_ID. Never hardcode secrets in files. Use az login only for quick tests; it's not repeatable.
Service principal secrets expire. Set up rotation with Azure Key Vault or use managed identities for Azure resources (e.g., VM running Terraform).
📊 Production Insight
We once had a secret expire during a Friday night deployment. Now we use short-lived tokens from Azure AD and rotate them weekly via automation.
🎯 Key Takeaway
Use service principal authentication with environment variables for repeatable, secure Terraform runs.
Structuring Terraform Configurations for Azure
A well-structured Terraform project is essential for maintainability. Use a modular approach: separate root modules for environments (dev, staging, prod) and reusable child modules for resources (networking, compute, databases). Each module should have clear inputs and outputs. For Azure, group resources by lifecycle and dependency. For example, a networking module creates VNet, subnets, NSGs, and route tables. A compute module depends on networking outputs. Use terraform.tfvars files per environment to override defaults. Avoid hardcoding resource names; use naming conventions with var.environment and var.project. Keep state files in a remote backend (Azure Storage) with locking enabled.
modules/networking/main.tfHCL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
resource "azurerm_resource_group""rg" {
name = "rg-${var.project}-${var.environment}-net"
location = var.location
}
resource "azurerm_virtual_network""vnet" {
name = "vnet-${var.project}-${var.environment}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
address_space = var.vnet_address_space
}
output "vnet_id" {
value = azurerm_virtual_network.vnet.id
}
output "subnet_ids" {
value = azurerm_subnet.subnets[*].id
}
💡Module Registry
Use the Terraform Registry for Azure modules (e.g., Azure/network) to avoid reinventing the wheel. But audit them for production use.
📊 Production Insight
We refactored a monolithic 2000-line config into 10 modules. Deployment time dropped by 40% and error rate by 60%.
🎯 Key Takeaway
Modularize by resource type and environment to keep configurations DRY and maintainable.
thecodeforge.io
Azure Terraform
Managing State with Azure Storage Backend
State files contain sensitive information and must be stored securely. Azure Storage Account with blob containers is the recommended backend. Enable blob soft delete and versioning to recover from accidental deletion. Use a dedicated storage account per environment with network restrictions (firewall, private endpoint). Enable azurerm_backend with key per state file (e.g., prod.terraform.tfstate). Use terraform init -backend-config to inject backend settings without hardcoding. For teams, enable state locking via Azure Blob Storage lease. This prevents concurrent modifications. Never store state locally in production.
State files can contain secrets like storage account keys. Use Azure RBAC to restrict access to the storage account.
📊 Production Insight
We lost a state file once due to accidental deletion. Now we enable soft delete and versioning, and take daily backups.
🎯 Key Takeaway
Remote state with locking is mandatory for team collaboration and safety.
Deploying a Multi-Tier Application on Azure
Let's deploy a typical three-tier app: web, API, and database. Use Azure App Service for web and API, and Azure SQL Database. Create a resource group, App Service Plan, two App Services, and a SQL Server with database. Use azurerm_app_service_plan with S1 SKU for production. Configure connection strings as app settings. Use azurerm_sql_database with S1 tier. For networking, enable VNet integration for App Services to connect to SQL via private endpoint. This example shows a complete, runnable configuration.
Use Key Vault references in App Settings instead of plaintext. Terraform can set references with @Microsoft.KeyVault(SecretUri=...).
📊 Production Insight
We hardcoded a SQL password in state once. Now we use Key Vault and never store secrets in Terraform state.
🎯 Key Takeaway
A multi-tier app on Azure can be fully defined in Terraform with App Service and SQL Database.
Networking: VNets, Subnets, and NSGs
Networking is critical for security and performance. Create a VNet with subnets for each tier: web, app, data, and management. Use Network Security Groups (NSGs) to restrict traffic. For production, use azurerm_network_security_group with explicit allow rules. Avoid using * as source; specify IP ranges or service tags. Use azurerm_subnet_network_security_group_association to attach NSGs. For App Services, use VNet Integration (regional) to route traffic through the VNet. For databases, use Private Endpoints to keep traffic within Azure backbone.
Azure adds default rules that allow VNet inbound and deny all inbound from internet. Override with explicit rules as needed.
📊 Production Insight
We once left a subnet with default NSG rules, allowing RDP from internet. A security scan caught it. Now we enforce NSGs via policy.
🎯 Key Takeaway
Design VNet with separate subnets per tier and apply NSGs with least-privilege rules.
Using Terraform Workspaces for Environment Isolation
Workspaces allow you to manage multiple environments with the same configuration. Create workspaces for dev, staging, prod. Each workspace has its own state file. Use terraform.workspace in configurations to differentiate resources. For example, name = "app-${terraform.workspace}". Workspaces are simple but have limitations: they share the same backend and variable values. For complex environments, use separate directories or Terragrunt. Workspaces work well for small teams with similar environments. Avoid using workspaces for completely different configurations (e.g., different regions).
workspaces.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create workspaces
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod
# List workspaces
terraform workspace list
# Select workspace
terraform workspace select prod
# Apply with workspace-specific variables
export TF_VAR_environment=$(terraform workspace show)
terraform apply -auto-approve
🔥Workspace vs Directory
Workspaces share the same root module. If environments diverge significantly, use separate directories or Terragrunt.
📊 Production Insight
We used workspaces for a multi-region deployment and hit state conflicts. Now we use separate directories per region.
🎯 Key Takeaway
Workspaces provide lightweight environment isolation with shared configuration.
CI/CD Pipeline for Terraform on Azure
Automate Terraform with Azure DevOps or GitHub Actions. The pipeline should: validate formatting, run terraform init, terraform validate, terraform plan, and manual approval before terraform apply. Store backend config and secrets as pipeline variables. Use terraform plan -out=tfplan to capture the plan, then terraform apply tfplan for consistency. For Azure DevOps, use the Terraform task or bash scripts. For GitHub Actions, use the hashicorp/setup-terraform action. Always run terraform fmt -check to enforce style. Fail the pipeline on validation errors.
Save the plan file as a pipeline artifact for auditability. You can re-apply it later if needed.
📊 Production Insight
We skipped manual approval once and a misconfigured NSG exposed a database. Now we require two approvals for prod.
🎯 Key Takeaway
Automate Terraform with CI/CD pipelines that include validation, planning, and manual approval.
Handling Secrets and Sensitive Data
Never store secrets in Terraform state or configuration files. Use Azure Key Vault to store secrets and reference them in Terraform with data.azurerm_key_vault_secret. For provider authentication, use environment variables or managed identities. For application secrets (e.g., DB passwords), use Key Vault references in App Settings. Terraform can create Key Vault and secrets, but avoid putting secret values in .tf files. Use sensitive = true in outputs to prevent state exposure. For CI/CD, use pipeline secret variables.
secrets.tfHCL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
data "azurerm_key_vault""kv" {
name = "kv-myapp-prod"
resource_group_name = "rg-myapp-prod"
}
data "azurerm_key_vault_secret""db_password" {
name = "db-password"
key_vault_id = data.azurerm_key_vault.kv.id
}
resource "azurerm_app_service""web" {
app_settings = {
"SQL_CONNECTION_STRING" = "Server=tcp:${azurerm_sql_server.sql.fully_qualified_domain_name};Database=${azurerm_sql_database.db.name};User ID=${azurerm_sql_server.sql.administrator_login};Password=${data.azurerm_key_vault_secret.db_password.value};Trusted_Connection=False;Encrypt=True;"
}
}
output "db_password" {
value = data.azurerm_key_vault_secret.db_password.value
sensitive = true
}
⚠ State Leakage
Even with sensitive, the value may appear in logs. Use terraform output -json carefully.
📊 Production Insight
We accidentally committed a .tfvars file with a plaintext password. Now we use .gitignore and pre-commit hooks to block secrets.
🎯 Key Takeaway
Use Azure Key Vault for all secrets and mark outputs as sensitive to prevent exposure.
Testing Terraform Configurations with Terratest
Testing infrastructure code prevents regressions. Use Terratest (Go library) to write integration tests that deploy real resources and verify behavior. Write tests for: resource creation, network connectivity, and idempotency. Run tests in isolated environments (e.g., ephemeral resource groups). Terratest handles setup and teardown. Example: test that an App Service returns HTTP 200. This catches misconfigurations before production. Combine with terraform plan checks in CI. Testing is not common but is a hallmark of mature teams.
Use unique resource names and random suffixes to avoid collisions in shared subscriptions.
📊 Production Insight
We found that our NSG rules were too permissive only after a Terratest verified connectivity from unexpected sources.
🎯 Key Takeaway
Terratest integration tests validate real infrastructure behavior and catch issues early.
Drift Detection and Remediation
Azure resources can be modified outside Terraform (manual changes, auto-scaling, etc.). This creates drift. Use terraform plan regularly to detect drift. Automate drift detection with scheduled CI/CD jobs. For critical resources, use terraform apply to remediate, but be careful—it may revert desired changes. Use terraform refresh to update state without changes. For Azure, enable Azure Policy to enforce compliance and alert on drift. Consider using azurerm_resource_group_template_deployment for resources that must stay in sync. Drift is inevitable; plan for it.
drift.shBASH
1
2
3
4
5
6
7
8
9
# Schedulethis in CI (e.g., daily)
terraform init -backend-config="..."
terraform plan -detailed-exitcode
# Exit code 2 means changes detected
if [ $? -eq 2 ]; then
echo "Drift detected!"
# Send alert
# Optionally auto-remediate with approval
fi
⚠ Auto-Remediation Risks
Auto-remediation can revert legitimate changes (e.g., scaling). Use with caution and always have a rollback plan.
📊 Production Insight
A manual change to a load balancer probe caused a 5-minute outage. Drift detection caught it the next day. Now we run drift checks every hour.
🎯 Key Takeaway
Regular drift detection via terraform plan is essential to maintain desired state.
Advanced: Using Azure Policy with Terraform
Azure Policy enforces organizational rules. Terraform can create policy assignments and definitions. Use azurerm_policy_definition and azurerm_policy_assignment to apply policies like 'allowed locations' or 'require encryption'. This ensures resources created by Terraform (or manually) comply. Combine with azurerm_policy_set_definition for initiatives. Policies can also auto-remediate non-compliant resources. Use azurerm_management_group to scope policies. This is advanced but critical for large organizations.
Store policy definitions in a separate module and version them. Use policy_rule parameter to keep HCL clean.
📊 Production Insight
We used policy to block public IPs on VMs after a security incident. Now all new VMs are private by default.
🎯 Key Takeaway
Azure Policy integrated with Terraform enforces compliance and prevents misconfigurations.
Pre-Commit Hooks and Linting: Guardrails for Terraform Quality
Catch issues before they reach your repository using pre-commit hooks with antonbabenko/pre-commit-terraform. This framework runs checks on every commit: terraform fmt -check for formatting, terraform validate for syntax, tflint for provider-specific best practices, tfsec or checkov for security scanning (hardcoded keys, open security groups), and terrascan for compliance. Install with pip install pre-commit and a .pre-commit-config.yaml file. For production, configure hooks to run on all staged .tf files. Use terraform_docs to auto-generate documentation from variable and output descriptions. Use infracost to estimate cost changes on every PR. Integrate these checks into CI/CD as well — run the same hooks in your pipeline to catch anything developers might skip locally. For the Azure provider specifically, tflint catches common mistakes like missing features {} block or incorrect API versions. Set up pre-commit to run in CI with --all-files to ensure the entire codebase is checked. Block commits that introduce security issues by configuring hooks with severity thresholds.
tfsec/checkov catch issues like hardcoded secrets, public S3 buckets, and overly permissive security groups. Run them in CI to prevent insecure infrastructure from reaching production.
📊 Production Insight
tfsec caught a storage account with allow_blob_public_access = true in a developer's PR. The hook blocked the commit and the developer fixed it before the PR was even opened. Without the hook, it would have reached production.
🎯 Key Takeaway
Use pre-commit hooks with tflint, tfsec, and terraform_docs to enforce formatting, security, and documentation standards before code reaches the repo.
State Migration and Recovery: Handling State File Disasters
State files are the source of truth for Terraform — losing or corrupting them can be catastrophic. Enable blob versioning on your Azure Storage backend to retain state file history. Set lifecycle rules to clean up versions older than 90 days. For recovery, download a previous version of the state blob, run terraform init, and import resources if needed. To migrate state between backends (e.g., local to Azure Storage), use terraform init -migrate-state. Terraform detects the existing state and prompts for migration. Use -force-copy for automation. For state recovery from scratch, use terraform import for each resource — automate this with terraform state list from a known-good state or a script that queries Azure resources. For state corruption, restore from the last good version and run terraform plan to verify. Prevent corruption by using state locking (automatic with Azure Storage backend). Never edit state files manually — use terraform state mv, terraform state rm, and terraform state replace-provider for safe modifications. For team safety, restrict state write access to CI/CD pipelines only — developers should run terraform plan against the remote state without write access.
state-recovery.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
# Enable blob versioning on the state storage account
az storage account blob-service-properties update \
--account-name stterraformstate \
--resource-group rg-terraform-state \
--enable-versioning true
# List versions of a state blob
az storage blob list \
--account-name stterraformstate \
--container-name tfstate \
--include v \
--query "[?name=='prod.terraform.tfstate'].{Name:name, Version:versionId}" \
--output table
# Download a specific version
az storage blob download \
--account-name stterraformstate \
--container-name tfstate \
--name prod.terraform.tfstate \
--version-id "2026-07-10T10:00:00.0000000Z" \
--file prod.terraform.tfstate.recovered
# Migrate state from local to AzureStorage (first time)
terraform init -migrate-state -force-copy
Output
Versioning enabled. State file version downloaded. Migration complete.
⚠ State File Security
State files can contain secrets (connection strings, passwords, private keys). Use Azure RBAC to restrict access to the state storage account. Enable diagnostic logging to track who accessed the state file.
📊 Production Insight
A team member accidentally deleted the production state file from Azure Storage. Because we had blob versioning enabled, we restored the previous version in 2 minutes. Without versioning, recovery would have taken days of manual importing.
🎯 Key Takeaway
Enable blob versioning on your state backend, use state locking, and restrict write access to CI/CD pipelines to prevent and recover from state corruption.
thecodeforge.io
Azure Terraform
Terraform Cloud and Enterprise: Remote Operations and Policy as Code
Terraform Cloud (TFC) and Terraform Enterprise (TFE) provide remote state storage, remote operations, cost estimation, and Sentinel policy-as-code for Azure deployments. Connect your Azure backend to TFC by configuring the cloud block in your Terraform configuration. Use TFC workspaces per environment (dev, staging, prod) with Azure service principal credentials stored as workspace variables. Enable remote execution so plans and applies run on TFC's infrastructure — this eliminates the need for a dedicated CI/CD runner and provides audit logs. Use Sentinel policies to enforce Azure-specific rules: require tags on all resources, restrict VM SKUs, enforce geo-location constraints, and mandate encryption. For cost control, use TFC cost estimation to see the projected cost of every plan before applying. For team workflows, use TFC's run triggers to chain workspaces (e.g., apply networking before compute). For Azure DevOps integration, use the Terraform Cloud extension for Pipelines or the TFC API. For self-hosted TFE in air-gapped environments, configure the AzureRM provider with managed identity authentication. Always pin Terraform and provider versions in TFC/TFE to ensure reproducible runs.
Terraform Cloud configured. Runs will execute remotely with full audit logging.
🔥Sentinel Policies for Azure
Write Sentinel policies to enforce Azure governance: require resource_group_name pattern, block public IPs on VMs, enforce tags, and require encryption. Policies run before the apply, preventing non-compliant infrastructure.
📊 Production Insight
We migrated from a DIY CI/CD pipeline to Terraform Cloud and reduced our plan-to-apply time by 40%. Sentinel policies caught two non-compliant deployments in the first week — a VM with no tags and a storage account with public network access enabled.
🎯 Key Takeaway
Use Terraform Cloud for remote operations, cost estimation, and Sentinel policy enforcement; integrate with Azure DevOps for a unified CI/CD pipeline.
⚙ Quick Reference
15 commands from this guide
File
Command / Code
Purpose
main.tf
terraform {
Why Terraform on Azure?
auth.sh
az ad sp create-for-rbac --name "terraform-sp" --role Contributor --scopes /subs...
Setting Up Authentication for Azure
modulesnetworkingmain.tf
resource "azurerm_resource_group" "rg" {
Structuring Terraform Configurations for Azure
backend.tf
terraform {
Managing State with Azure Storage Backend
app.tf
resource "azurerm_resource_group" "rg" {
Deploying a Multi-Tier Application on Azure
network.tf
resource "azurerm_virtual_network" "vnet" {
Networking
workspaces.sh
terraform workspace new dev
Using Terraform Workspaces for Environment Isolation
az storage account blob-service-properties update \
State Migration and Recovery
terraform-cloud.tf
terraform {
Terraform Cloud and Enterprise
Key takeaways
1
Cloud-Agnostic IaC
Terraform provides a unified workflow across Azure, AWS, and GCP, reducing cognitive overhead.
2
Remote State with Locking
Always use a remote backend like Azure Storage with locking to prevent state corruption in team environments.
3
Secrets Management
Use Azure Key Vault for all secrets and mark outputs as sensitive to avoid exposure in state files.
4
Automated Drift Detection
Regularly run terraform plan in CI to detect and remediate drift, ensuring infrastructure stays compliant.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01JUNIOR
Explain Terraform on Azure and its use cases.
Q02JUNIOR
How does Terraform on Azure handle high availability?
Q03JUNIOR
What are the security best practices for terraform?
Q04JUNIOR
How do you optimize costs for terraform?
Q05JUNIOR
Compare Azure terraform with self-hosted alternatives.
Q01 of 05JUNIOR
Explain Terraform on Azure and its use cases.
ANSWER
Microsoft Azure — Terraform on Azure is an Azure service for managing terraform in the cloud. Use it when you need reliable, scalable terraform without managing underlying infrastructure.
Q02 of 05JUNIOR
How does Terraform on Azure handle high availability?
ANSWER
Azure provides region pairs, availability zones, and SLA-backed guarantees. Configure redundancy at the application and data tier for 99.95%+ availability.
Q03 of 05JUNIOR
What are the security best practices for terraform?
ANSWER
Use managed identities, RBAC with least privilege, encrypt data at rest and in transit, enable diagnostic logging, and regularly audit access with Azure Monitor.
Q04 of 05JUNIOR
How do you optimize costs for terraform?
ANSWER
Right-size resources based on metrics, use reserved instances or savings plans, implement auto-scaling, and review Azure Advisor cost recommendations.
Q05 of 05JUNIOR
Compare Azure terraform with self-hosted alternatives.
ANSWER
Azure managed services reduce operational overhead (patching, backups, scaling). Trade-offs include less control and potential cost at extreme scale. Best for teams wanting to focus on applications over infrastructure.
01
Explain Terraform on Azure and its use cases.
JUNIOR
02
How does Terraform on Azure handle high availability?
JUNIOR
03
What are the security best practices for terraform?
JUNIOR
04
How do you optimize costs for terraform?
JUNIOR
05
Compare Azure terraform with self-hosted alternatives.
JUNIOR
FAQ · 6 QUESTIONS
Frequently Asked Questions
01
What is the difference between Terraform and ARM templates?
Terraform is cloud-agnostic, uses HCL, and has a mature state management system. ARM templates are Azure-native, use JSON, and are tightly integrated with Azure. Terraform offers better modularity and community modules.
Was this helpful?
02
How do I manage Terraform state for a team?
Use a remote backend like Azure Storage with blob locking. Store state in a dedicated storage account with RBAC restrictions. Use terraform init -backend-config to configure without hardcoding.
Was this helpful?
03
Can I use Terraform with Azure DevOps?
Yes. Use the Terraform task or bash scripts in a pipeline. Store backend config and secrets as pipeline variables. Include steps for init, validate, plan, and apply with manual approval.
Was this helpful?
04
How do I handle secrets in Terraform?
Use Azure Key Vault to store secrets and reference them with data.azurerm_key_vault_secret. Mark outputs as sensitive = true. Never hardcode secrets in .tf files or state.
Was this helpful?
05
What is drift and how do I detect it?
Drift occurs when Azure resources are modified outside Terraform. Detect it by running terraform plan regularly. Automate with scheduled CI/CD jobs. Use Azure Policy to alert on changes.
Was this helpful?
06
Should I use Terraform workspaces or separate directories for environments?
Workspaces are simple for similar environments. Use separate directories or Terragrunt when environments differ significantly (e.g., different regions or compliance requirements).