Azure Spring Clean: Compliance for Bicep with Checkov

It’s time for the Azure Spring Clean. The annual event is organised by Joe Carlyle and Thomas Thornton to encourage you to look at your Azure subscriptions and see how you could manage it better.

Azure Spring Clean

In this year’s article, we will look at a tool called Checkov that can help you check your Bicep code for best practices and compliance. So let’s get started.

What is Checkov

Checkov is an open-source tool that can be used to scan Infrastructure as Code (IaC) for best practice and compliance. Checkov allows you to validate your IaC against over 1000 built-in policies, along with the ability to create custom policies. Checkov supports all three major clouds and multiple IaC languages (Terraform, ARM, Bicep, CloudFormation, Kubernetes, Helm, Docker, and Ansible). We will focus on using this with Azure and Bicep files, but you could apply this to any of the other languages or clouds.

So what does Checkov look for? The built-in rules look for common misconfigurations and compliance with best practices. So some examples might include the following:

  • Storage accounts with the default network rule set to allow
  • Ensuring that HTTPS traffic is enforced
  • Identifying secrets in your code

Installing Checkov

Checkov is a Python tool, so you will need Python 3.7 or greater to run it. Once that is installed, you can install Checkov using PIP.

pip install checkov

Running Checkov

To run Checkov and scan your files, you need to run the Checkov command and point it at a folder that contains Bicep or ARM template files, and it will scan all files in that folder.

checkov -d <path to folder>

You can also scan a single file using the -f flag.

checkov -f <path to file>

This will start the scan. Checkov should automatically identify the type of files and use the appropriate scanner. Once complete, you should see the results output to the CLI.

Scan Results

You can see I have several passing rules and several more failed ones. Checkov has detected that it is scanning a Bicep file and has only run the validations for resources I am using. The scan results show a summary of the rules it has checked, the status and a link to a page that provides more detail.

The default scan will output to the CLI, but you can also output to a file using the --output-file-path parameter, providing a folder to output the files to. Combining this with the -o parameter allows us to output to a file in a specific format.

checkov -d <path to folder> --output-file-path c:\temp\checkov -o json

This will output json files with all the data listed in the CLI and more.

"check_id": "CKV_AZURE_34",
"bc_check_id": "BC_AZR_NETWORKING_14",
"check_name": "Ensure that 'Public access level' is set to Private for blob containers",
"check_result": {
    "result": "PASSED",
    "evaluated_keys": []
},

Skip Checks

If some checks generate false positives or you don’t wish to run, you can skip them using the --skip-check flag and the check ID to skip.

checkov -d <path to folder> --skip-check CKV_AZURE_23

This will skip this check for all files in the directory. For some languages, it is possible to use inline comments to skip a check just for that file. However, I have yet to find a way to do this in Bicep.

Pipeline Integration

So far, we have run tests manually in the CLI, but the best place to do this is in a pipeline after making changes to your code. There are plugins for some pipeline tools (Jenkins, for example), but there is not one for Azure DevOps; however, you can still undertake a Checkov scan. The easiest way to do this is using a docker container that already has Checkov configured and ready to go, so all you need to do is pass the files to scan.

The example below will:

  • Pull the latest version of the Checkov docker container
  • Run the container with your checked-out code mounted in the container
  • Run the scan and output the data in the JUnit XML format that Azure DevOps can read
  • Publish the scan results to Azure DevOps
stages:
  - stage: "runCheckov"
    displayName: "Checkov - Scan Bicep files"
    jobs:
      - job: "runCheckov"
        displayName: "Checkov scan for bicep"
        steps:
          - bash: |
              docker pull bridgecrew/checkov
            workingDirectory: $(System.DefaultWorkingDirectory)
            displayName: "Pull bridgecrew/checkov image"
          - bash: |
              docker run --volume $(pwd):/bicep bridgecrew/checkov --directory /bicep --output junitxml --soft-fail > $(pwd)/CheckovReport.xml
            workingDirectory: $(System.DefaultWorkingDirectory)
            displayName: "Run checkov"
          - task: PublishTestResults@2
            inputs:
              testRunTitle: "Checkov Results"
              failTaskOnFailedTests: true
              testResultsFormat: "JUnit"
              testResultsFiles: "CheckovReport.xml"
              searchFolder: "$(System.DefaultWorkingDirectory)"
            displayName: "Publish Test results"

Example from [Kasun Rajapkse](Checkov now supports scan Bicep- Bicep + Checkov + Azure DevOps | by Kasun Rajapakse | Enlear Academy)

Custom Policies

The quick win with Checkov is to use the built-in policies to validate your IaC against best practices and known misconfigurations quickly. However, creating your own custom policies using either YAML or Python is also possible. Custom policies are out of scope for this article, but you can find more details on them [here]([Custom Policies Overview - checkov](https://www.checkov.io/3.Custom Policies/Custom Policies Overview.html)).