| name | checkov |
| description | Scan Infrastructure as Code for security misconfigurations with Checkov — a static analysis tool that checks Terraform, CloudFormation, Kubernetes, Helm, ARM, Bicep, Serverless, and Dockerfile for security issues before deployment. Use this skill whenever the user wants to audit IaC for security issues, add security scanning to Terraform pipelines, or check Kubernetes manifests against security best practices. Trigger for "checkov scan", "iac security", "terraform security scan", "checkov terraform", or "checkov kubernetes". |
| SAFETY NOTE | Checkov is a purely defensive static analysis tool for scanning your own IaC configurations. |
Checkov: Infrastructure as Code Security Scanner
Checkov is an open-source static analysis tool for Infrastructure as Code (IaC). It finds security misconfigurations in Terraform, CloudFormation, Kubernetes, Helm, ARM, Bicep, Serverless, and Dockerfiles — before they reach production.
Installation
pip install checkov
pipx install checkov
docker pull bridgecrew/checkov
Basic Usage
checkov -d ./terraform/
checkov -f main.tf
checkov -d ./k8s/ --framework kubernetes
checkov -f Dockerfile --framework dockerfile
checkov -f template.yaml --framework cloudformation
checkov -d ./terraform/ -o json
checkov -d ./terraform/ -o sarif --output-file-path checkov-results.sarif
checkov -d ./terraform/ -o table
Terraform Scanning
terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
checkov -f plan.json --framework terraform_plan
checkov -d ./terraform/ --framework terraform
checkov -d ./terraform/ --skip-check CKV_AWS_20,CKV_AWS_57
checkov -d ./terraform/ --check CKV_AWS_3,CKV_AWS_21
checkov -d ./terraform/ --check-threshold HIGH
Common Terraform Issues Checkov Catches
S3 Buckets
# BAD — Checkov CKV_AWS_20: S3 bucket should not be publicly readable
resource "aws_s3_bucket" "data" {
bucket = "my-data-bucket"
acl = "public-read" # CKV_AWS_20: FAIL
}
# GOOD
resource "aws_s3_bucket" "data" {
bucket = "my-data-bucket"
}
resource "aws_s3_bucket_acl" "data" {
bucket = aws_s3_bucket.data.id
acl = "private"
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration { status = "Enabled" } # CKV_AWS_21
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
apply_server_side_encryption_by_default { sse_algorithm = "AES256" } # CKV_AWS_19
}
}
Security Groups
# BAD — CKV_AWS_25: Open to world
resource "aws_security_group_rule" "ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # CKV_AWS_25: FAIL
}
# GOOD — restrict to known CIDR
resource "aws_security_group_rule" "ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"] # VPC CIDR only
}
IAM Policies
# BAD — CKV_AWS_40: IAM policy with wildcard permissions
resource "aws_iam_policy" "bad" {
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "*" # CKV_AWS_40: FAIL
Resource = "*"
}]
})
}
# GOOD — least privilege
resource "aws_iam_policy" "good" {
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject"]
Resource = "arn:aws:s3:::my-bucket/*"
}]
})
}
Kubernetes Manifest Scanning
checkov -d ./k8s/ --framework kubernetes
checkov -d ./helm/my-chart/ --framework helm
Common Kubernetes issues:
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: my-app:latest
spec:
containers:
- name: app
image: my-app:1.2.3
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop: ["ALL"]
Dockerfile Scanning
# BAD — CKV_DOCKER_2: no HEALTHCHECK
FROM ubuntu:latest # CKV_DOCKER_7: use specific tag
RUN apt-get install -y curl # OK
# GOOD
FROM ubuntu:22.04
HEALTHCHECK --interval=30s --timeout=5s \ # CKV_DOCKER_2
CMD curl -f http://localhost:8080/health || exit 1
# CKV_DOCKER_3: Avoid running as root
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
USER appuser
# CKV_DOCKER_4: Don't add secrets as environment variables
# ENV SECRET_KEY=hardcoded_value # FAIL
COPY --chown=appuser:appgroup . /app
WORKDIR /app
CI/CD Integration
GitHub Actions
name: IaC Security Scan
on: [push, pull_request]
jobs:
checkov:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Run Checkov on Terraform
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
output_format: sarif
output_file_path: checkov-results.sarif
soft_fail: false
check: "HIGH,CRITICAL"
- name: Upload to GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
Pre-commit Hook
repos:
- repo: https://github.com/bridgecrewio/checkov
rev: '3.2.0'
hooks:
- id: checkov
args: ['--framework', 'terraform', '--quiet']
Custom Checks (Python)
from checkov.common.models.enums import CheckCategories, CheckResult
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
class EnsureRequiredTags(BaseResourceCheck):
def __init__(self):
name = "Ensure all resources have required tags"
id = "CKV_CUSTOM_1"
supported_resources = ['aws_instance', 'aws_s3_bucket', 'aws_rds_instance']
categories = [CheckCategories.GENERAL_SECURITY]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
required_tags = {"Owner", "Environment", "Project"}
tags = conf.get("tags", [{}])
if isinstance(tags, list):
tags = tags[0]
if isinstance(tags, dict):
present = set(tags.keys())
if required_tags.issubset(present):
return CheckResult.PASSED
return CheckResult.FAILED
scanner = EnsureRequiredTags()
checkov -d ./terraform/ --external-checks-dir ./custom_checks/
Output and Reporting
checkov -d ./terraform/ -o json | jq '.results.failed_checks[] | {id: .check_id, resource: .resource, file: .repo_file_path}'
checkov -d ./terraform/ -o json | jq '.summary'
checkov -d ./terraform/ -o junitxml > checkov-junit.xml
checkov -d ./terraform/ --compact
Suppressing False Positives
# Suppress in Terraform with comment
resource "aws_s3_bucket" "logs" {
bucket = "my-access-logs"
#checkov:skip=CKV_AWS_19:Access logs don't need encryption
#checkov:skip=CKV_AWS_21:Versioning not needed for transient logs
}
GitNexus Index
This skill is indexed by GitNexus for knowledge graph traversal.
Index path: /Users/localuser/.claude/skills/checkov/.gitnexus
Last indexed: 2026-05-24