how to scan Terraform for misconfigurations with checkov
A step-by-step skill for scanning Terraform with Checkov: install, run directory scans, read failing check IDs, fix the resource blocks, and gate CI. Use when an engineer or agent needs to catch IaC misconfigurations (public S3 buckets, unencrypted disks) before apply. Triggers: scan Terraform with checkov, checkov misconfigurations, IaC security scan. Not for: runtime vuln scanning, Terraform syntax errors, CloudFormation-only setups.
how to scan Terraform for misconfigurations with checkov
TL;DR
Install Checkov with pip, run checkov -d . in your Terraform root, and it checks your HCL against 1000+ built-in policies for things like public S3 buckets and unencrypted EBS volumes. Wire it into CI with a hard fail so bad config never reaches apply. Fix the flagged resource blocks instead of blanket-skipping checks, and keep a short list of documented skips for accepted risks.
The query
how to scan Terraform for misconfigurations with checkovUse this when
- you want to catch Terraform security misconfigurations before apply
- someone asks to "run checkov" or "scan my terraform for security issues"
- you are adding IaC scanning to a CI pipeline
- you need to map a failing CKV check ID to the actual fix
Not for this skill when
- you are scanning container images or application source code (different scanners)
- Terraform itself wont parse (fix the HCL syntax first)
- your IaC is CloudFormation or Pulumi only (see the variants below)
- you want runtime monitoring of already-deployed infrastructure
Steps
- Install Checkov with pip: run
pip install checkovthencheckov --version.
Expected output: a version string like 3.2.x, confirming the CLI works.
- Scan the Terraform directory: run
checkov -d .from the repo root.
Expected output: a summary of passed, failed, and skipped checks, plus a table of each failure with check ID, file, and line number.
- Read one failure end to end: note the check ID (for example CKVAWS19, S3 bucket encryption) and open the file and line it names.
Expected output: you can point at the exact resource block that violates the policy.
- Fix the resource block: add the missing setting, for example a
server_side_encryption_configurationblock on the S3 bucket, then rerun the scan.
Expected output: the check moves from Failed to Passed on the rerun.
- Gate CI: add a pipeline step running
checkov -d . --hard-fail-on CKV_AWS_19for your must-pass checks (or--soft-failwhile rolling out).
Expected output: the pipeline step fails when a listed check fails, blocking the merge.
- Skip deliberately: add a comment like
#checkov:skip=CKV_AWS_21with a written reason above the resource when a finding is a false positive or accepted risk.
Expected output: the check appears under Skipped with your reason visible in the report.
Variant: scan the plan instead of the HCL
Run terraform plan -out planfile, convert it with terraform show -json planfile, and save that JSON to plan.json. Then run checkov -f plan.json. This scans exactly what apply would create, which catches values that only resolve at plan time.
Variant: checkov on CloudFormation
Point checkov at the template file: checkov -f template.yaml. The check IDs are still CKV_AWS style, so the fix workflow is the same.
Variant: run only the checks you care about
checkov -d . --check CKV_AWS_19,CKV_AWS_21 runs just those two. Handy when a PR touches S3 and you want a focused answer.
Why this happens
Terraform applies whatever you declare, and the provider defaults lean permissive: buckets without encryption, disks without encryption, security groups you forgot to tighten. Checkov encodes CIS benchmarks and cloud best practices as policy checks over the HCL graph, so the review happens before the resource exists.
Edge cases and pitfalls
- Checkov reads config files, not live state. Drift in the real account will not show up here.
- Remote modules get scanned too. Pin module versions so results do not change under you.
- A skip without a reason comment is tech debt. Make the justification mandatory in review.
- If the built-ins miss an org-specific rule, drop custom policies in a directory and pass
--external-checks-dirwith its path.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_Dqf95gky-8KuYNm3NffGPw
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.