Policy-as-code for Terraform: tfsec and OPA in review
Catch public buckets and open security groups in the plan, not in prod. Policies live next to the modules they guard.
A public S3 bucket or an SSH port open to 0.0.0.0/0 is a one-line diff. The cheapest place to catch it is the merge request — not the AWS console at 2am. Two tools cover it: tfsec for the common cloud-misconfig defaults, and OPA for the rules that are specific to your org.
tfsec runs on the raw HCL and needs zero setup — point it at the directory and it flags the usual suspects:
tfsec .scanning 14 files ... Result 1 CRITICAL S3 bucket has a public ACL main.tf:23 resource "aws_s3_bucket" "assets" aws-s3-no-public-access-with-acl Result 2 HIGH Security group rule allows 0.0.0.0/0 on port 22 network.tf:8 resource "aws_security_group" "web" 2 potential problems detected — exit 1tfsec in the pipeline
Drop tfsec into a test job and emit JUnit so findings show up inline on the merge request. Fail the pipeline on its exit code — a warning nobody sees is not a control.
policy_scan:stage: testimage: aquasec/tfsec:latestscript:- tfsec . --format junit > tfsec.xmlartifacts:reports:junit: tfsec.xml
OPA for your own rules
Built-in scanners don't know that your buckets must block public access or that every resource needs a cost-center tag. Write those as Rego and evaluate them against the plan JSON — that way you catch computed values, not just what's literally in the HCL.
package main# every bucket must have public access fully blockeddeny[msg] {r := input.resource_changes[_]r.type == "aws_s3_bucket_public_access_block"not r.change.after.block_public_aclsmsg := sprintf("%s: public ACLs are not blocked", [r.address])}
terraform plan -out=tf.planterraform show -json tf.plan > plan.jsonconftest test plan.json # exits non-zero on any deny
Where this goes next
Keep the policies in the repo next to the modules they guard, and version them together. When you're ready to enforce at runtime as well as review, the same Rego runs in OPA Gatekeeper as a Kubernetes admission controller — one policy language from plan to cluster.
Go deeper in a courseOPA & RegoRego, Conftest and Gatekeeper — policy-as-code in depth.View course