Cheat sheet — IaC Security Scanning¶
Companion to Module 06 — Infrastructure-as-Code Security · CC BY 4.0 — print it, pin it, share it.
Last reviewed: 2026-07
Checkov — scan Terraform/HCL¶
checkov -d . # scan a whole directory (recurse the tree)
checkov -f main.tf # scan a single file
checkov -d . --framework terraform # limit to one IaC framework (also: cloudformation, kubernetes, helm)
checkov -d . --compact # trim the per-check code blocks from output
checkov -d . -o cli -o sarif # multiple outputs at once (sarif for PR annotations)
checkov -d . --output-file-path results/ # write outputs to files instead of stdout
checkov -d . --check CKV_AWS_18 # run ONLY this check (S3 access logging)
checkov -d . --skip-check CKV_AWS_20 # run everything EXCEPT this check
Checkov — the CI gate (exit codes are the whole game)¶
checkov -d . # exit 1 if any check FAILS, 0 if all pass — this is your gate
checkov -d . --soft-fail # always exit 0 (report only, never block) — for onboarding a repo
checkov -d . --hard-fail-on HIGH,CRITICAL # block only on these severities; softer ones report but pass
checkov -d . --soft-fail-on CKV_AWS_18 # let this one specific check report without failing the build
# .github/workflows — the canonical Action (bridgecrewio/checkov-action)
- uses: bridgecrewio/checkov-action@v12
with:
directory: .
framework: terraform
soft_fail_on: CKV_AWS_18 # report, don't block, on this check
output_format: sarif
Suppression — an audit trail, not a mute button¶
resource "aws_security_group" "lb" {
# checkov:skip=CKV_AWS_260: public HTTPS is intended — this SG fronts the public ALB
ingress {
from_port = 443
to_port = 443
cidr_blocks = ["0.0.0.0/0"]
}
}
- Inline, per-resource, with a check-ID + a real reason — you over-ruling the junior, on the record.
- Never
--skip-checka rule across the whole codebase to clear noise; that silences the real exposure too.
tfsec — Terraform-native scanner¶
tfsec . # scan the current directory
tfsec . --format sarif # SARIF for PR annotations (also: json, junit, csv)
tfsec . --minimum-severity HIGH # only surface HIGH/CRITICAL
tfsec . --exclude aws-vpc-no-public-ingress-sgr # skip a specific check by its slug
Trivy — one scanner for config AND images¶
trivy config . # scan Terraform / CloudFormation / Helm / K8s manifests
trivy config --severity HIGH,CRITICAL . # filter by severity
trivy config --format sarif -o tf.sarif . # SARIF output
trivy fs . # filesystem scan: config + vuln + secrets in one pass
trivy fs --scanners misconfig,secret . # pick which scanners run
trivy configis the same engine you use for images in Module 10 — one tool across IaC and containers.
Map a finding back to a standard¶
# checkov finding → CIS control (traceability is what makes it a finding, not a lint nit)
# CKV_AWS_18 → S3 access logging CKV_AWS_21 → S3 versioning
# CKV_AWS_20 → S3 public-read block CKV_AWS_24 → SG ingress 0.0.0.0/0 on :22
# CKV_AWS_260 → SG ingress 0.0.0.0/0 on any port
Gotchas worth remembering¶
- The scan is not the deliverable — the gate is. Fixing a finding by hand regresses the next time someone copies the module. Wire the scan into CI so the bad config cannot merge; that exit code is the whole point.
- A scanner is a junior reviewer with no context. It flags two identical
0.0.0.0/0findings and can't tell you the:443one is your intended public ALB while the:5432one is a database you just exposed. The known-bad pattern is its job; the bad decision is yours. - Scanners miss secrets in HCL. A
password = "changeme"literal inrds.tfis agitleaks/trufflehogjob (Module 07), not a Checkov job — don't assume a clean config scan means no secrets. - A wildcard "fix" is often still broken. Moving
*fromActiontoResourcepasses the pattern check but still composes into privilege escalation. Confirm the gate fails the original for the right reason and passes only the genuinely-fixed config. - IaC has a supply chain too. A vulnerable Terraform provider/module poisons every config that uses it (e.g. CVE-2025-13357, HashiCorp Vault provider). Pin provider/module versions and scan what you pull.
Comments
Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).