intermediate 45 min read getting-started Updated: 2025-06-28

OPA & Terraform: The Definitive Guide to Policy-as-Code Guardrails (2025 Edition)

Master the integration of Open Policy Agent (OPA) with Terraform to enforce security, compliance, and operational best practices on your infrastructure as code.

πŸ“‹ Prerequisites

  • Basic to intermediate knowledge of Terraform (plan, apply, providers).
  • Familiarity with command-line tools and JSON data structures.
  • Docker installed for running OPA easily.
  • A code editor like VS Code with a Rego extension is recommended.

🏷️ Topics Covered

opa terraform integration tutorialterraform policy validation with opaterraform opa conftest examplesinfrastructure as code policy guardrailsterraform security scanning with opaopa terraform best practices

Why Use OPA with Terraform?

Terraform has revolutionized infrastructure management, allowing us to define entire datacenters in code. However, this power brings a new challenge: how do you ensure that the thousands of lines of IaC written by dozens of teams adhere to your organization's security, compliance, and cost-management rules?

You could rely on manual pull request reviews, but this is slow, error-prone, and doesn't scale. This is where Open Policy Agent (OPA) comes in. OPA is a general-purpose, open-source policy engine that decouples policy decision-making from your software. When combined with Terraform, it provides a powerful framework for creating automated, code-based guardrails for your infrastructure.

Terraform

Defines the desired state of your infrastructure. It answers the question, "What do we want to build?"

Open Policy Agent (OPA)

Evaluates that desired state against a set of policies. It answers the question, "Is what we want to build allowed?"

The Core Workflow: Validating a Terraform Plan

The modern way to use OPA with Terraform leverages OPA's native built-in functions to parse Terraform plan files directly. This simplifies the entire process into two main steps.

1

Generate a Terraform Plan File

The standard terraform plan command creates a binary plan file that contains the proposed infrastructure changes.

terraform plan -out=tfplan.binary
2

Evaluate the Plan with OPA

The opa eval command can directly ingest the binary plan file, evaluate it against your Rego policies, and output any violations.

opa eval --input-file tfplan.binary -d policy.rego "data.terraform.validation.violation"

Writing Production-Ready Policies

Let's write a few practical Rego policies that use the native terraform.parse_plan() built-in for common use cases.

Example 1: Enforce Mandatory Tags

This policy ensures every EC2 instance and S3 bucket has Owner and CostCenter tags.

package terraform.validation
import rego.v1

plan := terraform.parse_plan(input.raw_plan) 

violation[msg] if {
    resource := plan.resource_changes[_]
    resource.type in ["aws_instance", "aws_s3_bucket"]
    contains_element(resource.change.actions, "create")
    
    provided_tags := object.keys(resource.change.after.tags)
    required_tags := {"Owner", "CostCenter"}
    
    missing_tags := required_tags - provided_tags
    count(missing_tags) > 0
    
    msg := sprintf(
        "%s is missing required tags: %v",
        [resource.address, missing_tags]
    )
}

Example 2: Disallow Public S3 Buckets

This policy checks for S3 buckets with the public-read or public-read-write canned ACLs.

package terraform.validation
import rego.v1

plan := terraform.parse_plan(input.raw_plan)

violation[msg] if {
    resource := plan.resource_changes[_]
    resource.type == "aws_s3_bucket"
    contains_element(resource.change.actions, "create")
    
    resource.change.after.acl in ["public-read", "public-read-write"] 
    
    msg := sprintf(
        "%s has a public ACL, which is not allowed.",
        [resource.address]
    )
}

Unit Testing Your OPA Policies

Ensuring your policies work as expected is critical. OPA includes a robust testing framework that allows you to write unit tests for your policies using Rego itself. Create a file named s3_test.rego to test our S3 policy.

Example Test: s3_test.rego

package terraform.validation
import rego.v1

# Mock data for a non-compliant S3 bucket
mock_noncompliant_plan := {
    "resource_changes": [{
        "address": "aws_s3_bucket.unsafe",
        "type": "aws_s3_bucket",
        "change": { "actions": ["create"], "after": {"acl": "public-read"} }
    }]
}

# Test case: A non-compliant bucket should have exactly ONE violation. 
test_noncompliant_bucket if {
    # The 'with' keyword provides mock data for the test
    violations := violation with terraform.plan as mock_noncompliant_plan
    
    count(violations) == 1
    contains(violations[_], "has a public ACL")
}

You can run these tests with the simple command: opa test . --verbose. This allows you to validate your policy logic before deploying it into your CI/CD pipeline.

Automating Enforcement with CI/CD

The real power of OPA is realized when you automate it. Here’s an example of a GitHub Actions workflow that runs your OPA policies on every pull request.

.github/workflows/opa-check.yml

name: Terraform Plan & OPA Policy Check

on:
  pull_request:
    paths:
      - '**.tf'
      - 'policies/**.rego'

jobs:
  opa-check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4 

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3

      - name: Setup OPA
        uses: open-policy-agent/setup-opa@v2
        with:
          opa-version: latest

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan -out=tfplan.binary 

      - name: Run OPA Policy Check
        run: |
          opa eval --fail-defined --input-file tfplan.binary --data policies/ "data.terraform.validation.violation"

The key flag here is --fail-defined. It tells OPA to exit with a non-zero status code if the violation rule produces any results. This will automatically fail the pipeline step and block the pull request from being merged, effectively enforcing your guardrails.

πŸŽ‰ Congratulations!

You've learned the fundamentals of using OPA and Terraform for modern infrastructure governance. You now have the skills to:

Write Policies

Write and test custom Rego policies for common infrastructure resources.

Validate Plans

Use the modern OPA workflow to validate Terraform plans and catch issues early.

Automate Enforcement

Integrate policy checks into a CI/CD pipeline to create effective, automated guardrails.