azure
Azure Infrastructure as Code: Using Terraform and ARM Templates
Master Infrastructure as Code in Azure with this comprehensive guide covering Terraform, ARM Templates, state management, module development, and pipeline integration.
March 1, 2024
cleartechy editorial team
5 min read
Azure Infrastructure as Code: A Complete Implementation Guide
Infrastructure as Code (IaC) is essential for managing cloud resources efficiently. This guide covers implementation details for both Terraform and ARM Templates in Azure.
IaC Tools Comparison
Key differences between IaC tools:
| Feature | Terraform | ARM Templates |
|---|---|---|
| Language | HCL | JSON/Bicep |
| State Management | External state | Azure native |
| Multi-cloud | Yes | Azure only |
| Learning Curve | Moderate | Steep |
Terraform Implementation
Basic Infrastructure Setup
# Provider configuration provider "azurerm" { features {} } # Resource group resource "azurerm_resource_group" "example" { name = "example-resources" location = "East US" tags = { environment = "Production" department = "IT" } } # Virtual network resource "azurerm_virtual_network" "example" { name = "example-network" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location address_space = ["10.0.0.0/16"] subnet { name = "subnet1" address_prefix = "10.0.1.0/24" } subnet { name = "subnet2" address_prefix = "10.0.2.0/24" } } # Storage account resource "azurerm_storage_account" "example" { name = "examplestorageacc" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location account_tier = "Standard" account_replication_type = "LRS" tags = { environment = "Production" } }
Module Development
# modules/webapp/main.tf variable "name" { type = string description = "Name of the web app" } variable "location" { type = string description = "Azure region" } variable "resource_group_name" { type = string description = "Resource group name" } resource "azurerm_app_service_plan" "example" { name = "${var.name}-plan" location = var.location resource_group_name = var.resource_group_name sku { tier = "Standard" size = "S1" } } resource "azurerm_app_service" "example" { name = var.name location = var.location resource_group_name = var.resource_group_name app_service_plan_id = azurerm_app_service_plan.example.id site_config { dotnet_framework_version = "v4.0" scm_type = "LocalGit" } app_settings = { "WEBSITE_NODE_DEFAULT_VERSION" = "10.14.1" } } output "webapp_url" { value = azurerm_app_service.example.default_site_hostname }
ARM Templates Implementation
Resource Deployment
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "metadata": { "description": "Name of the storage account" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for resources" } } }, "variables": { "storageAccountSku": "Standard_LRS" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2021-04-01", "name": "[parameters('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "[variables('storageAccountSku')]" }, "kind": "StorageV2", "properties": { "supportsHttpsTrafficOnly": true, "minimumTlsVersion": "TLS1_2", "allowBlobPublicAccess": false } } ], "outputs": { "storageAccountId": { "type": "string", "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" } } }
Linked Templates
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "networkTemplate": { "type": "string", "metadata": { "description": "URI to the network template" } } }, "resources": [ { "type": "Microsoft.Resources/deployments", "apiVersion": "2021-04-01", "name": "networkDeployment", "properties": { "mode": "Incremental", "templateLink": { "uri": "[parameters('networkTemplate')]", "contentVersion": "1.0.0.0" }, "parameters": { "vnetName": { "value": "myVNet" }, "addressPrefix": { "value": "10.0.0.0/16" } } } } ] }
State Management
Terraform State Configuration
# Backend configuration terraform { backend "azurerm" { resource_group_name = "terraform-state-rg" storage_account_name = "terraformstate" container_name = "tfstate" key = "prod.terraform.tfstate" } } # State locking resource "azurerm_storage_account" "state" { name = "terraformstate" resource_group_name = "terraform-state-rg" location = "East US" account_tier = "Standard" account_replication_type = "LRS" blob_properties { versioning_enabled = true } } resource "azurerm_storage_container" "state" { name = "tfstate" storage_account_name = azurerm_storage_account.state.name container_access_type = "private" }
Pipeline Integration
Azure DevOps Pipeline
trigger: branches: include: - main paths: include: - terraform/* variables: - group: terraform-vars stages: - stage: Validate jobs: - job: ValidateAndPlan pool: vmImage: 'ubuntu-latest' steps: - task: TerraformInstaller@0 inputs: terraformVersion: '1.0.0' - task: TerraformTaskV3@3 inputs: provider: 'azurerm' command: 'init' backendServiceArm: '$(AZURE_SUBSCRIPTION)' backendAzureRmResourceGroupName: '$(BACKEND_RG)' backendAzureRmStorageAccountName: '$(BACKEND_SA)' backendAzureRmContainerName: '$(BACKEND_CONTAINER)' backendAzureRmKey: '$(BACKEND_KEY)' - task: TerraformTaskV3@3 inputs: provider: 'azurerm' command: 'plan' environmentServiceNameAzureRM: '$(AZURE_SUBSCRIPTION)' - stage: Apply dependsOn: Validate condition: succeeded() jobs: - deployment: ApplyTerraform environment: 'Production' strategy: runOnce: deploy: steps: - task: TerraformTaskV3@3 inputs: provider: 'azurerm' command: 'apply' environmentServiceNameAzureRM: '$(AZURE_SUBSCRIPTION)' commandOptions: '-auto-approve'
Testing and Validation
Infrastructure Testing
| Test Type | Tool | Purpose |
|---|---|---|
| Static Analysis | tflint | Syntax validation |
| Security Scanning | tfsec | Security checks |
| Policy Compliance | Checkov | Policy validation |
| Integration Tests | Terratest | Resource testing |
Best Practices Summary
-
Code Organization
- Use modules
- Implement state management
- Version control
- Documentation
-
Security
- Secure state storage
- Use service principals
- Implement least privilege
- Regular security scans
-
Deployment
- Use pipelines
- Implement validation
- Stage deployments
- Regular testing
-
Maintenance
- Version tracking
- State backups
- Regular updates
- Monitoring
Troubleshooting Guide
Common IaC issues and solutions:
-
State Issues
- Check backend configuration
- Verify access permissions
- Review state locks
- Backup state files
-
Deployment Failures
- Check dependencies
- Verify credentials
- Review logs
- Test locally
-
Module Problems
- Check versions
- Verify inputs
- Review outputs
- Test modules
Next Steps
After implementing IaC:
- Set up monitoring
- Implement compliance checks
- Automate testing
- Train team members
- Document processes
Remember to regularly review and update your IaC implementation to maintain optimal infrastructure management.
azure
infrastructure-as-code
terraform
arm-templates
devops