DEV Community

Mauricio Choqueña Choque
Mauricio Choqueña Choque

Posted on

Applying SAST Tools to Infrastructure as Code — A Hands-On Look at Checkov

Why Infrastructure as Code Needs Static Analysis Too

Infrastructure as Code (IaC) — Terraform, Pulumi, OpenTofu, CloudFormation — turned infrastructure into something version-controlled, reviewable, and reproducible. But that also means a single misconfigured line — an S3 bucket left public, a security group open to 0.0.0.0/0, an unencrypted database — can be committed, merged, and deployed automatically, at scale, before anyone notices.

Static Application Security Testing (SAST) for IaC works the same way it does for application code: it parses configuration files without deploying anything, and flags insecure patterns against a known rule set. OWASP's list of Source Code Analysis Tools includes several options for this. This article focuses on Checkov, an open-source policy-as-code scanner built by Bridgecrew (now part of Palo Alto Networks), chosen here specifically because it's free, multi-cloud, and multi-framework — without relying on tfsec.

Why Checkov

Checkov scans IaC files and builds a graph representation of the resources and their relationships, then evaluates that graph against hundreds of built-in security and compliance policies.

Key features:

  • Supports Terraform, OpenTofu, CloudFormation, Kubernetes manifests, Dockerfiles, Helm charts, Serverless framework, ARM templates, and more — not limited to one IaC tool.
  • Over 1,000 built-in policies covering AWS, Azure, GCP, and Kubernetes best practices (CIS Benchmarks aligned).
  • Supports custom policies written in Python or YAML, so teams can encode their own organizational rules.
  • Outputs in CLI text, JSON, JUnit XML, and SARIF — SARIF format integrates directly with GitHub's Security tab.
  • Can suppress specific findings inline with comments, without disabling the whole rule globally.

Installing and Running Checkov

pip install checkov

# Scan a directory of Terraform files
checkov -d ./infrastructure

# Scan a single file
checkov -f main.tf

# Output as JSON for CI pipelines
checkov -d ./infrastructure -o json --output-file-path ./checkov_report.json
Enter fullscreen mode Exit fullscreen mode

A Real Example

Consider this Terraform snippet — a common pattern that looks harmless but hides several real misconfigurations:

resource "aws_s3_bucket" "data" {
  bucket = "company-data-bucket"
  acl    = "public-read"
}

resource "aws_security_group" "web" {
  name = "web-sg"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_db_instance" "app_db" {
  identifier        = "app-database"
  engine            = "mysql"
  instance_class    = "db.t3.micro"
  allocated_storage = 20
  storage_encrypted = false
  publicly_accessible = true
}
Enter fullscreen mode Exit fullscreen mode

Running checkov -f main.tf produces output like:
Check: CKV_AWS_20: "S3 Bucket has an ACL defined which allows public READ access."
FAILED for resource: aws_s3_bucket.data
File: main.tf:1-4
Check: CKV_AWS_24: "Ensure no security groups allow ingress from 0.0.0.0:0 to port 22"
FAILED for resource: aws_security_group.web
File: main.tf:6-13
Check: CKV_AWS_16: "Ensure RDS instances have storage_encrypted enabled"
FAILED for resource: aws_db_instance.app_db
File: main.tf:15-21
Check: CKV_AWS_17: "Ensure RDS instances are not publicly accessible"
FAILED for resource: aws_db_instance.app_db
File: main.tf:15-21

Each check includes a rule ID (CKV_AWS_20, CKV_AWS_24...), a human-readable description, the exact resource name, and the file/line range — enough for a developer to jump straight to the fix.

Fixing the Findings

resource "aws_s3_bucket" "data" {
  bucket = "company-data-bucket"
  acl    = "private"
}

resource "aws_security_group" "web" {
  name = "web-sg"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/16"]  # restricted to internal VPC range
  }
}

resource "aws_db_instance" "app_db" {
  identifier          = "app-database"
  engine              = "mysql"
  instance_class      = "db.t3.micro"
  allocated_storage   = 20
  storage_encrypted   = true
  publicly_accessible = false
}
Enter fullscreen mode Exit fullscreen mode

Re-running Checkov against the fixed file shows all four checks passing.

Integrating Checkov into a CI Pipeline

A minimal GitHub Actions workflow that scans every Terraform change and fails the build on findings:

name: IaC Security Scan with Checkov

on: [push, pull_request]

jobs:
  checkov-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Checkov
        uses: bridgecrewio/checkov-action@master
        with:
          directory: ./infrastructure
          framework: terraform
          output_format: sarif
          output_file_path: checkov-results.sarif
      - name: Upload SARIF to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: checkov-results.sarif
Enter fullscreen mode Exit fullscreen mode

Uploading the SARIF report to GitHub's Security tab means findings show up alongside other code scanning alerts, with no separate dashboard needed.

Public Repository Example

You can see Checkov applied to real Terraform code here:

  • github.com/bridgecrewio/checkov — the tool's own repository, which includes hundreds of example Terraform/CloudFormation/Kubernetes files used as test fixtures for its own rule set, under tests/terraform/checks.
  • github.com/bridgecrewio/terragoat — a deliberately vulnerable, multi-cloud Terraform application built specifically to be scanned by tools like Checkov, useful as a public sandbox to practice against realistic misconfigurations.

Cloning either repo and running checkov -d . locally demonstrates the tool against real, non-trivial infrastructure code.

Where Checkov Fits Among IaC SAST Tools

Tool IaC scope License Notes
Checkov Terraform, CloudFormation, Kubernetes, Helm, Dockerfile, ARM, Serverless Open source (Apache 2.0) Broadest framework coverage, graph-based analysis
Terrascan Terraform, Kubernetes, Helm Open source OPA/Rego-based policies
KICS (Checkmarx) Terraform, CloudFormation, Kubernetes, Docker, Ansible Open source Large community rule library
Cloud Custodian Cloud resources (runtime, not pure static) Open source More focused on ongoing compliance than pre-deploy scanning

Compared to single-framework scanners, Checkov's advantage is breadth: one tool can cover Terraform, Kubernetes manifests, and Dockerfiles in the same pipeline run, which reduces the number of separate security tools a team needs to maintain.

Conclusion

Securing infrastructure code doesn't require a heavyweight commercial platform to get started. An open-source, policy-as-code scanner like Checkov can catch real, high-impact misconfigurations — public buckets, open security groups, unencrypted databases — before terraform apply ever runs, and it does so across multiple IaC frameworks at once. For teams adopting DevSecOps practices, plugging a tool like this into CI is a low-cost, high-value first step toward "shifting left" on cloud security.

Top comments (0)