Integrate security governance mechanisms in your Terraform IAC version control and CI/CD pipelines [ soup to nuts ] - Part 2

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

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).

You can clone the full pipeline configuration along with the sample code from

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. (

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 =
  name       = "iac-governance"
  initialization {
    init_type   = "Import"
    source_type = "Git"
    source_url  = ""

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.


Our build pipeline will consist of the following stages;

  • Stage 1 - Terraform Install: We install Terraform on our pipeline agent
  - stage: _install
    displayName: Terraform Install
    - job: _install
        - task: TerraformInstaller@0
          displayName: Installing Terraform
            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
    - job: _validate
      - checkout: none
      - task: TerraformCLI@0
          command: 'init'
          workingDirectory: '$(System.DefaultWorkingDirectory)terraform/workspaces/infrastructure'
          backendType: 'selfConfigured'
          allowTelemetryCollection: false
      - task: TerraformCLI@0
          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
    - job: _bridgecrewSecurityScan
      - task: UsePythonVersion@0
        displayName: 'Install Python 3.8'
          versionSpec: '3.8'
          addToPath: true
          architecture: 'x64'
      - task: Bash@3
          targetType: 'inline'
          script: 'pip3 install bridgecrew && pip3 install -U requests[security]'
      - task: Bash@3
          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
          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
    - job: _gitLeaksSecurityScan
      - task: Gitleaks@2
          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
    - job: _publishArtifact
      - task: PublishPipelineArtifact@1
          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
I am using a self-hosted agent for my pipeline

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.

- 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


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

Signup to get access to the full archive of everything that's been published and everything that's still to come.

Jim Musana