Skip to content

Latest commit

 

History

History
272 lines (189 loc) · 10.3 KB

File metadata and controls

272 lines (189 loc) · 10.3 KB

⚙️ Set Up Azure DevOps Pipeline for Terraform

🎯 Learning Objectives

By the end of this lab, you'll be able to:

  • Install the Terraform extension — enabling Terraform tasks (init, plan, apply) in Azure Pipelines
  • Create an Azure DevOps repository — to host all pipeline YAML, Terraform code, and app source
  • Configure production.tfvars — with your environment-specific values including admin_object_id
  • Update the pipeline YAML — with your Terraform backend (storage account, resource group, service connection)
  • Run the pipeline — to provision the full AKS infrastructure via Terraform

⏱️ Estimated Time: ~30 minutes

✅ Prerequisites

Before starting, ensure you have:

  • Terraform basics — variables, state, init/plan/apply
  • Azure DevOps pipeline concepts — stages, tasks, YAML
  • Completed Lab 1.1 — WIF service connection created
  • Completed Lab 1.2 — storage account and container created
  • Completed Lab 1.3 — Group Object ID recorded

🚀 Step-by-Step Implementation

Step 1: Install the Terraform Extension

  1. 🔌 Navigate to the Marketplace

    Go to the Terraform extension on the Azure DevOps Marketplace and click Get it free.

  2. 🏢 Select your organisation

    Choose your Azure DevOps organisation (e.g., devopsjourneyapr2026) and click Install.

    The extension adds the following pipeline tasks:

    • TerraformInstaller@1 — downloads and installs a specific Terraform version
    • TerraformTaskV4@4 — runs init, validate, plan, apply, or destroy

    ✅ Expected Output:

    Extension "Terraform" successfully installed to your organisation.
    

Step 2: Create an Azure DevOps Repository

  1. 📁 Navigate to Repos

    In your Azure DevOps project, click Repos in the left navigation.

  2. ➕ Create a new repository

    Click the repository dropdown → New repository.

    • Name: DevOps-Journey (or your preferred name)
    • Keep Add a README checked
  3. 📋 Copy the repository contents

    Clone the repo and push the contents from this GitHub repository:

    # Clone your new Azure DevOps repo
    git clone https://dev.azure.com/<your-org>/DevOps-Journey/_git/DevOps-Journey
    cd DevOps-Journey
    
    # Copy the lab 2 contents into it
    cp -r /path/to/labs/2-AzureDevOps-Terraform-Pipeline/* .
    git add -A
    git commit -m "Initial Terraform pipeline setup"
    git push

Step 3: Update production.tfvars

  1. 📝 Open the tfvars file

    Open labs/2-AzureDevOps-Terraform-Pipeline/vars/production.tfvars and update the values for your environment.

  2. 🔑 Set admin_object_id

    This is the Entra ID Group Object ID from Lab 1.3. It grants the group:

    • Key Vault Administrator RBAC on the Key Vault
    • AKS Cluster Admin RBAC on the AKS cluster
    # Replace with your actual values
    admin_object_id = "278cc1b9-653d-464a-90f7-309e02d4b5d1"

    ⚠️ Use admin_object_idnot the old name access_policy_id. The Key Vault in this repo uses RBAC-based access control, not legacy access policies.

    Other values to review and update in the tfvars file:

    resource_group_name    = "devopsjourneyapr2026-rg"
    location               = "uksouth"
    cluster_name           = "devopsjourneyapr2026"
    kubernetes_version     = "1.33"
    acr_name               = "devopsjourneyapr2026acr"
    key_vault_name         = "devopsjourneyapr2026-kv"

Step 4: Update the Pipeline YAML

  1. 📝 Open the pipeline YAML

    Open labs/2-AzureDevOps-Terraform-Pipeline/pipelines/lab2pipeline.yaml and update the backend variables:

    variables:
      - name: backendServiceArm
        value: 'azure-devops-journey-apr2026'        # ← Your WIF service connection name
      - name: backendAzureRmResourceGroupName
        value: 'devops-journey-rg-apr2026'           # ← Your Terraform state RG
      - name: backendAzureRmStorageAccountName
        value: 'devopsjourneyapr2026'                # ← Your storage account name
      - name: backendAzureRmContainerName
        value: 'tfstate'
      - name: backendAzureRmKey
        value: 'terraform.tfstate'

    💡 These values connect Terraform to the Azure Blob backend you created in Lab 1.2.


Step 5: Set Up and Run the Pipeline

  1. 🔧 Create the pipeline in Azure DevOps

    • Navigate to PipelinesNew Pipeline
    • Choose Azure Repos Git → select your repository
    • Choose Existing Azure Pipelines YAML file
    • Select the branch and path to lab2pipeline.yaml
  2. 💾 Save and run

    Click Save and run.

  3. 📋 Review pipeline stages

    The pipeline runs the following Terraform stages:

    • Validateterraform validate checks HCL syntax
    • Planterraform plan previews all resources to be created
    • Applyterraform apply provisions the infrastructure

    ✅ Expected Output (Terraform Apply stage):

    Apply complete! Resources: 25 added, 0 changed, 0 destroyed.
    
    Outputs:
      aks_cluster_name       = "devopsjourneyapr2026"
      acr_name               = "devopsjourneyapr2026acr"
      key_vault_name         = "devopsjourneyapr2026-kv"
      resource_group_name    = "devopsjourneyapr2026-rg"
    

✅ Validation

Infrastructure checklist:

  • Pipeline completes all stages (Validate, Plan, Apply) with green ticks
  • AKS cluster devopsjourneyapr2026 visible in Azure Portal
  • ACR devopsjourneyapr2026acr created
  • Key Vault devopsjourneyapr2026-kv created with RBAC access control enabled
  • Application Insights workspace-based resource created

Technical validation:

# Verify AKS cluster
az aks show \
  --name devopsjourneyapr2026 \
  --resource-group devopsjourneyapr2026-rg \
  --query "{Name:name, K8sVersion:kubernetesVersion, State:provisioningState}" -o table

# Verify ACR
az acr show \
  --name devopsjourneyapr2026acr \
  --query "{Name:name, LoginServer:loginServer, SKU:sku.name}" -o table

# Verify Key Vault (RBAC-based)
az keyvault show \
  --name devopsjourneyapr2026-kv \
  --resource-group devopsjourneyapr2026-rg \
  --query "{Name:name, RBAC:properties.enableRbacAuthorization}" -o table

✅ Expected Output:

Name                   K8sVersion    State
---------------------  ------------  ---------
devopsjourneyapr2026   1.33.x        Succeeded

Name                     LoginServer                              SKU
-----------------------  ---------------------------------------  ------
devopsjourneyapr2026acr  devopsjourneyapr2026acr.azurecr.io       Premium

Name                      RBAC
------------------------  ------
devopsjourneyapr2026-kv   True

🔧 Troubleshooting (click to expand)
# Problem: Pipeline fails at Terraform Init with "AuthorizationFailed"
# Solution: Ensure the WIF service connection has Contributor + User Access Admin on the subscription
az role assignment list \
  --assignee "$(az ad sp list --display-name 'azure-devops-journey-identity' --query '[0].id' -o tsv)" \
  --query "[].roleDefinitionName" -o tsv

# Problem: "admin_object_id is not set" or Terraform variable error
# Solution: Check production.tfvars — ensure admin_object_id is populated with the correct group ID
az ad group show --group "devopsjourney-aks-group-apr2026" --query id -o tsv

# Problem: AKS version "1.33" not available in your region
# Solution: List available versions
az aks get-versions --location uksouth --query "values[].version" -o tsv | sort -V | tail -5

# Problem: Pipeline cannot access Terraform state storage account
# Solution: Assign Storage Blob Data Contributor to the WIF service principal on the storage account
az role assignment create \
  --assignee "<wif-sp-object-id>" \
  --role "Storage Blob Data Contributor" \
  --scope "/subscriptions/<sub-id>/resourceGroups/devops-journey-rg-apr2026/providers/Microsoft.Storage/storageAccounts/devopsjourneyapr2026"

� Key Takeaways

  1. backendServiceArm authenticates Terraform's Azure backend — it tells the TerraformTaskV4 task which Azure DevOps service connection to use when reading/writing the remote state file in Azure Blob Storage.
  2. The Key Vault uses RBAC authorization (enableRbacAuthorization = true) — not legacy access policies. The admin_object_id creates a Key Vault Administrator role assignment. access_policy_id was the old name used when Key Vault access policies were configured.
  3. Kubernetes 1.33 is configured in production.tfvars as kubernetes_version = "1.33". AKS uses the patch upgrade channel so patch versions are managed automatically.
  4. User Access Administrator is needed to create role assignments — Terraform creates RBAC assignments (e.g., ACR pull for AKS, Key Vault roles) during terraform apply. Contributor alone cannot manage role assignments.

➡️ What's Next

All Azure infrastructure is now provisioned via the Terraform pipeline. In the next lab you'll build and push the Python/Flask Docker image to your new Azure Container Registry.

← Back to Lab 1.3 | Continue to Lab 3 →


📚 Additional Resources