A template repository for Azure DevOps (ADO) pipelines running Terraform to manage Azure infrastructure.
This repository provides a ready-to-use template for infrastructure as code (IaC) workflows. It includes:
- Azure DevOps pipeline definitions with reusable templates
- Example Terraform configuration for Azure resources
- Environment-specific configurations (dev/prod)
- A modules directory for reusable Terraform components
- Community standard files and best practices
.
├── .editorconfig # Consistent editor formatting
├── .terraform-version # Terraform version for tfenv
├── pipelines/
│ ├── terraform-pipeline.yml # Main pipeline (Terraform extension)
│ ├── terraform-cli-pipeline.yml # Alternative pipeline (Terraform CLI)
│ ├── terraform-destroy-pipeline.yml # Pipeline for destroying infrastructure
│ └── templates/
│ ├── terraform-install.yml # Template: install Terraform
│ ├── terraform-init.yml # Template: terraform init
│ ├── terraform-validate.yml # Template: terraform validate
│ ├── terraform-plan.yml # Template: terraform plan
│ ├── terraform-apply.yml # Template: terraform apply
│ └── terraform-destroy.yml # Template: terraform destroy
├── terraform/
│ ├── main.tf # Main resource definitions
│ ├── variables.tf # Input variables
│ ├── outputs.tf # Output values
│ ├── versions.tf # Terraform and provider versions
│ ├── terraform.tfvars.example # Example variable values
│ ├── .tflint.hcl # TFLint configuration
│ ├── environments/
│ │ ├── dev/
│ │ │ ├── backend.tfvars # Dev backend configuration
│ │ │ └── terraform.tfvars # Dev variable values
│ │ └── prod/
│ │ ├── backend.tfvars # Prod backend configuration
│ │ └── terraform.tfvars # Prod variable values
│ └── modules/ # Reusable Terraform modules
│ └── README.md
├── scripts/
│ └── setup-backend.sh # Helper: create backend storage
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONFIGURATION.md # Detailed setup guide
├── CONTRIBUTING.md
├── LICENSE
└── SECURITY.md
The main pipeline using Azure DevOps Terraform extension tasks. This pipeline:
- Validate Stage: Installs Terraform, initializes, and validates configuration
- Plan Stage: Runs
terraform planto preview changes - Apply Stage: Applies changes to infrastructure (only on main branch)
Features:
- Uses the official Terraform Azure DevOps extension
- Supports remote state management with Azure Storage
- Includes deployment approval gates through environments
- Automatically triggers on changes to terraform files
An alternative pipeline that uses Terraform CLI commands directly through bash scripts.
Features:
- No Terraform extension required
- More control over Terraform commands
- Includes format checking
- Publishes and downloads plan artifacts between stages
- Uses Azure CLI task for authentication
A manual pipeline for destroying infrastructure.
Features:
- Manual trigger only (no automatic triggers)
- Requires deployment environment approval
- Uses the same backend configuration as the apply pipeline
- Click Use this template on GitHub (or fork/clone the repository).
- Update
terraform/with your own resource definitions. - Configure environment-specific values in
terraform/environments/. - Set up your Azure DevOps pipelines using the YAML files in
pipelines/.
See CONFIGURATION.md for a detailed setup guide.
- Azure DevOps Account: Access to an Azure DevOps organization and project
- Azure Subscription: An Azure subscription for deploying resources
- Service Connection: An Azure Resource Manager service connection configured in Azure DevOps
- Backend Storage: An Azure Storage Account for storing Terraform state (optional but recommended)
Use the included helper script to create the Azure Storage backend:
./scripts/setup-backend.sh [resource_group] [storage_account] [container] [location]
# Example with defaults:
./scripts/setup-backend.shOr create the resources manually:
# Create resource group
az group create --name tfstate-rg --location eastus
# Create storage account
az storage account create \
--name tfstatestorage \
--resource-group tfstate-rg \
--location eastus \
--sku Standard_LRS
# Create container
az storage container create \
--name tfstate \
--account-name tfstatestorage- In Azure DevOps, go to Project Settings → Service connections
- Create a new Azure Resource Manager service connection
- Note the service connection name
Update the following variables in the pipeline files or create a variable group:
azureServiceConnection: Name of your Azure service connectionbackendResourceGroupName: Resource group containing the state storagebackendStorageAccountName: Storage account name for statebackendContainerName: Container name in the storage accountbackendKey: Name of the state file
For the CLI pipeline, you may also need to set:
ARM_CLIENT_IDARM_CLIENT_SECRETARM_SUBSCRIPTION_IDARM_TENANT_ID
- Copy
terraform/terraform.tfvars.exampletoterraform/terraform.tfvars - Update values according to your requirements
- Ensure
terraform.tfvarsis not committed (it's in .gitignore)
Alternatively, set variables in Azure DevOps pipeline variables.
- In Azure DevOps, go to Pipelines → New Pipeline
- Select your repository
- Choose "Existing Azure Pipelines YAML file"
- Select the pipeline file you want to use:
pipelines/terraform-pipeline.yml(recommended)pipelines/terraform-cli-pipeline.yml(alternative)pipelines/terraform-destroy-pipeline.yml(for destroying resources)
For deployment approvals:
- Go to Pipelines → Environments
- Create a new environment named "production"
- Add approvals and checks as needed
- Developer pushes code to a feature branch
- Validate stage runs automatically:
- Installs Terraform
- Initializes configuration (without backend)
- Validates syntax
- Plan stage runs on successful validation:
- Initializes with backend
- Generates execution plan
- Apply stage runs only on main branch:
- Requires environment approval
- Applies the planned changes
- Manually trigger the destroy pipeline
- Environment approval required
- Destroy stage runs:
- Initializes Terraform
- Destroys all managed infrastructure
The example Terraform configuration creates:
- Azure Resource Group: Container for resources
- Azure Storage Account: Example storage resource
Edit the files in the terraform/ directory:
main.tf: Add or modify resourcesvariables.tf: Add new variablesoutputs.tf: Add outputs to display after deploymentversions.tf: Update Terraform or provider version constraints
Use environment-specific configurations in terraform/environments/ and place reusable components in terraform/modules/. See the respective README files for details.
- Use Remote State: Store Terraform state in Azure Storage for team collaboration
- Separate Environments: Use different backends/workspaces for dev/staging/prod
- Plan Before Apply: Always review the plan before applying changes
- Use Variable Files: Keep sensitive data out of version control
- Implement Approvals: Use Azure DevOps environments for production deployments
- Version Lock: Pin Terraform and provider versions for consistency
- Automated Validation: Run validate and format checks on every commit
Issue: Terraform state locked
- Solution: Check if another pipeline is running. If stuck, manually unlock using Azure Portal or CLI
Issue: Authentication failed
- Solution: Verify service connection has proper permissions on the subscription and state storage
Issue: Backend configuration error
- Solution: Ensure backend storage account and container exist and are accessible
- Store sensitive variables in Azure DevOps variable groups marked as secret
- Use service principals with minimum required permissions
- Enable soft delete on state storage accounts
- Implement branch policies requiring review before merging to main
- Use deployment approvals for production environments
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License. See LICENSE for details.