
In PART 1 of my Infrastructure as Code (IAC) security and governance blog series, I introduced the need for a modern CI/CD pipeline that integrates governance and enforcement mechanisms in cloud infrastructure deployments - as a means of ensuring that DevOps Engineers meet their organization's internal and regulatory governance requirements.
If you followed the step by step instructions, you should have the following;
- A free Azure DevOps, Terraform cloud and Bridgecrew cloud account
- A project in Azure Devops
- Two CLI-Driven workspaces in terraform cloud
In PART 2 (this article), we glue everything together and see it in action.

Table of Contents
- Import the sample code repository
- Setup build pipeline
- View checkov scan report
- Configure Azure policy Check Gate
For this demo, I've created some sample terraform configuration that creates a few test resources in Azure - ( an App Service and SQL database resource).
When you review the code in the above repository, you will notice bad practices like like passing sensitive data such as passwords in plain text. This is deliberate and is meant to demonstrate the IAC scan tools when we run out build pipeline. The resulting violations will be published for review and remediation as necessary.
Import the sample code repository
Lets start by importing sample terraform code repository from github into our Azure DevOps project
- In Azure Devops, open the iac-governance project we created in Part 1
- Select Import and enter the clone URL. (https://github.com/blackdevopss/iac-governance.git)



You can also import a github repository into Azure DevOps using the azuredevops_git_repository terraform resource below
resource "azuredevops_git_repository" "gr" {
project_id = azuredevops_project.azdo.id
name = "iac-governance"
initialization {
init_type = "Import"
source_type = "Git"
source_url = "https://github.com/blackdevopss/iac-governance.git"
}
}
Build pipeline
After importing the sample code, we are ready to setup the build pipeline. I've defined the pipeline stages in YAML as that's the latest "modern and elegant" way of building Azure pipelines since they can be included in version control alongside your infrastructure code (neat!). If you prefer the classic editor way of building your pipelines, you can still pull this off so no worries - just follow along. The YAML file for this pipeline is included in the sample code.
Stages
Our build pipeline will consist of the following stages;

- Stage 1 - Terraform Install: We install Terraform on our pipeline agent
stages:
- stage: _install
displayName: Terraform Install
jobs:
- job: _install
steps:
- task: TerraformInstaller@0
displayName: Installing Terraform
inputs:
terraformVersion: '1.1.7'
- Stage 2 - Terraform Validate: We validate to make sure the syntax and arguments of our terraform configuration code is error free.
- stage: _validate
displayName: Terraform Validate
jobs:
- job: _validate
steps:
- checkout: none
- task: TerraformCLI@0
inputs:
command: 'init'
workingDirectory: '$(System.DefaultWorkingDirectory)terraform/workspaces/infrastructure'
backendType: 'selfConfigured'
allowTelemetryCollection: false
- task: TerraformCLI@0
inputs:
command: 'validate'
workingDirectory: '$(System.DefaultWorkingDirectory)terraform/workspaces/infrastructure'
allowTelemetryCollection: false
- Stage 3 - Checkov IAC scan: We check for misconfigurations that may lead to security or compliance problems. Checkov includes more than 750 predefined policies to check for common misconfiguration issues. The results of the scan are uploaded to the Bridgecrew platform. Be sure to create an API Token in your Bridgecrew account and copy the API key for use in this pipeline step.
- stage:
displayName: Bridgecrew IAC Scan
jobs:
- job: _bridgecrewSecurityScan
steps:
- task: UsePythonVersion@0
displayName: 'Install Python 3.8'
inputs:
versionSpec: '3.8'
addToPath: true
architecture: 'x64'
- task: Bash@3
inputs:
targetType: 'inline'
script: 'pip3 install bridgecrew && pip3 install -U requests[security]'
- task: Bash@3
inputs:
targetType: 'inline'
script: '~/.local/bin/bridgecrew -d terraform --bc-api-key $(bridgecrew-api-key) --repo-id $(repo_id) --branch master --include-all-checkov-policies --framework all -o junitxml > $(System.DefaultWorkingDirectory)/BridgecrewScanReport.xml'
- task: PublishTestResults@2
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: 'BridgecrewScanReport.xml'
searchFolder: '$(System.DefaultWorkingDirectory)'
failTaskOnFailedTests: true
- Stage 4 - GitLeaks Scan: We check for hardcoded secrets like passwords, api keys, and tokens in git repos.
- stage: _gitLeaksSecurityScan
displayName: Git Secret Leaks Scan
jobs:
- job: _gitLeaksSecurityScan
steps:
- task: Gitleaks@2
inputs:
scanlocation: '$(System.DefaultWorkingDirectory)'
configtype: 'default'
scanmode: 'all'
verbose: true
uploadresults: true
reportformat: 'sarif'
reportname: 'gitLeakScanReport'
- Stage 5 - Publish Terraform Artifact: We publish the Terraform files as an artifact to be used in our Release pipeline.
- stage: _publishArtifact
displayName: Publish Terraform Artifact
jobs:
- job: _publishArtifact
steps:
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(System.DefaultWorkingDirectory)terraform/workspaces/infrastructure'
artifact: 'tfplan_$(Build.SourceBranchName)_iac_governance'
# $(Rev:r) adds a revision format to the build number, making each build number unique
Setup build pipeline
In your Azure DevOps iac-governance repository, click the blue "Set up build" button

On the "configure your pipeline" page, select "Existing Azure Pipelines YAML file" option and set following;
- branch: main
- path: terraform/azure_devops/pipelines/build/infra-build-pipelines.yml

On the "Review your pipeline YAML ", select "Run"

You should see the pipeline swing in action executing the following stages and job tasks.


View checkov scan report
Bridgecrew provides a centralized view for tracking misconfigurations across your code scans and runtime environments. Navigate to the Projects tab in the Bridgecrew platform. Here you will see the results of our Terraform IAC scan in the Azure DevOps pipeline once the run completes.


I also included a task to publish and display a copy of the checkov scan results in the Tests tab in the Azure pipeline summary.

Review the findings from the scan and remediate accordingly. In my case, I moved all the sensitive data such as passwords into an Azure Key Vault and injected those into the pipeline using a variable group created within the pipeline library.

variables:
- group: Terraform-IAC-Vars
I also implemented the security hardening that Bridgecrew recommended for remediation in my terraform resource configuration code. (see examples below)

Configure Azure policy Check Gate
One scenario for adding Azure Policy to a pipeline is when you want to ensure that resources are deployed only to authorized regions and are configured to send diagnostics logs to Azure Log Analytics. In Azure DevOps, you can add a pre- or post-deployment condition that includes the Security and compliance assessment task as a gate - but this is a topic for another blog post

Conclusion
As a modern DevOps Engineer, one of your most important end goals should be to proactively improve the security posture of your organization's cloud infrastructure and reduce the burden on your security and operations team members. I hope that by sharing my favorite tools and techniques in this blog, I have contributed some useful information and knowledge that you can apply to your projects.
You can find the full pipeline along with the Terraform code at https://github.com/blackdevopss/iac-governance.git
Signup to get access to the full archive of everything that's been published and everything that's still to come.