Monday, 25 August 2025

OPA Policy Enforcement for AWS S3 using Terraform

OPA + Terraform S3 Policy Guide (Windows)

OPA + Terraform S3 Policy Guide (Windows)


1. Prerequisites

Tools & Versions

Tool / Software Recommended Version (as of Sept 2025)
Terraform CLI 1.13.1
OPA (Open Policy Agent) 0.67.0
AWS CLI v2 Latest (v2.x.y)

Install Steps

(A) Install Terraform

  1. Download: Terraform for Windows (v1.13.1)
  2. Extract the .zip to C:\Terraform
  3. Add C:\Terraform to System PATH:
    • Search “Environment Variables”
    • Edit System variables → Path → New → C:\Terraform
  4. Verify installation:
    terraform -version

(B) Install OPA

  1. Download: OPA Windows Release (v0.67.0)
  2. Extract opa_windows_amd64.exe (rename to opa.exe) to C:\OPA
  3. Add C:\OPA to System PATH
  4. Verify installation:
    opa version

(C) Install AWS CLI v2

  1. Download: AWS CLI v2 MSI Installer
  2. Run installer
  3. Configure:
    aws configure
    Enter:
    • Access Key
    • Secret Key
    • Region (e.g., us-east-1)
    • Output format: json

2. Create Terraform Configuration

Directory structure:

C:\OPA_S3\
│
├── main.tf               # Terraform configuration (AWS provider & S3 bucket)
├── variables.tf          # (Optional) Variables file
├── outputs.tf            # (Optional) Outputs file
├── s3.tfplan             # Terraform binary plan file (auto-generated)
├── s3-plan.json          # JSON plan for OPA (auto-generated)
│
└── policy\               # Folder for OPA policies
    └── s3.rego           # OPA policy for S3 compliance

Create main.tf inside C:\OPA_S3:

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "example" {
  bucket = "my-opa-test-bucket-12345"
  acl    = "public-read" # <-- This will violate the policy
}

3. Generate Terraform Plan

cd C:\OPA_S3
terraform init
terraform plan -out=s3.tfplan
terraform show -json s3.tfplan > s3-plan.json

This creates a machine-readable s3-plan.json for OPA.


4. Create OPA Policy

Create folder C:\OPA_S3\policy and file s3.rego:

package terraform.s3

# Default: no deny messages
default deny = []

# Rule: Disallow public S3 buckets
deny[msg] {
  some resource
  input.resource_changes[resource].type == "aws_s3_bucket"
  acl := input.resource_changes[resource].change.after.acl
  acl == "public-read"
  msg := sprintf("Bucket %v has public-read ACL", [input.resource_changes[resource].name])
}

# Rule: Require versioning
deny[msg] {
  some resource
  input.resource_changes[resource].type == "aws_s3_bucket"
  not input.resource_changes[resource].change.after.versioning.enabled
  msg := sprintf("Bucket %v does not have versioning enabled", [input.resource_changes[resource].name])
}

# Rule: Require server-side encryption
deny[msg] {
  some resource
  input.resource_changes[resource].type == "aws_s3_bucket"
  not input.resource_changes[resource].change.after.server_side_encryption_configuration
  msg := sprintf("Bucket %v does not have server-side encryption enabled", [input.resource_changes[resource].name])
}

5. Evaluate Policy with OPA

opa eval -i s3-plan.json -d policy\s3.rego "data.terraform.s3.deny"

Expected output example:

{
  "result": [
    {
      "expressions": [
        {
          "value": [
            "Bucket aws_s3_bucket.example has public-read ACL",
            "Bucket aws_s3_bucket.example does not have versioning enabled",
            "Bucket aws_s3_bucket.example does not have server-side encryption enabled"
          ]
        }
      ]
    }
  ]
}

If the list is empty ([]), your Terraform code passes all policies.


6. Enforce the Policy

Integration examples:

  • CI/CD pipeline: Fail the job if deny messages exist.
  • Pre-apply hook: Block terraform apply if violations are found.

Example PowerShell snippet:

if ((opa eval -i s3-plan.json -d policy\s3.rego "data.terraform.s3.deny" | ConvertFrom-Json).result[0].expressions[0].value.Count -gt 0) {
    Write-Host "Policy violations found! Aborting..."
    exit 1
}

7. How the Policy Works

  • Reads Terraform plan (s3-plan.json → contains resource_changes array).
  • Loops through resources with some resource.
  • Checks only aws_s3_bucket type.
  • Validates:
    • ACL should not be public-read
    • Versioning must be enabled
    • Server-side encryption must be enabled
  • Adds messages to deny list if violations are found.

No comments:

Post a Comment