Screenshot from the article

Introduction

To create a comprehensive Azure DevOps CI/CD pipeline with Terraform, we’ll implement an end-to-end workflow for a sample e-commerce application using advanced patterns. This guide includes troubleshooting for real-world scenarios and optimizations for enterprise environments.

Infrastructure Architecture

Our deployment will provision:

  • Azure Kubernetes Service (AKS) cluster with managed identities
  • Azure PostgreSQL Flexible Server with VNET integration
  • Azure Front Door with Web Application Firewall (WAF)
  • Azure Monitor workspace with diagnostic settings
  • Key Vault for secret management

Terraform Module Structure:

modules/
├── network
├── database
├── kubernetes
├── monitoring
└── frontdoor
environments/
├── prod
│   ├── main.tf
│   ├── variables.tf
│   └── terraform.tfvars
└── staging

Pipeline Implementation

Multi-Stage YAML Pipeline

# azure-pipelines.yml
variables:
  TF_VERSION: 1.8.5
  ENVIRONMENT: prod
  BACKEND_SA: $(backendStorageAccount)
stages:
- stage: Validate
  jobs:
  - job: Lint
    steps:
    - script: terraform fmt -check -recursive
    - task: terrascan@1
      inputs:
        scanType: 'iac'
        iacType: 'terraform'
- stage: Plan
  dependsOn: Validate
  jobs:
  - job: TerraformPlan
    steps:
    - task: TerraformInstaller@0
      inputs:
        terraformVersion: $(TF_VERSION)
    - script: |
        terraform init -backend-config="storage_account_name=$(BACKEND_SA)"
        terraform plan -out=tfplan        
      workingDirectory: environments/$(ENVIRONMENT)
- stage: Approve
  dependsOn: Plan
  jobs:
  - job: Approval
    pool: server
    steps:
    - task: ManualValidation@0
      timeoutInMinutes: 1440
- stage: Apply
  dependsOn: Approve
  jobs:
  - job: TerraformApply
    steps:
    - script: terraform apply tfplan
      workingDirectory: environments/$(ENVIRONMENT)
- stage: Monitor
  jobs:
  - job: DeploymentCheck
    steps:
    - task: AzureCLI@2
      inputs:
        script: |
          az monitor activity-log list \
            --resource-group $(resourceGroup) \
            --query "[?operationName.value=='Microsoft.Resources/deployments/write']"

Advanced Configuration Patterns

State Management with Azure Storage

# backend.tf
terraform {
  backend "azurerm" {
    resource_group_name  = "tfstate-rg"
    storage_account_name = "sttfstate$(unique_string)"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    use_oidc             = true
  }
}

Zero-Downtime Deployment

resource "azurerm_kubernetes_cluster" "aks" {
  lifecycle {
    create_before_destroy = true
  }
  
  automatic_channel_upgrade = "patch"
  maintenance_window {
    allowed {
      day   = "Saturday"
      hours = [2, 4]
    }
  }
}

Real-World Troubleshooting Scenarios

Case 1: Authentication Failure During Init Symptom: Error: Failed to get existing workspaces: storage: service returned error Solution:

  1. Verify Managed Identity has Storage Blob Data Contributor role
  2. Enable network exceptions for Azure DevOps IP ranges in storage account
  3. Use OIDC authentication instead of SAS tokens
# Add to backend configuration
use_oidc = true

Case 2: State Locking Conflicts Symptom: Error acquiring state lock Resolution:

terraform force-unlock LOCK_ID -force
az storage blob lease break --container-name tfstate --blob-name prod.tflock

Case 3: Pipeline Dependency Race Conditions Mitigation: Implement pipeline gates and deployment slots

- stage: BlueGreen
  jobs:
  - deployment: SlotSwap
    environment: Production
    strategy:
      rolling:
        preDeploy:
          steps:
          - script: terraform apply -target azurerm_web_app_slot.prod
        deploy:
          steps:
          - script: az webapp deployment slot swap -g MyResourceGroup -n MyApp --slot staging

Monitoring & Observability

terraform.tf:

module "monitoring" {
  source = "Azure/avm-res-insights-monitor/azurerm"
  
  diagnostic_settings = {
    "aks-diag" = {
      target_resource_id = azurerm_kubernetes_cluster.aks.id
      log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id
    }
  }
  
  alert_rules = {
    "HighCPU" = {
      description = "Average CPU > 80%"
      condition   = "avg Percentage CPU > 80"
    }
  }
}

Security Best Practices

  1. Secret Management:
data "azurerm_key_vault_secret" "db_password" {
  name         = "postgres-password"
  key_vault_id = azurerm_key_vault.main.id
}
resource "azurerm_key_vault_access_policy" "devops" {
  key_vault_id = azurerm_key_vault.main.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = azuread_service_principal.devops.object_id
  
  secret_permissions = ["Get"]
}
  1. Network Restrictions:
resource "azurerm_storage_account_network_rules" "tfstate" {
  default_action             = "Deny"
  ip_rules                   = ["52.237.103.0/24"] # Azure DevOps IP range
  virtual_network_subnet_ids = [azurerm_subnet.agents.id]
}

FAQ: Common Pipeline Issues

Q: Pipeline fails with “Error: AuthorizationFailure” A:

  1. Verify Service Principal has Contributor role at resource group level
  2. Check storage account firewall rules allow Azure DevOps IPs
  3. Enable managed identity authentication in pipeline settings

Q: Terraform plan shows unexpected changes on every run A:

  1. Use ignore_changes for cloud-generated tags:
lifecycle {
  ignore_changes = [tags["CreatedBy"], tags["Timestamp"]]
}

2. Set explicit versions for AzureRM provider

3. Use Terraform Cloud for remote execution consistency

Q: How to manage multiple environments? A: Implement workspace strategy:

terraform workspace new staging
terraform workspace select prod

Combine with Azure DevOps variable groups for environment-specific configurations.

Q: Debugging failed pipeline runs A:

  1. Enable debug logging:
variables:
  SYSTEM_DEBUG: true

2. Use Terraform console for state inspection

3. Implement pipeline artifacts for plan files:

- task: PublishPipelineArtifact@1
  inputs:
    targetPath: $(System.DefaultWorkingDirectory)/tfplan
    artifact: TerraformPlan

Final Recommendations

  1. Policy Enforcement: Use Azure Policy with Terraform validation
  2. Cost Control: Integrate Infracost in pipeline gates
  3. Drift Detection: Schedule daily Terraform plan runs
  4. Collaboration: Implement Terraform Cloud for team workflows

This implementation provides production-grade patterns while addressing real-world operational challenges. The combination of Azure DevOps pipeline capabilities with Terraform’s infrastructure management creates a robust framework for cloud-native application delivery.

📢 Have questions or feedback? Drop a comment below or connect with me on Twitter/X@spysood!

Originally published on Medium.