Contents

Part 5: Deploying Infrastructure with Terraform in Azure Pipelines

🏗️ Why Automate Infrastructure Deployment?

Scanning Terraform code is great (and we did that in Part 4),
But at some point, you need to actually provision the infrastructure:
Virtual Networks, App Services, Storage, Event Grid, etc.

Doing it manually = slow, inconsistent, and error-prone.
Using Terraform + Azure Pipelines = automated, repeatable, and secure.


🔧 Pre-requisites

Before we write the pipeline steps, make sure you:

    • Have a working Terraform directory (terraform/)
    • Are using a remote backend (Azure Storage or Terraform Cloud)
    • Have created an Azure service connection in Azure DevOps (SPN with Contributor or least privilege)
    • Store secrets like client ID, tenant ID, and secret in DevOps pipeline variables or key vault

🧪 Terraform Directory Structure

Example layout:

terraform/
  ├── main.tf
  ├── variables.tf
  ├── outputs.tf
  └── backend.tf

Make sure your backend.tf points to your Azure Storage account for state management.


🛠️ Add Terraform Apply Stage to Azure DevOps Pipeline

- stage: TerraformApply
  displayName: 'Deploy Infrastructure to Azure'
  dependsOn: IaCScan
  jobs:
    - job: terraformApply
      displayName: 'Run Terraform Apply'
      pool:
        vmImage: 'ubuntu-latest'
      steps:
        - checkout: self

        - task: AzureCLI@2
          displayName: 'Terraform Init & Apply'
          inputs:
            azureSubscription: 'YourServiceConnectionName'
            scriptType: 'bash'
            scriptLocation: 'inlineScript'
            inlineScript: |
              cd terraform
              terraform init -backend-config="..."   # your backend values
              terraform validate
              terraform plan -out=tfplan.out
              terraform apply -auto-approve tfplan.out

🧠 What Each Command Does

    • terraform init: Downloads providers, configures backend
    • terraform validate: Makes sure the .tf files are syntactically valid
    • terraform plan: Shows what will be created/changed
    • terraform apply: Provisions the actual resources on Azure

🔐 Secure Your Pipeline

    • Store sensitive values as pipeline secrets or in Azure Key Vault
    • Lock down the service principal’s permissions to only what’s needed
    • Use terraform apply -input=false to avoid prompts

🧼 Optional Enhancements

    • Add terraform destroy in a separate stage for teardown in test environments
    • Store plan output as an artifact to audit changes
    • Use terraform fmt -check for code style checks
    • Add environment approvals before applying to production

🧭 Example Output

After apply runs, you should see logs like:

azurerm_resource_group.rg: Creation complete after 3s
azurerm_storage_account.sa: Creation complete after 6s
...
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

💥 Your infrastructure is now provisioned — automatically, cleanly, and consistently.


✅ What You’ve Done So Far

You now have a secure, real-world pipeline that:

    • Scans your dependencies with Snyk
    • Scans your code with SonarQube
    • Audits your infra-as-code with Checkov
    • Applies your Terraform-defined infrastructure to Azure

⏭️ What’s Next?

Now that your infrastructure is ready, it’s time to:

🎯 Deploy the Java application onto the Azure resources we’ve just provisioned.
We’ll do that in Part 6: Application Deployment to Azure App Service