As the name suggests, Static analysis is the ability to scan software code to search and highlight deviations from specified standards. The purpose of static code analysis is to speed up the feedback process of developing software or infrastructure.
In general, once code is merged/committed to a repository, failures/defects/bugs are identified during the following stages: code build, unit testing, build deployment, functional testing, or after product release. The cost of fixing a defect increases as the code moves further away (towards the right) from the code repository to the production environment. Hence, it makes financial sense to identify defects and fix them as early as possible. It is possible to reduce and maybe prevent buggy code from being merged using a pull-request-based workflow. That is achieved by associating a pull-request policy with a code build and unit testing check to ensure that the incoming changes do not (a) break the build and (b) cause unit tests to fail. Static analysis is a practical approach to identifying such code and should be added to the pull request policy. A static analysis tool searches for anomalies in code and determines the level of deviation to highlight depending upon the static-analysis policies selected. The objective is to search for patterns that can turn into defects later and address them as early as possible.
While researching on this topic, I came across an informative starting point at Microsoft-docs. I read up about the four tools mentioned there and decided to proceed with Checkov. Per Bridgecrew, Checkov is a static code analysis tool for scanning infrastructure as code (IaC) files for misconfigurations that may lead to security or compliance problems. Checkov includes more than 750 predefined policies to check for common misconfiguration issues. That was an excellent starting point. On further exploration, I found helpful blogs and Youtube videos on the topic. Before I delve deeper, I want to thank Ned Bellavance and Adin Ermie for showing me how to integrate these tools.
I have a GitHub code repository where I deployed an Amazon VPC and a few other networking infrastructure components using Terraform and Azure Pipelines –Working-with-Terraform-workspace-and-AWS. My objective in this note was to integrate Checkov into the toolchain.
In the project, I used azure-pipelines.yaml
to break the infrastructure deployment into multiple stages. These are stage: validate
where I ran terraform validate
against all the workspaces to check for code correctness, followed by stage: Dev
, Test
, and Prod
, where I deployed the infrastructure changes. Per the documentation, Checkov can be used to scan the .tf source files
and the terraform plan file
to identify anomalies and highlight them. Hence, I planned to run a scan against the terraform source code in the validate
stage and scan the plan file in each Dev
, Test
, and Prod
stage since the plan files
are separate for these three environments.
With that objective at hand and a little bit of research, I identified three steps to add to azure-pipelines.yaml
that had to be followed for each of these four stages.
Step 1: Install Checkov.
I used a bash task to install Checkov following the installation guide at Checkov-quick-start.
Step 2: Scan terraform configuration files.
I used a bash task to run the scan command where the output was formatted in JUnit. The command is self-explanatory. I selected the source folder with terraform configuration files to be the working directory
. And ran the checkov -d .
command to run that on the current directory. The output would be available on the build logs if I did not provide the -o junitxml
flag. By routing the output to an XML file, I published them in the next step.
Note: I added a continueOnError: true
so that, if the build failed (due to code scan identifying vulnerabilities), I could get the next step (publish report) to run and review the code scan failures.
Step 3: Publish the result.
Finally, I published the scan result in the last step, which Checkov produced via the familiar PublishTestResults
task.
I applied these three steps to the validate
stage.
However, as mentioned in the docs, Checkov can scan the Terraform plan file, too, and I followed a tweaked version of the above three steps for all the three stages, Dev
, Test
, and Prod
. I wrote “tweaked version” since I scanned the plan file, not the terraform configuration files. The below three steps provide a little more detail.
Step 1: Install Checkov.
This step is identical to the previous one, where I installed Checkov on the local build agent.
Step 2: Scan plan file.
For the following three stages(Dev
, Test
, and Prod
), I scanned the plan file using the command shown below. This task is started after Terraform created a tfplan file
.
This is a two-step process where the tfplan file
is converted to JSON, and then a Checkov scan is run on that to produce an XML file in JUnit format. Here is a little more information on terraform show and an example from checkov-terraform-scanning.
Step 3: Publish scan report.
This step was identical to step 3 of the validate
stage, where the scan report was published to be available for review.
These reports were available on the build page next to the Summary tab, titled Tests.
Here is an image of the scan result.
Based on the report’s title, I drilled down and identified the vulnerabilities in my code.
I titled the code scan report as testRuntitle: Terraform source code scan
in the PublishTestResults
task and was able to view the information as shown below.
I followed a similar approach for the plan file scan in Stage: Dev
and Test
and Prod
. If you are interested in knowing more, I have a link to the azure-pipelines build log. Click on the Test tab to review the vulnerabilities. The link to my GitHub repository is Working-with-Terraform-workspace-and-AWS.
Overall, I found it reasonably easy to integrate Checkov into azure-pipelines.yaml
to scan the Terraform configuration and plan files. The Checkov error log notifies which resource configuration has a security vulnerability (points to the line number in the terraform source file) and how to remediate it. E.g., the CKV_AWS_130/Ensure VPC subnets do not assign public IP by default
provides a link to the guideline where Checkov provides a fix to the vulnerability. In this case, it is to set the map_public_ip_on_launch
to false
.
There are multiple options from here on. I could either decide to review and fix the errors identified in the scan or introduce Checkov policy suppression blocks in the terraform code to suppress these errors. Here is an example of how to suppress policies.
Either way, it is an excellent mechanism to identify vulnerabilities in the Terraform configuration files. If you are interested, please give Checkov a try and share your findings. As I have shown, it is pretty easy to integrate that with the existing azure-pipelines.yaml
file to build the Terraform configuration files. If I can be of help, please don’t hesitate to reach out.
Note: I learned this concept from Ned’s video and Adin’s blog.