You wrote Terraform that works. Does it follow security best practices? Checkov has over 1000 built-in policies that check your infrastructure code before you apply it.
Quick Start
pip install checkov
# Scan Terraform
checkov -d ./terraform/
# Results
Passed checks: 42
Failed checks: 8
Skipped checks: 2
Check: CKV_AWS_18: "Ensure S3 bucket has access logging enabled"
FAILED for resource: aws_s3_bucket.data
File: /main.tf:15-25
Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/s3-policies/s3-13
Check: CKV_AWS_145: "Ensure S3 bucket is encrypted with KMS"
FAILED for resource: aws_s3_bucket.data
File: /main.tf:15-25What Checkov Scans
| Framework | File Types | Check Count |
|---|---|---|
| Terraform | .tf, .tfvars | 400+ |
| CloudFormation | .yaml, .json, .template | 300+ |
| Kubernetes | manifests, Helm | 100+ |
| Dockerfile | Dockerfile | 30+ |
| ARM templates | .json | 100+ |
| Serverless | serverless.yml | 20+ |
| GitHub Actions | .github/workflows/*.yml | 30+ |
Master this topic with hands-on labs
Go beyond reading — build real projects in sandboxed environments with expert video guidance.
Browse Courses →Common Terraform Failures
S3 Bucket Security
# ❌ Fails CKV_AWS_18, CKV_AWS_145, CKV_AWS_19
resource "aws_s3_bucket" "data" {
bucket = "my-data-bucket"
}
# ✅ Passes all checks
resource "aws_s3_bucket" "data" {
bucket = "my-data-bucket"
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.bucket.arn
}
}
}
resource "aws_s3_bucket_logging" "data" {
bucket = aws_s3_bucket.data.id
target_bucket = aws_s3_bucket.logs.id
target_prefix = "data-bucket/"
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration {
status = "Enabled"
}
}RDS Security
# ❌ Fails checks
resource "aws_db_instance" "main" {
engine = "postgres"
instance_class = "db.t3.medium"
publicly_accessible = true # CKV_AWS_17
storage_encrypted = false # CKV_AWS_16
}
# ✅ Passes
resource "aws_db_instance" "main" {
engine = "postgres"
instance_class = "db.t3.medium"
publicly_accessible = false
storage_encrypted = true
deletion_protection = true
backup_retention_period = 7
multi_az = true
}Kubernetes Checks
checkov -d ./k8s/
# Check: CKV_K8S_1: "Do not admit privileged containers"
# Check: CKV_K8S_20: "Containers should not run with allowPrivilegeEscalation"
# Check: CKV_K8S_22: "Use read-only filesystem for containers"
# Check: CKV_K8S_28: "Ensure resource limits are set"
# Check: CKV_K8S_40: "Do not allow containers to run as root"Dockerfile Checks
checkov -f Dockerfile
# Check: CKV_DOCKER_2: "Ensure HEALTHCHECK is added"
# Check: CKV_DOCKER_3: "Ensure USER is not root"
# Check: CKV_DOCKER_7: "Ensure base image uses a specific tag"Get weekly IT automation tips
Docker, Ansible, Terraform, MLOps — curated insights delivered to your inbox. No spam.
Subscribe Free →CI/CD Integration
GitHub Actions
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov scan
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
soft_fail: false
output_format: sarif
output_file_path: results.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifCustom Checks
# custom_checks/s3_naming.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class S3NamingConvention(BaseResourceCheck):
def __init__(self):
name = "Ensure S3 bucket follows naming convention"
id = "CKV_CUSTOM_1"
supported_resources = ["aws_s3_bucket"]
categories = [CheckCategories.CONVENTION]
super().__init__(name=name, id=id,
categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
bucket = conf.get("bucket", [""])[0]
if bucket.startswith(("dev-", "staging-", "prod-")):
return CheckResult.PASSED
return CheckResult.FAILED
check = S3NamingConvention()checkov -d ./terraform/ --external-checks-dir ./custom_checks/Skip Checks
# Inline skip
resource "aws_s3_bucket" "public_assets" {
#checkov:skip=CKV_AWS_18:Access logging not needed for public CDN assets
bucket = "public-assets"
}# CLI skip
checkov -d ./terraform/ --skip-check CKV_AWS_18,CKV_AWS_19Always document why you skip a check.
---
Ready to go deeper? Master infrastructure security with hands-on courses at CopyPasteLearn.
Ready to learn by doing?
Stop reading tutorials — start building. Expert video courses with hands-on labs in real sandboxed environments.
Related Articles
Tofu vs Terraform Comparison
OpenTofu forked Terraform after the BSL license change. Compare features, compatibility, licensing, and ecosystem to decide which IaC tool fits your team.
Ansible vs Terraform When to Use
Ansible and Terraform solve different infrastructure problems. Learn when to use each, when to use both together, and how they complement each other.
GitHub Actions CI/CD for Terraform
Automate Terraform with GitHub Actions. Plan on PR, apply on merge, remote state locking, and secure secrets for IaC pipelines.
CI/CD for ML on Kubernetes
Build a CI/CD pipeline for ML models using GitHub Actions, MLflow, Docker, and Kubernetes. Automate the path from training to production.
CI/CD Pipeline Tutorial from Scratch
Build a complete CI/CD pipeline from scratch with GitHub Actions. Lint, test, build, and deploy your application — fully automated on every push to your.
Cilium Service Mesh Kubernetes
Cilium replaces kube-proxy and sidecar service meshes with eBPF. Learn how Cilium handles networking, observability, and security in Kubernetes.
Explore topics
Browse more articles on the topics covered here.