Testing the Intent, Not Just the Syntax
Static analysis checks how you wrote the code. Plan analysis checks what the code will do. These are fundamentally different questions.
When you run terraform plan, Terraform contacts your cloud provider, compares the desired state (your code) against the current state (what's actually deployed), and produces a detailed diff — a list of resources to create, update, or destroy. This plan is a precise description of the future state of your infrastructure. It's also machine-readable.
Open Policy Agent (OPA) is a general-purpose policy engine. You write policies in a language called Rego, and OPA evaluates data against those policies to produce a pass/fail decision. By converting the terraform plan output to JSON and feeding it to OPA, you can write policies that answer questions like:
- "Will any S3 bucket be created without server-side encryption enabled?"
- "Will any security group allow inbound traffic from
0.0.0.0/0on port 22?" - "Will any IAM role be granted
AdministratorAccess?"
The workflow in practice has three steps: generate the plan as a binary file, convert that binary plan to JSON, then evaluate the OPA policies against that JSON and check whether the deny rules returned any results. If they did, the policy check fails and the pipeline stops before terraform apply is ever called.
The power of this approach is that it enforces compliance before any real infrastructure is created. A developer can't accidentally make a database public because the CI pipeline will reject the plan before it's applied. This is fundamentally different from scanning resources after they're deployed (reactive) — plan analysis is proactive.
Key point: OPA policies are code too, and they should be version-controlled, reviewed, and tested just like your Terraform modules. A policy that's too strict will block legitimate changes; one that's too loose will miss real violations. Treat policy authoring with the same care as application code.