Sitemap
Susovan Panja

Susovan Panja

Cook, Gamer, Reader, Dreamer

Checkov — IaC Scanner

Tool Opinion

7 min readOct 14, 2024

--

My first interaction with Checkov was a few years back, and it resulted from one of the conversations I had with our Solutions Architect and my good friend Anirudh. A few people across the globe were contributing to the IaC code (Terraform), and we need to ensure misconfigurations do not creep into infrastructure via the IaC.

Press enter or click to view image in full size

Infrastructure Misconfiguration

It basically means we have created/coded our infrastructure in such a way that may cause data breach, compliance issue, hacking etc. unintentionaly

Examples of misconfiguration:
1. Storage bucket made public.
2. Database opened to public (0.0.0.0/0)
3. Un-restricted access on SSH ports (0.0.0.0/0)
4. pgaudit not enabled for Cloud Postgresql

What is Checkov?

Think of Checkvo as a SAST (Static Code Analysis) scanner for IaC code. It can find misconfigurations in IaC code that may lead to security or compliance problems. It comes with more than 750 predefined policies to check for common misconfiguration issues, which I find sufficient for most projects. It also supports custom policies, which is outside the scope of this article but may be in the future.

Press enter or click to view image in full size
https://www.checkov.io/

IaC types supported

Checkov supports a wide range of IaC types. Our scope will be Terraform on GCP.

  • Terraform (for AWS, GCP, Azure and OCI)
  • CloudFormation (including AWS SAM)
  • Azure Resource Manager (ARM)
  • Serverless framework
  • Helm charts
  • Kubernetes
  • Docker

Installation

{a} Install via pip =>

$ pip3 install checkov --user

{b} Install via homebrew =>

$ brew tap bridgecrewio/checkov https://github.com/bridgecrewio/checkov
$ brew update
$ brew install checkov

Running scan locally

For this article, we are going to use the terraform code that is “Vulnerable by Design” and provided by Checkov itself — TerraGoat

  1. Clone the repo.
$ git clone https://github.com/bridgecrewio/terragoat.git

2. Switch to terraform folder.

$ cd terragoat/terraform/

3. Execute the scan.

# For a single file we can use -f <file_name> and 
# for a directory -d <directory_name>
$ checkov -d gcp

Analyze the result

➜  terraform git:(master) checkov -d gcp
[ terraform framework ]: 100%|████████████████████|[7/7], Current File Scanned=gcp/variables.tf
[ secrets framework ]: 100%|████████████████████|[7/7], Current File Scanned=gcp/gcs.tf
_ _
___| |__ ___ ___| | _______ __
/ __| '_ \ / _ \/ __| |/ / _ \ \ / /
| (__| | | | __/ (__| < (_) \ V /
\___|_| |_|\___|\___|_|\_\___/ \_/

By Prisma Cloud | version: 3.2.257

terraform scan results:

Passed checks: 17, Failed checks: 56, Skipped checks: 0

Check: CKV_GCP_56: "Ensure PostgreSQL database 'log_temp_files flag is set to '0'"
PASSED for resource: google_sql_database_instance.master_instance
File: /big_data.tf:1-19
Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/google-cloud-policies/cloud-sql-policies/bc-gcp-sql-7
Check: CKV_GCP_55: "Ensure PostgreSQL database 'log_min_messages' flag is set to a valid value"
PASSED for resource: google_sql_database_instance.master_instance
File: /big_data.tf:1-19
Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/google-cloud-policies/cloud-sql-policies/bc-gcp-sql-6

If we analyze the above result, 17 passed and 56 failed.

Let's analyze one of the failed checks.

Check: CKV_GCP_11: "Ensure that Cloud SQL database Instances are not open to the world"
FAILED for resource: google_sql_database_instance.master_instance
File: /big_data.tf:1-19
Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/google-cloud-policies/google-cloud-networking-policies/bc-gcp-networking-4

1 | resource "google_sql_database_instance" "master_instance" {
2 | name = "terragoat-${var.environment}-master"
3 | database_version = "POSTGRES_11"
4 | region = var.region
5 |
6 | settings {
7 | tier = "db-f1-micro"
8 | ip_configuration {
9 | ipv4_enabled = true
10 | authorized_networks {
11 | name = "WWW"
12 | value = "0.0.0.0/0"
13 | }
14 | }
15 | backup_configuration {
16 | enabled = false
17 | }
18 | }
19 | }

The check is CKV_GCP_11: “Ensure that Cloud SQL database Instances are not open to the world”. This check will look for any Cloud SQL resource which are made public as part of our terraform code.

Get Susovan Panja’s stories in your inbox

Join Medium for free to get updates from this writer.

It will show the violating file name with line number “/big_data.tf:1–19” and the code snippet.

Also the link to the guide “https://docs.prismacloud.io/en/enterprise-edition/policy-reference/google-cloud-policies/google-cloud-networking-policies/bc-gcp-networking-4”, so that we can understand the vulnerability itself and also how to fix it.

Press enter or click to view image in full size
https://docs.prismacloud.io/

Exclusions

There maybe times, when we have written a resource in such a way that it is against best practices for infrastructure, but we have a clear use case for that. Example can be a public bucket that contains all the consumer facing documentation.

In those situations we need to exclude that resource or to suppress the check itself for the scanning job.

There are two ways of exclusion:

  1. Skip certain checks for the entire scan
# This will skip the above check failure (public Cloud SQL), multiple 
# <check_id> allowed
$ checkov -d gcp --skip-check CKV_GCP_11
OR
$ checkov -d gcp --skip-check CKV_GCP_11,CKV_GCP_12

2. Skip certain resources from the scan

To skip a check on a given Terraform definition block, apply the following comment pattern inside its scope: checkov:skip=<check_id>:<suppression_comment>

resource "google_sql_database_instance" "master_instance" {
name = "terragoat-${var.environment}-master"
database_version = "POSTGRES_11"
region = var.region

#checkov:skip=CKV_GCP_11:The Cloud SQL is part of honeypot setup

settings {
tier = "db-f1-micro"
ip_configuration {
ipv4_enabled = true
authorized_networks {
name = "WWW"
value = "0.0.0.0/0"
}
}
backup_configuration {
enabled = false
}
}
}

There are different ways for skipping/suppressing checks, depending upon the IaC type we are scanning. More examples here.

Integrations

Checkov can be integrated with the code repository and with CI/CD providers, like Jenkins, and GitHub Actions.

Sample GitHub Workflow:

---
name: Checkov
on:
push:
branches:
- master
jobs:
build:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v4
with:
python-version: 3.8
- name: Test with Checkov
id: checkov
uses: bridgecrewio/checkov-action@master
with:
directory: example/examplea
framework: terraform

For more integrations https://www.checkov.io/4.Integrations/GitHub%20Actions.html

When to scan

  1. Run the scan locally, before committing and pushing to git.
  2. Run it as part of MR (merge request) or PR (pull request).
  3. Run it as part of Terraform Build (plan, deploy).

Just to clarify, the above points are not OR but AND. Scan wherever and whenever possible.

Conclusion

As we rapidly move from on-prem to cloud infrastructure, the attack surface has increased exponentially. Infrastructure is the base of any application we build and run; it must be protected. If infrastructure is not secured, our application, and user data are also not secured.

Since we are treating infrastructure as code (IaC), we must embrace all the scanning, testing, and securing practices used by developers in SDLC and start introducing them in our IDLC (Infrastructure Development Life Cycle). Using Checkov or any other similar tool is step 1.

Bonus

Kubernetes Cluster Scanning (Realtime)

Checkov can be used to scan the Kubernetes cluster resources during runtime. It just needs read-only access. We need to apply the provided manifest and the scanning job will start on the cluster.

### List all the scan variables:
$ checkov -l --framework kubernetes

### k8s manifest file scanning:
$ checkov -f deployment.yaml

### Run checov against live k8s cluster:
$ kubectl apply -f https://raw.githubusercontent.com/bridgecrewio/checkov/main/kubernetes/checkov-job.yaml
$ kubectl get jobs -n checkov
$ kubectl logs job/checkov -n checkov

Helm Chart Scanning

Checkov can also scan helm charts. Helm charts are basically templates, so we need to convert them to actual deployable manifest files. The process is somewhat the same for third-party helm charts and private helm charts.

The steps are:

1. Add the helm repo to local helm registry. We can also fetch and extract the helm charts. So that we can examine the template/code and we know exactly what resources we are creating on k8s cluster, which images we are pulling etc. I prefer the second approach as I know exactly what I am doing with the helm chart and its easier to debug any issues.

2. Create chart configuration file i.e. gocd.yaml. Every helm chart have a values.yaml file, it contains the default config values for the chart. The approach should be create copy of this file, it can be named anything, in our case it is gocd.yaml. Update this new config file with all the changes we want and use this to apply the helm chart.

3. Use helm template command to convert the helm chart to deployable manifest file.

4. Run Checkov scan against the generated manifest file i.e. k8s-template.yaml

5. Analyze the result and adjust the helm chart accordingly.

### Download the helm chart and create the config file
$ helm repo add gocd https://gocd.github.io/helm-chart
$ helm inspect values gocd/gocd > gocd.yaml

### Run checov against helm charts:
$ helm template gocd/gocd -f gocd.yaml > k8s-template.yaml
$ checkov -f k8s-template.yaml --framework kubernetes

If you’ve enjoyed this story, please click the 👏 button and share it, so that others can find it as well! Also, feel free to leave a comment below.

--

--