DEV Community

Cover image for πŸš€ Azure Pipeline for Terraform Deployment (Dev & Prod Environments)
Deepak Sharma
Deepak Sharma

Posted on

πŸš€ Azure Pipeline for Terraform Deployment (Dev & Prod Environments)

Managing infrastructure with Terraform is one of the most common practices in modern DevOps workflows. But when it comes to automation and governance, Azure DevOps pipelines make the process much smoother.

In this blog, I’ll walk you through a real-world Azure DevOps pipeline that deploys Terraform infrastructure to Dev and Prod environments with manual approvals in between.


πŸ”‘ Prerequisites

Before setting up this pipeline, make sure you have the following in place:

  1. Active Azure Subscription You need a valid Azure subscription where your Terraform resources will be deployed.
  2. Azure DevOps Account An Azure DevOps project should be created to host your pipeline and repository.
  3. Self-Hosted Agent Pool A self-hosted agent is required to run Terraform tasks. This gives more control and avoids limitations of Microsoft-hosted agents.
  4. App Registration with Federated Credentials Create an App Registration in Azure AD and configure it with federated credentials. This will be used as the Service Connection (SPN) in Azure DevOps to authenticate Terraform with Azure.
  5. Terraform Code A working Terraform configuration (with .tf files and .tfvars for Dev and Prod) must be present in your repository.

πŸ“Œ Pipeline Overview

This pipeline is designed with two major stages:

  1. Dev Stage β†’ Runs Terraform init, plan, requires manual approval, and then applies changes on the Dev environment.
  2. Prod Stage β†’ After Dev is successful, it requires another manual approval and then applies changes to the Prod environment.

By using manual validations, we ensure that no changes are applied accidentally in production without human approval.


πŸ”§ Key Features of the Pipeline

  • Multi-stage deployment β†’ Dev first, then Prod.
  • Terraform AzureRM backend β†’ Stores the Terraform state in an Azure Storage Account.
  • Manual validations β†’ Adds an approval step before applying changes.
  • Reusable variables β†’ Service connection, resource group, storage account, and container details are stored as variables to avoid repetition.

πŸ“ Pipeline YAML

Here’s the YAML code for the pipeline:

trigger:
- master

pool:
  name: mademitech

variables:
  serviceConnection: 'mademi-spn'
  rgName: 'mademi-rg'
  storageAccount: 'mademisg'
  containerName: 'mademistatefiles'

stages:
  - stage: Dev
    jobs:
      - job: Validate_Dev
        displayName: Validate on Dev
        steps:
          - task: TerraformTask@5
            displayName: Init Dev
            inputs:
              provider: 'azurerm'
              command: 'init'
              backendServiceArm: $(serviceConnection)
              backendAzureRmResourceGroupName: $(rgName)
              backendAzureRmStorageAccountName: $(storageAccount)
              backendAzureRmContainerName: $(containerName)
              backendAzureRmKey: 'dev.tfstate'

          - task: TerraformTask@5
            displayName: Plan Dev
            inputs:
              provider: 'azurerm'
              command: 'plan'
              commandOptions: '-var-file=dev.tfvars --lock=false'
              environmentServiceNameAzureRM: $(serviceConnection)

      - job: ManualValidation
        displayName: Manual Approval for Dev Deployment
        dependsOn: Validate_Dev
        pool: server
        steps:
          - task: ManualValidation@1
            inputs:
              notifyUsers: 'deepak83s143@gmail.com'
              onTimeout: 'resume'

      - job: Deploy_Dev
        displayName: Deploy on Dev
        dependsOn: ManualValidation
        steps:
          - task: TerraformTask@5
            displayName: Apply Dev
            inputs:
              provider: 'azurerm'
              command: 'apply'
              commandOptions: '-var-file=dev.tfvars --auto-approve --lock=false'
              environmentServiceNameAzureRM: $(serviceConnection)

  - stage: Prod
    dependsOn: Dev
    jobs:
      - job: ManualValidation_Prod
        displayName: Manual Approval for Prod
        pool: server
        steps:
          - task: ManualValidation@1
            inputs:
              notifyUsers: 'deepak83s143@gmail.com'
              onTimeout: 'resume'

      - job: Deploy_Prod
        displayName: Deploy on Prod
        dependsOn: ManualValidation_Prod
        steps:
          - task: TerraformTask@5
            displayName: Init Prod
            inputs:
              provider: 'azurerm'
              command: 'init'
              backendServiceArm: $(serviceConnection)
              backendAzureRmResourceGroupName: $(rgName)
              backendAzureRmStorageAccountName: $(storageAccount)
              backendAzureRmContainerName: $(containerName)
              backendAzureRmKey: 'prod.tfstate'

          - task: TerraformTask@5
            displayName: Apply Prod
            inputs:
              provider: 'azurerm'
              command: 'apply'
              commandOptions: '-var-file=prod.tfvars --auto-approve'
              environmentServiceNameAzureRM: $(serviceConnection)
Enter fullscreen mode Exit fullscreen mode

πŸ” Step-by-Step Explanation

1. Trigger & Pool

trigger:
- master
Enter fullscreen mode Exit fullscreen mode

This pipeline runs automatically whenever code is pushed to the master branch.
The pool is set to mademitech, which means it will run on a self-hosted agent.


2. Variables

variables:
  serviceConnection: 'mademi-spn'
  rgName: 'mademi-rg'
  storageAccount: 'mademisg'
  containerName: 'mademistatefiles'
Enter fullscreen mode Exit fullscreen mode

These variables store reusable values for the backend configuration.
If tomorrow you change your storage account or service connection, you only need to update it once here.


3. Dev Stage

  • Init: Initializes Terraform with AzureRM backend and points to the Dev state file.
  • Plan: Runs terraform plan using dev.tfvars.
  • Manual Validation: Waits for approval before applying changes.
  • Apply: Applies the infrastructure changes on Dev.

4. Prod Stage

  • Depends on Dev β†’ Ensures that only after successful Dev deployment, Prod stage runs.
  • Manual Validation: Extra safety check before deploying to Prod.
  • Init + Apply: Runs Terraform init and applies changes using prod.tfvars.

βœ… Why This Approach?

  • Governance β†’ Manual approvals ensure no accidental changes hit production.
  • Reusability β†’ Variables make the pipeline maintainable.
  • Safety β†’ Dev is always tested first before Prod.
  • Automation + Control β†’ Combines Terraform automation with human oversight.

🎯 Final Thoughts

This pipeline strikes a balance between automation and manual governance. It’s a solid starting point for teams looking to deploy infrastructure with Terraform while keeping production safe.

From here, you can also enhance it by:

  • Adding linting & validation steps before plan.
  • Integrating policy checks with tools like Terraform Cloud or OPA.
  • Using templates for even more reusability.

πŸ‘‰ Follow me on

Top comments (0)