Infrastructure-as-code made it trivial to spin up a cloud environment in minutes. It also made it trivial to ship a misconfigured S3 bucket, an open security group, or an unencrypted database to production in those same minutes. Checkov, the open-source static analysis tool from Bridgecrew (now part of Palo Alto Networks’ Prisma Cloud), exists to catch those mistakes before terraform apply ever runs. Checkov’s newest release, version 3.3.29 (listed on October 13, 2026), ships more than 1,000 built-in policies and scans everything from Terraform and OpenTofu to Kubernetes manifests, CloudFormation templates, and Dockerfiles.
This tutorial walks through a full Checkov setup: installing the scanner, running your first scan, tuning out false positives, writing custom policies, wiring it into GitHub Actions and pre-commit, and mapping results to compliance frameworks. By the end you will have a working CI pipeline that blocks insecure infrastructure before it merges, plus a reference project you can copy into your own repository.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
What Is Checkov and Why IaC Security Scanning Matters in 2026
Checkov is a static analysis engine purpose-built for infrastructure-as-code. Instead of scanning running cloud accounts after the fact, it parses the configuration files that define your infrastructure, builds a graph of how resources connect, and flags configurations that violate security or compliance rules. A public S3 bucket, a security group open to 0.0.0.0/0, an IAM policy with wildcard permissions, or a Kubernetes pod running as root all get caught at the pull-request stage, long before a cloud engineer clicks apply.
The project is maintained under the bridgecrewio organization on GitHub, carries roughly 9,000 GitHub stars, and ships under the Apache 2.0 license, so the core scanner is free to use commercially with no seat limits. Checkov’s graph-based engine distinguishes it from simpler regex-style linters: it traces relationships between resources across multiple files, so it can catch a misconfiguration that only becomes dangerous when two separate resources are combined, such as a public load balancer pointed at a database with no encryption.
Shift-left security has moved from a buzzword to standard practice. Gartner’s research on DevSecOps adoption found that “in 2023, 50% of respondents said their organizations had implemented DevSecOps, while 31% were implementing it and 11% planned to implement it,” and that among teams who had already adopted it, “66% reported fewer security incidents,” according to Gartner’s peer community research on DevSecOps strategies. Tools like Checkov are a big part of how that shift actually happens day to day, since they turn security review from a manual gate into an automated check that runs on every commit.
How Checkov’s Graph-Based Scanning Engine Actually Works
Most people’s first mental model for a static scanner is a glorified grep: a tool that reads each file line by line and flags a string pattern it does not like. Checkov does something closer to what a compiler does. It parses Terraform, CloudFormation, or Kubernetes YAML into an abstract representation, then builds a directed graph connecting every resource, variable, module, and data source reference across the entire scanned directory, not just within a single file.
That graph is what lets Checkov answer questions a line-by-line scanner cannot. A security group resource on its own might look fine; the same security group attached to an EC2 instance that also has a public IP and no bastion host in front of it is a different risk entirely. Checkov’s graph checks traverse those relationships the way a human reviewer tracing through a Terraform module tree would, except it does it in seconds across every file in the repository rather than hours across a handful of pull requests a reviewer has time to actually read.
This also explains why Checkov’s resource-count matters for scan time. A ten-resource sandbox environment resolves its graph almost instantly. A sprawling monorepo with cross-referenced modules, remote state data sources, and hundreds of resources takes measurably longer, because the engine has to resolve every reference before it can evaluate a single graph-based check. Scoping scans by framework and directory, covered in Step 4 below, is the main lever for keeping that resolution time manageable as a codebase grows.
Checkov vs tfsec vs Terrascan vs Trivy vs Snyk IaC: How the Scanners Compare
Checkov is not the only IaC scanner, and it is not always the right default. Terraform-only shops sometimes prefer a narrower, faster tool, while teams that already run a broader vulnerability scanner may want to consolidate rather than add another CLI. Here is how the main options line up as of October 2026.
| Tool | License | Frameworks Covered | Best Fit |
|---|---|---|---|
| Checkov | Apache 2.0, free | Terraform, OpenTofu, CloudFormation, Kubernetes, Helm, ARM, Bicep, Dockerfile, Ansible, Serverless, AWS CDK | Multi-cloud, multi-framework shops that want one scanner for everything |
| tfsec | MIT, free | Terraform HCL only | Terraform-only teams that want a lightweight, narrowly scoped scanner |
| Terrascan | Apache 2.0, free | Terraform, Kubernetes, Helm, Kustomize, CloudFormation, ARM | Teams already invested in Rego-based policy-as-code |
| Trivy | Apache 2.0, free | IaC plus container images, OS packages, language dependencies, secrets, filesystems | Teams that want one tool covering both artifact vulnerabilities and IaC misconfigurations |
| Snyk IaC | Commercial, free tier limited | Terraform, CloudFormation, Kubernetes, ARM | Teams already paying for the Snyk platform who want unified dashboards |
Checkov and Open Policy Agent (OPA) get confused for competitors, but they solve different problems. OPA is a general-purpose policy engine written in Rego that can enforce rules anywhere in your stack, from Kubernetes admission control to API gateways. Checkov is purpose-built for IaC, with parsers already written for a dozen formats and more than 1,000 checks ready to run on day one. You can run both side by side: Checkov for IaC-specific misconfiguration checks, OPA for broader runtime and admission policy. Checkov is also not a replacement for Terraform Cloud or HCP Terraform’s own policy mechanism; it is complementary and runs independently of whatever remote-state backend you use.
Prerequisites: Tools, Versions, and Permissions You Need Before You Start
Before you start scanning, get these pieces in place. None of this requires cloud credentials, since Checkov scans static configuration files on disk rather than live infrastructure.
- Python 3.9 through 3.12, if you are installing via pip (check with
python3 --version) - pip 23 or newer, or Homebrew on macOS/Linux, or Docker 24+ if you prefer the container image
- Checkov 3.3.29 (released October 13, 2026) or later
- Git, and a local clone of the Terraform, Kubernetes, or CloudFormation repository you want to scan
- A code editor with YAML and HCL syntax highlighting (VS Code, JetBrains, or similar)
- GitHub Actions, GitLab CI, or another CI runner if you plan to gate merges on scan results
- pre-commit 3.x installed locally if you want local feedback before you even push
- Roughly 15 minutes for the base install and first scan, more if you are writing custom policies
Checkov needs no network access to scan your code; it works entirely offline against the files in front of it. The only exception is if you enable Checkov’s optional cloud-platform integration for centralized reporting, which is a separate, paid Prisma Cloud feature and not required for anything in this tutorial.
Step 1: Install Checkov With pip, Homebrew, or Docker
Pick one installation path based on how your team already manages Python tooling. The pip route is the most common and the one Checkov’s own documentation leads with.
# Option 1: pip (most common)
pip install checkov
# Option 2: Homebrew (macOS/Linux)
brew install checkov
# Option 3: Docker, no local Python required
docker pull bridgecrew/checkov:latest
# Verify the install and print the version
checkov --version
If checkov --version prints 3.3.29 or newer, you are on the current release line, and anything older, including 3.3.28, is no longer the newest build. Windows users also benefit from Checkov 3.2.527, which Safeguard reported fixed Windows drive-letter and UNC paths in May 2026. Pin this version in your requirements file or CI config rather than tracking “latest,” since Checkov ships new releases roughly every few days and an unpinned upgrade mid-sprint can silently add new failing checks to a build that passed the day before.
Step 2: Run Your First Scan Against a Terraform Directory
Point Checkov at any directory containing Terraform, and it auto-detects the framework without any flags.
# Scan a local directory
checkov -d ./infra
# Or scan with Docker, mounting the current directory
docker run --rm -v "$PWD:/tf" bridgecrew/checkov -d /tf
Checkov walks every file in the directory, identifies Terraform, Kubernetes, or any other supported format automatically, and runs every applicable built-in policy against each resource it finds. On a small repository with a few dozen resources, this takes a handful of seconds. On a monorepo with thousands of resources across multiple cloud accounts, expect the first scan to take a few minutes while Checkov builds its resource graph. Scan speed keeps improving between releases: Safeguard reported that Checkov 3.2.527 improved scans from 11.4s to 9.8s in May 2026.
Step 3: Read and Interpret the Checkov Report Output
The default CLI output groups results by check, showing passed and failed checks with the exact file and line number responsible.
Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
FAILED for resource: aws_s3_bucket.reports
File: /infra/storage.tf:12-18
Guide: https://docs.checkov.io/en/latest/checks/CKV_AWS_18.html
12 | resource "aws_s3_bucket" "reports" {
13 | bucket = "acme-reports-prod"
14 | }
Check: CKV_AWS_23: "Ensure every security group rule has a description"
PASSED for resource: aws_security_group.app
Passed checks: 42, Failed checks: 3, Skipped checks: 1
Each failed check includes a check ID (CKV_AWS_18 in the example above), a plain-English description, the exact file and line range, and a link to Checkov’s documentation explaining why the rule exists and how to fix it. That check ID is the thing you will reference constantly: when you suppress a check, write a custom policy, or search Checkov’s GitHub issues for context, you search by ID, not by description.
Step 4: Scope Scans to Specific Frameworks, Directories, and Checks
A monorepo with Terraform, Kubernetes, and Dockerfiles living side by side does not always need every framework scanned on every run. Narrow the scope with flags.
# Only scan Terraform, ignore Kubernetes and Dockerfiles in the same repo
checkov -d . --framework terraform
# Scan multiple specific frameworks
checkov -d . --framework terraform kubernetes
# Run only a specific check or a specific category of checks
checkov -d . --check CKV_AWS_18,CKV_AWS_19
# Exclude a path entirely, such as test fixtures
checkov -d . --skip-path "tests/fixtures"
Scoping matters most in CI, where a full unscoped scan across a large monorepo adds unnecessary minutes to every pipeline run. Splitting the scan by framework and running each in parallel across separate CI jobs usually cuts wall-clock time substantially on larger repositories.
Step 5: Suppress False Positives With Inline Skips and a Config File
Not every flagged check applies to every situation. A development-only S3 bucket that intentionally allows public read for static asset hosting is not a bug, and Checkov lets you document that decision instead of just ignoring the warning.
# Inline suppression directly in the Terraform file
resource "aws_s3_bucket" "static_assets" {
bucket = "acme-public-assets-dev"
#checkov:skip=CKV_AWS_18:Dev bucket for public static assets, logging not required
}
For suppressions that should apply repo-wide rather than resource-by-resource, use a persistent config file instead of scattering inline comments everywhere.
# .checkov.yaml at the repo root
framework:
- terraform
- kubernetes
skip-check:
- CKV_AWS_8 # Launch config encryption, handled at the AMI level
- CKV_K8S_21 # Default namespace usage, acceptable in this sandbox cluster
compact: true
quiet: true
Checkov picks up .checkov.yaml automatically if it sits in the directory you scan, so you do not need to pass it explicitly with a flag on every run. Treat every entry in that skip list as something a reviewer should question during a security audit, since an unexplained skip list that grows unchecked quietly erodes the value of the whole scan.
Step 6: Write a Custom Policy in Python or YAML
Built-in checks cover the common cloud misconfigurations, but every organization has internal rules that no public ruleset will ever cover, like requiring a specific tag on every resource or banning a deprecated instance type. Checkov supports custom policies in both YAML (for simple attribute checks) and Python (for anything that needs real logic).
# custom_checks/CostCenterTag.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckCategories, CheckResult
class CostCenterTag(BaseResourceCheck):
def __init__(self):
name = "Ensure resource has a cost_center tag"
id = "CKV_CUSTOM_1"
supported_resources = ["aws_instance", "aws_s3_bucket"]
categories = [CheckCategories.GENERAL_SECURITY]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
tags = conf.get("tags", [{}])[0]
if tags.get("cost_center"):
return CheckResult.PASSED
return CheckResult.FAILED
check = CostCenterTag()
Point Checkov at the directory holding your custom checks with --external-checks-dir custom_checks, and it merges them with the built-in policy set automatically. Custom check IDs should use a distinct prefix like CKV_CUSTOM_ so they never collide with a built-in ID in a future Checkov release.
Step 7: Export SARIF, JUnit, and CycloneDX Reports for Your Toolchain
The default CLI output is fine for a human reading a terminal, but CI systems, code-scanning dashboards, and compliance tooling want structured output. Checkov supports several export formats out of the box.
# SARIF, for GitHub Advanced Security code scanning
checkov -d . -o sarif --output-file-path results.sarif
# JUnit XML, for CI systems that render test-style reports
checkov -d . -o junitxml --output-file-path results.xml
# CycloneDX, for feeding software bill of materials tooling
checkov -d . -o cyclonedx --output-file-path results.xml
# JSON, for custom dashboards or scripting
checkov -d . -o json --output-file-path results.json
Uploading the SARIF file to GitHub’s code scanning API surfaces Checkov findings directly in the Security tab of your repository, right next to CodeQL and Dependabot alerts, which keeps security triage in one place instead of scattered across separate tools.
Step 8: Wire Checkov Into GitHub Actions
A local scan only helps if someone remembers to run it. Gating pull requests on a Checkov scan makes the check mandatory rather than optional.
# .github/workflows/checkov.yml
name: Checkov IaC Scan
on:
pull_request:
paths:
- "infra/**"
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: infra
framework: terraform
output_format: sarif
output_file_path: results.sarif
soft_fail: false
- name: Upload SARIF to code scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
With soft_fail: false, a failed check returns a non-zero exit code and blocks the merge if branch protection requires the check to pass. Flip it to true during the rollout period so the team can see findings without blocking anyone, then switch it to a hard fail once the backlog of existing violations is under control.
Step 9: Add Checkov as a Pre-Commit Hook for Local Feedback
Catching a misconfiguration in CI is good; catching it before the commit even happens is better, since it skips an entire round trip of push, wait, read CI logs, and fix. Checkov ships a ready-made pre-commit hook.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/bridgecrewio/checkov.git
rev: 3.3.29
hooks:
- id: checkov
args: ["--framework", "terraform", "--compact"]
Run pre-commit install once per clone to activate the hook, and every future commit touching Terraform files triggers a scan automatically. Local hooks are convenience, not enforcement, since anyone can bypass them with git commit --no-verify. Keep the CI gate from Step 8 as the actual security control and treat the pre-commit hook purely as faster developer feedback.
Step 10: Scan Kubernetes Manifests, Dockerfiles, and CloudFormation Templates
Checkov’s framework support goes well past Terraform. The same command structure applies across every supported format, which is the entire point of consolidating on one scanner.
| Framework | Scan Command | Typical Finding |
|---|---|---|
| Kubernetes manifests | checkov -d ./k8s --framework kubernetes | Container running as root, missing resource limits, privileged pod |
| Dockerfile | checkov -d . --framework dockerfile | Missing USER directive, use of latest tag, exposed secrets in build args |
| CloudFormation | checkov -d ./cfn --framework cloudformation | Unencrypted RDS instance, public Lambda function URL |
| Helm charts | checkov -d ./charts --framework helm | Insecure default values propagated into the rendered manifest |
| ARM / Bicep | checkov -d ./arm --framework arm | Storage account allowing public blob access |
Running one scanner across every one of these formats, rather than a different point tool per language, is the main practical argument for choosing Checkov over a narrower, Terraform-only option like tfsec once a team’s infrastructure spans more than one format.
Step 11: Map Checks to Compliance Frameworks (CIS, NIST, SOC 2, PCI DSS)
Security and compliance teams rarely ask “did Checkov pass.” They ask “are we compliant with the CIS AWS Foundations Benchmark” or “can we show this control for our SOC 2 audit.” Checkov’s compliance flag maps individual checks to named frameworks so you can answer that question directly.
# Scan and filter output to a specific compliance framework
checkov -d . --framework terraform --compact \
--check "$(checkov --list | grep CIS_AWS | cut -d' ' -f1 | tr '\n' ',')"
# Or use the built-in compliance report flag where supported
checkov -d . --framework terraform -o compliance --compact
The mapped checks also get tuned over time: AppSec Santa listed Checkov 3.2.529 on May 14, 2026, with an update to the 90-day key-rotation check. Treat the compliance mapping as a starting point for the auditor conversation, not the finished artifact. Checkov confirms that your infrastructure configuration meets a specific technical control; it has no visibility into process controls, access reviews, or the parts of a SOC 2 or PCI DSS audit that live outside the configuration files themselves.
Step 12: Set Hard-Fail Gates and Baseline Existing Violations
Turning on Checkov against a repository that has been running in production for three years almost always surfaces hundreds of pre-existing violations on the first scan. Hard-failing the build on day one just blocks every single PR and gets the check disabled within a week. Baseline the existing violations first, then gate only on new ones.
# Generate a baseline of current violations
checkov -d . --framework terraform --create-baseline
# This writes .checkov.baseline next to .checkov.yaml
# Future scans compare against it and only report NEW violations
checkov -d . --framework terraform --baseline .checkov.baseline
Pair the baseline with a tracked backlog ticket for every pre-existing violation, and set a deadline to burn that backlog down. A baseline that never shrinks just becomes a permanent exemption list, which defeats the purpose of scanning in the first place.
Step 13: Monitor, Update, and Maintain Your Checkov Pipeline Over Time
Checkov ships new releases frequently, sometimes multiple times a week (Uniget listed Checkov 3.3.29 on October 13, 2026, following 29 releases in the 3.3 series), as new checks get added for newly disclosed misconfiguration classes and newly released cloud resource types. A pipeline you set up once and never revisit falls out of date quickly.
- Bump the pinned Checkov version on a monthly cadence rather than ad hoc, and review the changelog for new checks that might newly fail your existing infrastructure
- Re-run the baseline step after every version bump, since a new release can introduce new checks that immediately flag existing resources
- Rotate ownership of the skip-check list quarterly so suppressions get re-justified instead of accumulating forever
- Track pass/fail trends over time, not just pass/fail on the latest commit, to catch slow regressions in infrastructure hygiene
Gartner’s longer-run forecast on DevSecOps adoption projected that “DevSecOps practices would be embedded in 85% of product development teams by 2027, compared with 30% in 2022,” based on Gartner’s research cited by GlobalSign’s summary of essential steps to enable security in DevOps. A scanner that nobody maintains past the initial rollout will not get a team anywhere near that bar, no matter how well the first week of setup goes.
Common Pitfalls When Rolling Out Checkov
Most Checkov rollouts that stall or get abandoned fail for process reasons, not technical ones. The scanner itself is reliable once installed correctly; the mistakes below are almost all about how a team introduces it, not about Checkov’s own behavior.
- Hard-failing the build on day one. Rolling Checkov out against an existing repository without a baseline step blocks every open pull request simultaneously and almost always leads to the check getting disabled within days.
- Letting the skip-check list grow without review. Every suppressed check is a security decision. Without an owner and an expiration date, skip lists become permanent exemptions nobody remembers approving.
- Scanning the wrong directory in a monorepo. Pointing Checkov at the repository root in a large monorepo scans vendored modules, test fixtures, and documentation examples alongside real infrastructure, inflating both scan time and noise.
- Treating a passing scan as a finished security review. Checkov catches known misconfiguration patterns. It does not catch a legitimately risky architectural decision that happens to be correctly configured, so it supplements rather than replaces a human security review for anything high-risk.
- Not pinning the Checkov version in CI. An unpinned “latest” tag can introduce new failing checks in the middle of a sprint with no warning, since Checkov adds checks frequently.
- Ignoring the difference between soft fail and hard fail during rollout. Jumping straight to a hard fail without a visibility period means the first time most engineers see Checkov’s output is when it blocks their merge, which breeds resentment toward the tool rather than buy-in.
None of these are reasons to skip Checkov. They are reasons to sequence the rollout deliberately: baseline first, soft-fail for a visibility window, then switch to a hard gate once the team has seen the output and the backlog is under control. Teams that follow that order rarely end up disabling the check later.
Troubleshooting Checkov: 8 Common Issues and Fixes
Most Checkov problems fall into a handful of repeating categories: a path or framework flag that does not match the directory layout, a version mismatch between a laptop and a CI runner, or a custom policy that silently never fires because of a small configuration mistake. The table below covers the issues that come up most often once a team moves past the first successful scan and starts running Checkov in CI on a daily basis.
| Issue | Likely Cause | Fix |
|---|---|---|
| Checkov reports zero checks run | Framework not auto-detected, or wrong directory path | Pass --framework terraform explicitly and confirm the path with -d points at the actual files |
| Scan hangs on a large Terraform module | Deep module nesting forcing a large graph build | Scan modules independently with --download-external-modules false to skip remote module resolution |
| Custom policy never triggers | Check ID collides with a built-in ID, or wrong resource type in supported_resources | Use a CKV_CUSTOM_ prefix and confirm the exact resource type string matches the provider schema |
| Inline skip comment ignored | Comment placed outside the resource block, or typo in the check ID | Place #checkov:skip= inside the resource block, and copy the check ID exactly from the failed output |
| SARIF upload rejected by GitHub | File exceeds GitHub’s SARIF size limit, usually from scanning vendored code | Scope the scan with --skip-path to exclude vendored or generated directories |
| Different results locally vs. in CI | Version mismatch between a developer’s local install and the pinned CI version | Pin the exact version in both pre-commit config and CI workflow, and verify with checkov --version |
| Docker scan reports path not found | Volume mount path mismatch between host and container | Confirm the -v "$PWD:/tf" mount matches the -d /tf path passed to Checkov inside the container |
| Baseline file causes merge conflicts | Multiple branches regenerating the baseline independently | Regenerate and commit the baseline only from a single protected branch, then rebase feature branches onto it |
Advanced Tips: Graph Checks, Terraform Plan Scanning, and Policy-as-Code at Scale
Once the basic pipeline runs reliably, a few advanced techniques get more value out of Checkov without much extra setup time.
Scan the Terraform plan, not just the raw HCL. Static HCL scanning cannot see values that only exist after variable interpolation, data source lookups, or module outputs resolve. Run terraform plan -out=tfplan followed by terraform show -json tfplan > plan.json, then point Checkov at the JSON plan with checkov -f plan.json. This catches misconfigurations that only become visible once Terraform actually resolves every variable and reference, which static scanning alone misses.
Use graph checks for cross-resource logic. Checkov’s graph-based checks, written in YAML with a connection block, can flag a pattern that only matters when two resources interact, such as a security group attached to an instance that also has a public IP. A simple per-resource check cannot express that relationship; a graph check can.
Run framework-specific scans in parallel CI jobs. Splitting a single Checkov invocation covering Terraform, Kubernetes, and Dockerfiles into three parallel jobs, one per framework, cuts wall-clock scan time on large repositories and gives clearer, framework-specific failure messages in the CI UI.
Centralize policy exceptions in version control, not tribal knowledge. Every skip-check entry, every baseline regeneration, and every custom policy change should go through the same pull-request review as application code. Treating policy-as-code with the same rigor as the code it governs is what separates a scanner that actually improves security posture from one that becomes theater.
A Real Example: Catching a Public Database Before It Ships
Here is what the full pipeline looks like on an actual pull request, end to end, using the setup from Steps 1 through 12. A developer adds a new RDS instance to infra/database.tf to support a new feature, forgets to set storage_encrypted = true, and opens a pull request.
$ git commit -m "add reporting database"
Checkov IaC Scan.......................................................Failed
- hook id: checkov
- exit code: 1
Check: CKV_AWS_16: "Ensure RDS instances have encryption at rest enabled"
FAILED for resource: aws_db_instance.reporting
File: /infra/database.tf:4-11
4 | resource "aws_db_instance" "reporting" {
5 | identifier = "reporting-db"
6 | engine = "postgres"
7 | instance_class = "db.t3.medium"
8 | allocated_storage = 50
9 | }
Passed checks: 1, Failed checks: 1, Skipped checks: 0
The pre-commit hook from Step 9 catches this before the commit even completes locally, so the developer fixes it in under a minute by adding one line, storage_encrypted = true, and commits again. If the hook had been bypassed with --no-verify, the GitHub Actions workflow from Step 8 would have caught the same failure during CI, blocked the merge through branch protection, and surfaced the finding in the repository’s Security tab through the uploaded SARIF file. Either way, the unencrypted database never reaches production, and no human reviewer had to notice the missing line by eye while scanning a pull request diff.
This is the practical payoff of the setup in this tutorial. The check itself, CKV_AWS_16, is one of more than 1,000 built-in policies Checkov ships out of the box, so nobody on the team had to know in advance that RDS encryption was a thing to check for. The scanner already knew.
Build a Complete Working Project: Sample Terraform Repo With CI Gating
Here is a minimal but complete project structure that ties every step in this tutorial together. Copy this layout into a new repository and adapt the Terraform resources to your own environment.
my-infra-repo/
âââ .github/
â âââ workflows/
â âââ checkov.yml # Step 8: CI gate
âââ .pre-commit-config.yaml # Step 9: local hook
âââ .checkov.yaml # Step 5: scoped skip-check config
âââ .checkov.baseline # Step 12: baseline of pre-existing findings
âââ custom_checks/
â âââ CostCenterTag.py # Step 6: custom policy
âââ infra/
â âââ storage.tf
â âââ network.tf
â âââ compute.tf
âââ k8s/
âââ deployment.yaml
With this layout in place, the workflow looks like this end to end: a developer edits infra/storage.tf, the pre-commit hook scans it locally before the commit even lands, the push triggers the GitHub Actions workflow which runs the same scan scoped to the infra directory, results upload as SARIF to the Security tab, and the baseline file ensures only genuinely new violations block the merge. Every piece reuses the exact commands from Steps 1 through 12, just assembled into one pipeline instead of run manually one at a time.
Checkov’s own documentation at checkov.io and the bridgecrewio/checkov repository on GitHub stay the authoritative source for the full, current list of built-in checks, since the policy set grows with nearly every release. Cross-reference any check ID you are unsure about against the GitHub releases page before deciding whether to suppress it or fix the underlying resource.
Frequently Asked Questions
Is Checkov free to use commercially?
Yes. The core Checkov CLI ships under the Apache 2.0 license with no seat limits, no usage caps, and no paid tier required for local scanning, custom policies, or CI/CD integration. Prisma Cloud adds a separate paid platform layer with centralized dashboards, pull-request annotations, and runtime scanning on top of the same open-source engine.
Does Checkov replace a vulnerability scanner like Trivy or Snyk?
No. Checkov focuses on IaC misconfigurations: public resources, missing encryption, overly permissive access. It does not scan container images for known CVEs in OS packages or language dependencies the way Trivy or Snyk’s broader scanners do. Many teams run Checkov for IaC and a separate scanner for image and dependency vulnerabilities.
What is the latest Checkov version as of October 2026?
Checkov 3.3.29 is the newest release, published on GitHub on October 13, 2026. Versions before it, including 3.3.28, are no longer the newest, which is normal given how frequently the project ships.
Can Checkov scan a Terraform plan instead of raw HCL files?
Yes. Run terraform show -json against a saved plan file and point Checkov at the resulting JSON with the -f flag. Scanning the resolved plan catches misconfigurations hidden behind variable interpolation or module outputs that static HCL scanning alone cannot see.
How is Checkov different from Open Policy Agent (OPA)?
OPA is a general-purpose policy engine using the Rego language that can enforce rules anywhere in a stack, from Kubernetes admission control to API gateways. Checkov is purpose-built for IaC scanning, with more than 1,000 pre-written checks and parsers for a dozen IaC formats ready to use immediately, without writing any Rego.
Will Checkov break my CI pipeline the first time I turn it on?
It can, if you skip the baseline step. Scanning years-old infrastructure for the first time typically surfaces a large number of pre-existing violations. Generate a baseline with --create-baseline first, gate only on new violations going forward, and work down the pre-existing backlog separately.
Does Checkov support Kubernetes and Docker, or only Terraform?
Checkov supports Terraform, OpenTofu, CloudFormation, Kubernetes manifests, Helm charts, ARM templates, Bicep, Dockerfiles, Ansible, the Serverless Framework, AWS CDK, Kustomize, and OpenAPI specifications, all through the same command-line interface and the same configuration file.
How do I stop Checkov from flagging a specific resource I’ve reviewed and accepted?
Add an inline #checkov:skip=CHECK_ID:reason comment directly above or inside the resource block, or add the check ID to the skip-check list in a .checkov.yaml config file for a repo-wide suppression. Always include a reason, since an unexplained skip is the first thing a security reviewer will question.





