Policy for IaC
Policy for IaC
Infrastructure as Code gave teams repeatability and velocity — but it also means a single misconfigured Terraform module can stamp the same security hole across every environment in minutes. Gating policy at the IaC layer, before a terraform apply ever runs, is the highest-leverage control point in a cloud-native compliance program. This lesson covers the three dominant tools that enforce that gate: Checkov, tfsec, and HashiCorp Sentinel.
Why Gate at the Plan Stage?
The cost of a misconfiguration grows with how late you catch it. Catching an open S3 bucket in a static scan of a .tf file costs nothing. Catching it after terraform apply in production means incident response, potential data exposure, and audit findings. The goal is to fail fast in the PR pipeline so engineers fix issues while context is fresh and before any cloud API is called.
There are three natural enforcement points:
- Pre-commit hooks — catch obvious mistakes on the engineer's laptop before the code ever reaches version control.
- CI PR gate — run a full scan on every pull request; block merge if high-severity policies fail.
- Terraform plan check — parse the actual plan JSON (not just source files) for runtime-evaluated expressions that static analysis cannot see.
Production-grade pipelines use all three layers; the CI gate is the non-negotiable one because it is the last automated check before code reaches the main branch.
Checkov — Open-Source Static Analysis
Checkov, maintained by Bridgecrew (now Prisma Cloud), scans Terraform HCL, CloudFormation, Kubernetes manifests, ARM templates, and Dockerfiles. It ships with over 1,000 built-in checks mapped to CIS benchmarks, SOC 2, PCI DSS, HIPAA, and NIST 800-53. It is the most common open-source choice because it is free, regularly updated, and integrates cleanly into GitHub Actions and GitLab CI.
The most useful flags in a CI context: --soft-fail exits 0 even on failures (useful for reporting phases); --check CKV_AWS_18,CKV_AWS_20 runs only specific check IDs; --skip-check CKV_AWS_144 skips a check with a justification comment in your .checkov.yaml. Always suppress via config file, never via --skip-check inline in CI commands — config-file suppressions are reviewable and auditable.
var.enable_logging ? true : false are not always resolvable from HCL alone. The plan JSON contains the evaluated values, so plan-file scanning catches conditional misconfigurations that source-file scanning misses.
tfsec — Fast, Purpose-Built Terraform Scanner
tfsec (now merged into Trivy as trivy config) is purpose-built for Terraform. It is written in Go, extremely fast, and understands module references across directories — a significant advantage when your repo has a module hierarchy. Its output links directly to remediation guidance and the relevant CIS benchmark control.
Using SARIF output is a best practice in enterprise pipelines because GitHub and GitLab can render inline code annotations directly in the PR, so engineers see exactly which line triggered which finding without leaving the review interface.
HashiCorp Sentinel — Policy as Code for the Terraform Ecosystem
Sentinel is HashiCorp's commercial policy framework, available in Terraform Cloud and Terraform Enterprise. Unlike Checkov and tfsec (which run externally), Sentinel runs inside the Terraform run workflow, with direct access to the plan, the run metadata, and the workspace configuration. This makes it the authoritative enforcement point when your organization uses Terraform Cloud as the apply engine.
Sentinel policies are written in the Sentinel language (similar to Go) and can be set to three enforcement levels: advisory (warn only), soft-mandatory (can be overridden with justification), and hard-mandatory (absolutely blocks apply, no override). Use hard-mandatory for regulatory controls (encryption, public access blocks) and soft-mandatory for organizational standards where legitimate exceptions exist.
terraform plan locally or in a non-TFC CI bypass it entirely. Always pair Sentinel with Checkov/Trivy in the PR pipeline — Sentinel is the final hard stop; Checkov is the early feedback loop.
GitHub Actions Integration Pattern
A production-grade CI job runs the scans in parallel, uploads SARIF results to the Security tab, and fails the pipeline if any CRITICAL or HIGH findings exist in policy-controlled categories. Informational and low-severity findings are reported but non-blocking.
Managing Suppressions Without Creating Compliance Debt
Every scan will surface findings that are genuinely acceptable for your environment — a public S3 bucket that hosts a static website, for instance. Suppress these via a .checkov.yaml config file committed to the repo, not inline CLI flags. Each suppression must include the check ID, the resource it applies to, and a comment explaining the business justification. Suppressions without justification comments fail the code review process and, more importantly, fail auditor review.
date field to every suppression entry and run a quarterly job that alerts on suppressions older than 90 days. Suppressions are technical debt — they should be time-bounded and reviewed, not accumulated indefinitely. Many organizations have failed audits not because they had suppressions, but because they had suppressions nobody remembered authorizing.
Combining Checkov source scans, plan-file scans, Trivy for module-aware analysis, and Sentinel as the hard gate in Terraform Cloud creates a defense-in-depth policy enforcement architecture. Each layer catches different classes of misconfiguration, and together they give you the documented, automated evidence trail that SOC 2 and PCI DSS auditors require.