Deploying your pipeline from end-to-end is an automated process; but for some reason you want to have an approval before two stages or have hold between two stages, what can you do? You can add an approval gate to your pipeline! The approval and gates process helps you take further control of your pipeline; rather than it running from start to finish in an automated fashion, you take the control over the start of specific stages within the pipeline and decide when the pipeline finishes completely.
Why add an Approval Gate?
- Manual approval for authorised teams/users
- Can review the previous stage(s) to confirm the configuration/code/change is correct. An example is reviewing the Terraform plan stage prior to the approval of Terraform apply
The Approval Gate Process
I will create an example of the approval gate process by having an approval gate between two stages – terraform plan & terraform apply

A further detailed diagram from docs.microsoft.com on combining the approval gate process further into a release pipeline

Adding an Approval Gate to your Azure DevOps Pipeline
For an Approval Gate to be configured within your pipeline, you need to create an environment.
In Azure DevOps Pipelines -> Enviornments


Create new environment, in this example I am creating an environment called approvalgates-production

Within the newly created environment, select Approvals and checks

Now you can add your first check, I will be an myself as approver.


Now ready to edit a pipeline and make the addition(s) required.
Adding an Approval Gate to your Azure DevOps Pipeline
I am going to create a pipeline as below with two stages
Stages
└──terraform_plan
└──Git Checkout
└──Terraform Init
└──Terraform Plan
└──Archive Files
└──Publish Build Artifact
└──Delete Files (Cleanup)
└──terraform_apply
└──Checkout: None
└──Download Build Artifacts
└──Extract Build Artifacts
└──Terraform Init
└──Terraform Plan
└──Terraform Apply
I will add an approval gate prior to terraform_apply stage
I will add environment: ‘approvalgates-production’ to my pipeline along with some additional configuration
continueOnError: false
environment: 'approvalgates-production'
timeoutInMinutes: 120
strategy:
runOnce:
deploy:
Full pipeline
name: $(BuildDefinitionName)_$(date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
stages :
- stage: terraform_plan
jobs:
- job: terraform_plan
steps:
- checkout: self
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '0.13.4'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: 'tamopstf'
backendAzureRmResourceGroupName: 'tamopstfstates'
backendAzureRmStorageAccountName: 'tfstatedevops'
backendAzureRmContainerName: 'azureterraformbuildartifacts'
backendAzureRmKey: 'terraform.tfstate'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'plan'
inputs:
provider: 'azurerm'
command: 'plan'
commandOptions: '-input=false -var-file="../vars/production/production.tfvars"'
environmentServiceNameAzureRM: 'tamopstf'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(Build.SourcesDirectory)'
includeRootFolder: false
archiveType: 'tar'
tarCompression: 'gz'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).tgz'
replaceExistingArchive: true
displayName: 'Create Plan Artifact'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: '$(Build.BuildId)-tfplan'
publishLocation: 'Container'
displayName: 'Publish Plan Artifact'
- task: DeleteFiles@1
displayName: 'Remove unneeded files'
inputs:
contents: |
.terraform
tfplan
- stage: terraform_apply
dependsOn: [terraform_plan]
condition: succeeded('terraform_plan')
jobs:
- deployment: terraform_apply
continueOnError: false
environment: 'approvalgates-production'
timeoutInMinutes: 120
strategy:
runOnce:
deploy:
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
inputs:
artifactName: '$(Build.BuildId)-tfplan'
displayName: 'Download Plan Artifact'
- task: ExtractFiles@1
inputs:
archiveFilePatterns: '$(System.ArtifactsDirectory)/$(Build.BuildId)-tfplan/$(Build.BuildId).tgz'
destinationFolder: '$(System.DefaultWorkingDirectory)/'
cleanDestinationFolder: false
displayName: 'Extract Terraform Plan Artifact'
- task: TerraformInstaller@0
displayName: 'install'
inputs:
terraformVersion: '0.13.4'
- task: TerraformTaskV1@0
displayName: 'init'
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: 'tamopstf'
backendAzureRmResourceGroupName: 'tamopstfstates'
backendAzureRmStorageAccountName: 'tfstatedevops'
backendAzureRmContainerName: 'azureterraformbuildartifacts'
backendAzureRmKey: 'terraform.tfstate'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'plan'
inputs:
provider: 'azurerm'
command: 'plan'
commandOptions: '-input=false -var-file="../vars/production/production.tfvars"'
environmentServiceNameAzureRM: 'tamopstf'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
- task: TerraformTaskV1@0
displayName: 'apply'
inputs:
provider: 'azurerm'
command: 'apply'
commandOptions: '-input=false -auto-approve -var-file="../vars/production/production.tfvars"'
environmentServiceNameAzureRM: 'tamopstf'
workingDirectory: '$(System.DefaultWorkingDirectory)/terraform/'
Running the Pipeline
Notice the stage:- terraform_apply is in a waiting state with 0/1 checks passed?

Prior to approval, we can review the terraform plan task inside terraform_plan stage

Happy with the plan? Lets approve!


The plan has now been approved & the terraform_apply stage can now run.
GitHub Repo
Code here to allow you to create and run an approval gate; the code that has been used to create this blog post
1 comment