Checkov¶
Static analysis tool for Infrastructure as Code (IaC). Scans Terraform, CloudFormation, Kubernetes, Dockerfile, ARM templates, Helm charts. 1000+ built-in policies. Prevents misconfigurations before deployment. Python-based, developed by Bridgecrew (acquired by Palo Alto Networks). Free and open-source.
2026 Update
Checkov 3.x brings AI-powered fix suggestions. Policy-as-code with custom Python policies. Supply chain security (SCA for Terraform modules). Secrets detection. IDE integrations (VSCode, IntelliJ). CI/CD native with exit codes. 1000+ policies covering CIS, PCI-DSS, HIPAA, SOC2.
Quick Hits¶
# Installation (Python pip)
pip install checkov
# Or via Homebrew (macOS/Linux)
brew install checkov
# Or use Docker
docker pull bridgecrew/checkov
# Scan Terraform directory
checkov --directory ./terraform
# Scan specific file
checkov --file main.tf
# Scan CloudFormation
checkov --framework cloudformation --file template.yaml
# Scan Kubernetes manifests
checkov --framework kubernetes --directory ./k8s
# Scan Dockerfile
checkov --framework dockerfile --file Dockerfile
# Scan Helm charts
checkov --framework helm --directory ./charts
# Multiple frameworks
checkov --framework terraform kubernetes dockerfile --directory .
# Specific checks only
checkov --check CKV_AWS_20,CKV_AWS_21 --directory .
# Skip specific checks
checkov --skip-check CKV_AWS_20 --directory .
# Output formats
checkov --directory . --output json
checkov --directory . --output junitxml # For CI/CD
checkov --directory . --output sarif # GitHub Code Scanning
# Soft fail mode (warnings only, exit 0)
checkov --directory . --soft-fail
# Compact output (summary only)
checkov --directory . --compact
# Show suppressed checks
checkov --directory . --show-suppressed
# Baseline file (suppress existing issues)
checkov --directory . --baseline baseline.json
Real talk:
- Run Checkov BEFORE
terraform applyto catch issues early - Exit code 1 = failures found (use in CI/CD pipelines)
--soft-failuseful during initial adoption (don't block)- JSON output enables custom dashboards and reporting
- Baseline files prevent legacy code from blocking new PRs
# Pre-commit hook integration
# .pre-commit-config.yaml
repos:
- repo: https://github.com/bridgecrewio/checkov
rev: 3.0.0
hooks:
- id: checkov
args: [--quiet, --compact]
# GitHub Actions workflow
name: IaC Security Scan
on: [push, pull_request]
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
output_format: sarif
soft_fail: false # Block on failures
- name: Upload results to GitHub
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: results.sarif
# GitLab CI integration
checkov:
stage: security
image: bridgecrew/checkov:latest
script:
- checkov --directory terraform/ --output junitxml > checkov-report.xml
artifacts:
reports:
junit: checkov-report.xml
allow_failure: false
# Terraform workflow (local development)
# 1. Write Terraform
# 2. Run Checkov
checkov --directory .
# 3. Fix issues or suppress with inline comments
# main.tf
resource "aws_s3_bucket" "example" {
# checkov:skip=CKV_AWS_20:Bucket is private, public access not needed
bucket = "my-bucket"
}
# 4. Terraform plan and apply
terraform plan
terraform apply
# CI/CD pipeline (Jenkins example)
stage('Security Scan') {
steps {
sh 'pip install checkov'
sh 'checkov --directory terraform/ --output junitxml > checkov.xml'
junit 'checkov.xml'
}
}
# Docker scan workflow
# Scan Dockerfile before building image
checkov --framework dockerfile --file Dockerfile
docker build -t myapp:latest .
# Kubernetes manifest validation
checkov --framework kubernetes --directory k8s/ --compact
kubectl apply -f k8s/
# Multi-cloud IaC scan
checkov \
--framework terraform \
--directory . \
--check CKV_AWS_*,CKV_AZURE_*,CKV_GCP_* \
--output json \
--output-file-path results.json
# Generate baseline (first-time adoption)
checkov --directory . --output json > baseline.json
# Edit baseline.json to suppress known issues
checkov --directory . --baseline baseline.json
Why this works:
- Pre-commit hooks catch issues before commit
- CI/CD integration blocks insecure code from merging
- Inline suppressions with justifications (audit trail)
- Baseline files enable gradual security improvements
- SARIF format integrates with GitHub Security tab
Best Practices
- Run locally first - Catch issues before CI/CD
- Pre-commit hooks - Prevent bad code from being committed
- Inline suppressions - Document why check is skipped
- Custom policies - Write organization-specific checks (Python)
- Baseline files - Don't block on legacy code, fix incrementally
- CI/CD gates - Block PRs with security issues
- IDE integration - Real-time feedback in VSCode/IntelliJ
Security Coverage
- Checks available:
- AWS: 300+ checks
- Azure: 200+ checks
- GCP: 150+ checks
- Kubernetes: 100+ checks
- Dockerfile: 50+ checks
- What Checkov catches:
- Public S3 buckets
- Unencrypted resources
- Overly permissive IAM policies
- Missing security groups
- Hardcoded secrets
- Container vulnerabilities
- What Checkov misses:
- Runtime issues (use Prowler)
- Application code vulnerabilities (use Snyk/SonarQube)
- Network traffic analysis (use runtime tools)
Custom Policies
# checks/custom_policy.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class CustomS3Check(BaseResourceCheck):
def __init__(self):
name = "Ensure S3 bucket has custom tag"
id = "CKV_AWS_CUSTOM_1"
supported_resources = ['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')
if tags and isinstance(tags, list):
tag_dict = tags[0]
if 'Environment' in tag_dict:
return CheckResult.PASSED
return CheckResult.FAILED
# Use custom policy
checkov --external-checks-dir ./checks --directory .
Common Gotchas
- False positives - Some checks are opinionated, suppress if needed
- Performance - Large Terraform codebases take 1-5 minutes
- Module scanning - External modules not scanned (security blind spot)
- Secrets detection - Basic, use dedicated tools (TruffleHog, GitGuardian)
- Cloud provider drift - New services may lack checks initially
- CI/CD blocking - Use
--soft-failduring initial rollout - Suppression abuse - Audit suppressed checks regularly
Checkov vs Alternatives
- vs Terraform Validate - Checkov = security, validate = syntax
- vs Tfsec - Checkov multi-framework, tfsec Terraform-only
- vs Prowler - Checkov pre-deployment, Prowler post-deployment
- vs Snyk IaC - Checkov open-source, Snyk commercial with SCA
- Use together - Checkov (IaC) + Prowler (runtime) = full coverage
Policy Examples¶
Common Security Checks¶
# FAIL: Public S3 bucket (CKV_AWS_18)
resource "aws_s3_bucket_acl" "bad" {
bucket = aws_s3_bucket.example.id
acl = "public-read" # Insecure!
}
# PASS: Private S3 bucket
resource "aws_s3_bucket_acl" "good" {
bucket = aws_s3_bucket.example.id
acl = "private"
}
# FAIL: Unencrypted EBS volume (CKV_AWS_3)
resource "aws_ebs_volume" "bad" {
availability_zone = "us-west-2a"
size = 40
# Missing: encrypted = true
}
# PASS: Encrypted EBS volume
resource "aws_ebs_volume" "good" {
availability_zone = "us-west-2a"
size = 40
encrypted = true
kms_key_id = aws_kms_key.example.arn
}
# FAIL: Security group allows all inbound (CKV_AWS_24)
resource "aws_security_group" "bad" {
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"] # Open to world!
}
}
# PASS: Restricted security group
resource "aws_security_group" "good" {
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"] # Internal only
}
}
# Suppress check with justification
resource "aws_s3_bucket" "logs" {
# checkov:skip=CKV_AWS_18:Log bucket requires public read for CloudFront
bucket = "public-logs"
acl = "public-read"
}
Kubernetes Security¶
# FAIL: Container runs as root (CKV_K8S_23)
apiVersion: v1
kind: Pod
metadata:
name: bad-pod
spec:
containers:
- name: nginx
image: nginx
# Missing securityContext
# PASS: Non-root container
apiVersion: v1
kind: Pod
metadata:
name: good-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: nginx
image: nginx
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
Learning Resources¶
Official Resources¶
- Checkov Documentation - Official docs
- GitHub Repository - Source code, policies
- Policy Index - All built-in checks
- Bridgecrew Blog - Tutorials and use cases
Example Use Cases¶
Development Workflow
- Local scanning - Run Checkov before committing code
- PR validation - GitHub Actions scan on every pull request
- Terraform Cloud - Run checks as part of plan workflow
- Security gates - Block merges if critical issues found
Compliance
- CIS benchmarks - Filter checks by CIS framework
- PCI-DSS - Validate payment card compliance
- HIPAA - Healthcare data protection validation
- SOC2 - Service organization controls audit prep
Enterprise Adoption
- Baseline creation - Scan existing infrastructure, create baseline
- Gradual rollout - Start with
--soft-fail, tighten over time - Custom policies - Organization-specific security requirements
- Metrics dashboard - Track security posture improvements
Worth Checking¶
-
Official Docs
-
Integrations
-
Community
-
Learning
Last Updated: 2026-02-02 | Vibe Check: Essential DevSecOps - Checkov is mandatory for modern IaC workflows. Catches security issues before deployment. 1000+ built-in policies. Free and open-source. Integrates seamlessly with CI/CD. If you're writing Terraform, you're running Checkov. Tags: checkov, security, iac, terraform, kubernetes