DEV Community

Hariharan
Hariharan

Posted on

DevSecOps in Practice: Tools That Actually Catch Vulnerabilities - Part 4 - IaC Scanning with Checkov

The previous parts covered application security — secrets, code vulnerabilities, and dependency CVEs. This part shifts to the infrastructure side. The Terraform in the repo describes the AWS resources the app would run on. If that infrastructure is misconfigured, it doesn't matter how clean the application code is. IaC scanning catches those misconfigurations before terraform apply ever runs.

Code repo: https://github.com/pkkht/devsecops-demo/

What IaC scanning is
Infrastructure as Code scanning analyses your Terraform, CloudFormation,
Kubernetes manifests, or Helm charts for security misconfigurations. It works the same way as SAST — static analysis, no cloud connection required. It checks your configuration files against a library of security rules and tells you what's wrong and how to fix it.
The value is catching misconfigurations at code review time rather than after they've been deployed to a live environment. An open S3 bucket found in a Terraform file takes seconds to fix. The same bucket found after a data exposure incident is a very different conversation.

The tool: Checkov
Checkov is an open source IaC scanner maintained by Bridgecrew (now part of Palo Alto Networks). It supports Terraform, CloudFormation, Kubernetes, Helm, ARM, Bicep, and more. It maps findings to CWE and CVE identifiers and has over 1000 built-in rules for AWS, Azure, and GCP.

The demo Terraform

The terraform/main.tf in the repo contains 6 intentional misconfigurations:

  1. S3 bucket without server-side encryption — data at rest is unencrypted
  2. S3 bucket set to public-read — all objects exposed to the internet
  3. S3 bucket versioning not enabled — no recovery from accidental deletion
  4. Security group open to 0.0.0.0/0 on all ports — any IP, any port
  5. EC2 with unencrypted EBS root volume — encrypted = false
  6. No IMDSv2 enforcement — SSRF attacks can reach the instance metadata service

Local setup is skipped here for brevity — Checkov has known issues running
on Windows paths with spaces. The GitHub Actions workflow handles the scan
in a clean Linux environment.

GitHub Actions workflow
Create .github/workflows/iac.yml:

name: IaC - Checkov

on:
  push:
    branches: ["**"]
  pull_request:
    branches: ["**"]

jobs:
  checkov:
    name: Checkov IaC Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install Checkov
        run: pip install checkov

      - name: Run Checkov
        run: checkov -d terraform/ -o json > checkov-report.json

      - name: Upload Checkov Report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: checkov-report
          path: checkov-report.json
Enter fullscreen mode Exit fullscreen mode

What the pipeline found

The workflow failed as expected. GitHub Actions downloaded the checkov-report.json artifact which contains the full findings. Here's a snapshot of what Checkov caught — 18 failed checks across 4 resources:

"summary": {
  "passed": 10,
  "failed": 18,
  "skipped": 0,
  "resource_count": 4,
  "checkov_version": "3.2.524"
}
Enter fullscreen mode Exit fullscreen mode

The intentional misconfigurations were all caught, plus several additional
issues Checkov flagged that weren't in the original list. That's worth
noting — a real codebase will always have more findings than you expect.

Breaking down the failed checks by resource:

aws_security_group.app_sg — 5 failures

The wide-open ingress rule (from_port = 0, to_port = 65535, cidr = 0.0.0.0/0) triggered multiple checks because Checkov evaluates each port range independently. One misconfiguration, five findings.

aws_instance.app_server — 5 failures

aws_s3_bucket.app_storage — 8 failures

A single example finding from the JSON report:

{
  "check_id": "CKV_AWS_79",
  "check_name": "Ensure Instance Metadata Service Version 1 is not enabled",
  "check_result": { "result": "FAILED" },
  "resource": "aws_instance.app_server",
  "file_path": "/main.tf",
  "file_line_range": [81, 102]
}
Enter fullscreen mode Exit fullscreen mode

Why 18 failures from 6 misconfigurations
One thing worth explaining for readers who run this themselves — you'll see more failures than the 6 intentional misconfigurations. Checkov has over 1000 rules and many of them overlap. A single misconfigured security group rule triggers checks for SSH, RDP, HTTP, and unrestricted egress separately. A single S3 bucket without proper access controls triggers checks for ACLs, public access blocks, KMS encryption, versioning, and logging independently.
This is expected behaviour, not noise. Each check represents a distinct
security concern, and a real security review would assess each one individually.

What we've built so far
Five layers now in place:

  • Gitleaks pre-commit — blocks secrets at commit time
  • Gitleaks GitHub Actions — catches secrets at push time
  • Bandit GitHub Actions — catches code vulnerabilities, gates on HIGH severity
  • pip-audit GitHub Actions — catches vulnerable dependencies
  • Checkov GitHub Actions — catches Terraform misconfigurations before deployment

Top comments (0)