Checkov: Scan Terraform for Misconfigurations

Khimananda Oli 7 min read Database
Checkov: Scan Terraform for Misconfigurations

By Khimananda Oli | Last reviewed: August 2026

Deploying Infrastructure as Code without automated validation is a liability, not an asset. Using Checkov: Scan Terraform for Misconfigurations allows you to catch security gaps, compliance violations, and architectural flaws before they ever reach your cloud provider. This static analysis tool integrates directly into your workflow to enforce best practices consistently across AWS, Azure, GCP, and Kubernetes environments. If you are already managing state with Terraform state management and remote backends, adding policy scanning is the necessary next step to secure that infrastructure lifecycle.

Terraform HCLSource CodeCheckov EngineStatic AnalysisPolicy EvaluationGraph TraversalPassed ChecksCompliant ConfigFailed ChecksSecurity Risks
Checkov parses Terraform code statically to identify misconfigurations before provisioning occurs

How do you install and run Checkov to scan Terraform for misconfigurations?

Getting started requires minimal setup. Checkov is distributed via pip, Homebrew, and Docker, making it accessible regardless of your local environment. For most DevOps workflows in 2026, I recommend using the containerized version to avoid Python dependency conflicts on developer machines, though pip remains the fastest path for quick ad-hoc checks.

Installation methods

  • Pip (Python 3.8+): pip install checkov — simplest for local development.
  • Homebrew (macOS/Linux): brew install checkov — keeps the binary isolated from system Python.
  • Docker: docker pull bridgecrew/checkov — preferred for CI runners and reproducible environments.

Running your first scan

Navigate to your Terraform root module directory and execute the baseline scan. The default output is human-readable CLI text, which is excellent for debugging but insufficient for automation.

# Basic scan of current directory
checkov -d .

# Scan specific file with JSON output for parsing
checkov -f main.tf -o json

# Scan with compact output (one line per check)
checkov -d . -o cli --compact

A common mistake is scanning only individual files (-f) instead of directories (-d). Checkov builds a resource graph to understand relationships between modules, variables, and data sources. Scanning a single file in isolation often produces false positives because the tool cannot resolve variable values or module outputs defined elsewhere. Always prefer directory-level scans for accurate results.

Understanding the output structure

Each check result includes a unique ID (e.g., CKV_AWS_18), severity level, resource address, and remediation guidance. Passed checks confirm compliance; failed checks indicate actionable risks. Skipped checks appear when you have explicitly suppressed a policy. In my experience auditing SOC 2 environments, the "skipped" category deserves as much attention as failures — unjustified suppressions are often where real vulnerabilities hide.

How do you integrate Checkov into CI/CD pipelines to block insecure deployments?

Local scanning catches issues during development, but pipeline enforcement prevents drift. Integrating Checkov: Scan Terraform for Misconfigurations into your CI/CD system creates a mandatory quality gate. This aligns with the principles discussed in DevSecOps shift left strategies, ensuring security feedback arrives while changes are still cheap to fix.

Git PushPR / MergeLint & Validatefmt / validatetflintCheckov ScanPolicy CheckFail = BlockPass = ContinuePlan & ApplyDeploy InfraPipeline FailsNotify Dev
Checkov acts as a blocking gate in CI/CD between validation and deployment stages

GitHub Actions configuration

The official Bridgecrew action simplifies integration. Place this step after terraform fmt and terraform validate but before terraform plan. This ordering ensures you fail fast on syntax errors before spending time on expensive security scans.

- name: Run Checkov security scan
  uses: bridgecrewio/checkov-action@v12
  with:
    directory: ./infrastructure
    output_format: sarif
    output_file_path: reports/checkov-results.sarif
    skip_check: CKV_GIT_4
    quiet: true

- name: Upload SARIF to GitHub Security Tab
  uses: github/codeql-action/upload-sarif@v3
  if: always()
  with:
    sarif_file: reports/checkov-results.sarif

Using SARIF output uploads findings directly to the GitHub Security tab, giving developers inline annotations on pull requests rather than forcing them to dig through CI logs. This dramatically reduces friction and increases adoption rates among teams new to policy as code practices.

Handling soft fails and baselines

Legacy codebases often contain hundreds of pre-existing violations. Blocking all of them immediately halts development. Use the --baseline flag to create a snapshot of current failures, then configure the pipeline to only fail on new violations introduced by the PR. This ratchet approach maintains momentum while preventing regression.

# Generate baseline from current state
checkov -d . -o json > checkov-baseline.json

# Run scan comparing against baseline
checkov -d . --baseline checkov-baseline.json

How do you write custom Checkov policies for organization-specific requirements?

Built-in policies cover general cloud security, but every organization has unique constraints. You might require specific tagging schemas for cost allocation, restrict regions to Nepal or Singapore for data residency, or enforce naming conventions that encode team ownership. Custom policies bridge this gap using Python or YAML.

YAML-based custom policies (no-code)

For simple attribute checks, YAML policies are faster to write and easier to review. They live in a dedicated directory and are loaded via the --external-checks-dir flag.

metadata:
  name: "Ensure all S3 buckets have project tag"
  id: "CUSTOM_AWS_S3_PROJECT_TAG"
  category: "CONVENTION"
  severity: "MEDIUM"

scope:
  provider: aws

definition:
  and:
    - cond_type: "attribute"
      resource_types:
        - "aws_s3_bucket"
      attribute: "tags.project"
      operator: "exists"

Python-based custom policies (complex logic)

When validation requires conditional logic, API lookups, or cross-resource correlation, Python is necessary. Inherit from BaseResourceCheck and implement scan_resource_conf. Return CheckResult.PASSED, FAILED, or UNKNOWN.

from checkov.common.models.enums import CheckResult
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck

class EC2InstanceTypeRestriction(BaseResourceCheck):
    def __init__(self):
        super().__init__(
            name="Ensure EC2 uses approved instance families",
            id="CUSTOM_AWS_EC2_INSTANCE_TYPE",
            categories=["CONVENTION"],
            supported_resources=["aws_instance"]
        )

    def scan_resource_conf(self, conf):
        instance_type = conf.get("instance_type", [None])[0]
        approved_prefixes = ("t3.", "m6i.", "c6g.")
        if instance_type and any(instance_type.startswith(p) for p in approved_prefixes):
            return CheckResult.PASSED
        return CheckResult.FAILED

Store custom policies in a shared repository and reference them across all infrastructure repos. This centralizes governance and ensures consistent enforcement whether a team is building in Kathmandu or San Francisco.

How does Checkov compare to tfsec, Terrascan, and OPA for Terraform security?

Choosing the right scanner depends on your team's maturity, compliance needs, and existing toolchain. While Checkov: Scan Terraform for Misconfigurations is my default recommendation for most teams due to its breadth and CI ergonomics, alternatives excel in specific niches.

FeatureCheckovtfsecTerrascanOPA / Conftest
LanguagePython / YAMLGo / RegoRegoRego only
Built-in Policies1,500+200+600+0 (user-defined)
Multi-frameworkTF, K8s, Docker, ARM, Bicep, CloudFormationTF onlyTF, K8s, Helm, DockerAny structured data
Custom Policy EaseHigh (YAML option)Medium (Rego)Medium (Rego)Steep (Rego only)
SARIF OutputNativeNativeVia pluginVia conftest
Best ForGeneral DevSecOps, multi-cloudPure TF teams wanting speedCompliance-heavy auditsPlatform engineers, bespoke policy
CheckovBreadth: ★★★★★Ease: ★★★★☆Speed: ★★★☆☆Multi-frameworkYAML + PythonSARIF nativetfsecBreadth: ★★★☆☆Ease: ★★★★☆Speed: ★★★★★Terraform onlyGo binaryFastest scansTerrascanBreadth: ★★★★☆Ease: ★★★☆☆Speed: ★★★☆☆Compliance focusRego policiesAudit reportingOPABreadth: ★★★★★Ease: ★★☆☆☆Speed: ★★★★☆Universal engineRego onlyMax flexibility
Trade-offs between Checkov, tfsec, Terrascan, and OPA for Terraform security scanning

In practice, many mature teams run both Checkov and tfsec. tfsec’s Go implementation scans large codebases significantly faster, providing rapid feedback on PRs, while Checkov runs nightly for comprehensive compliance coverage including Kubernetes manifests and Dockerfiles that tfsec ignores. OPA remains the choice for platform teams building internal developer platforms where policy must span admission control, CI gates, and runtime enforcement with a single language.

Make Checkov Part of Your Infrastructure Safety Net

Static analysis alone does not guarantee security, but deploying without it guarantees preventable incidents. Start by integrating Checkov: Scan Terraform for Misconfigurations into your primary CI pipeline with a baseline to avoid blocking existing work. Gradually add custom policies as your organizational standards solidify, and pair scanning with runtime monitoring like Prometheus and Grafana to catch what static analysis cannot. If your team needs help designing a compliant IaC workflow or tuning policies to reduce noise without sacrificing safety, reach out to discuss your infrastructure security strategy.

Frequently Asked Questions

Install via pip using python3 -m pip install checkov or use the official Docker image bridgecrew/checkov. Both methods provide the latest stable release with updated policies for current Terraform providers and cloud APIs without requiring additional dependencies.

Run checkov -d /path/to/terraform to recursively scan all HCL files in that directory. Add --output cli for terminal results or --output junitxml for CI integration. The tool automatically detects Terraform modules and variable definitions during execution.

No, Checkov is completely free and open source under Apache 2.0 license. All built-in policies, CLI tools, and CI integrations are available at no cost. Enterprise features like custom policy packs require Bridgecrew platform subscription but core scanning remains free.

Checkov offers broader multi-framework support beyond Terraform including Kubernetes and CloudFormation. Tfsec provides faster single-language scans with deeper HCL parsing. Many teams run both tools in parallel since Checkov catches configuration drift while tfsec excels at code-level security patterns.

Yes, generate a JSON plan file using terraform plan -out=tfplan && terraform show -json tfplan > plan.json then run checkov -f plan.json. This evaluates resolved values after variable interpolation providing more accurate results than static HCL analysis alone.

Add inline comments like #checkov:skip=CKV_AWS_18:reason directly above the resource block. For module-wide skips use --skip-check CKV_AWS_18 flag. Document every skip with justification to maintain audit trails and prevent accidental security gaps during future refactoring cycles.

Top findings include unencrypted S3 buckets, publicly accessible security groups, missing logging on cloud resources, overly permissive IAM policies, and disabled versioning. These represent high-severity issues that frequently appear in production environments and violate CIS benchmarks across AWS Azure and GCP.

Create Python classes extending BaseResourceCheck or YAML files defining rego rules. Place them in a dedicated directory and pass --external-checks-dir ./custom-policies during execution. Custom policies integrate seamlessly with built-in checks and appear in standard output formats for unified reporting.

Yes, use bridgecrewio/checkov-action in workflow files. Configure it to scan changed directories only using --directory flag with PR diff paths. Set fail-on-high-severity to block merges when critical misconfigurations are detected ensuring security gates enforce compliance before code reaches main branch.

Static analysis cannot fully resolve complex dynamic blocks or for_each iterations. Use plan-based scanning with terraform show -json to evaluate rendered configurations. Alternatively suppress specific checks with documented inline comments when you verify the generated infrastructure meets security requirements despite static analysis limitations.

Update monthly or before major infrastructure changes using pip install --upgrade checkov. New cloud services and provider versions introduce fresh attack surfaces requiring updated policy coverage. Automate updates in CI pipelines to ensure consistent detection capabilities across development staging and production environments throughout 2026.

Yes, Checkov downloads and scans referenced modules from Terraform Registry Git repositories and local paths. Use --download-external-modules true flag to enable automatic fetching. Scanned modules inherit parent configuration context allowing accurate evaluation of variable defaults and nested resource security postures across reusable components.

Supported formats include CLI table JSON JUnit XML SARIF CSV and CycloneDX SBOM. Use --output sarif for GitHub Security tab integration or --output cyclonedx for supply chain documentation. Multiple outputs can be generated simultaneously by repeating the flag enabling diverse downstream consumption without rescanning.

Use --check HIGH,MEDIUM flag to include only specified severities or --skip-check LOW to exclude noise. Severity mappings follow NIST and CIS frameworks. Combine with --compact flag to reduce output verbosity focusing review efforts on actionable findings that require immediate remediation attention.

No, Checkov analyzes configuration not runtime state. Use terraform plan with detailed output or dedicated drift detection tools like Spacelift or env0 for state comparison. Checkov complements these by preventing misconfigurations before apply rather than identifying divergence after deployment has already occurred in live environments.