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
- Download: Terraform for Windows (v1.13.1)
- Extract the .zip to
C:\Terraform
- Add
C:\Terraform
to System PATH:- Search “Environment Variables”
- Edit System variables → Path → New →
C:\Terraform
- Verify installation:
terraform -version
(B) Install OPA
- Download: OPA Windows Release (v0.67.0)
- Extract
opa_windows_amd64.exe
(rename toopa.exe
) toC:\OPA
- Add
C:\OPA
to System PATH - Verify installation:
opa version
(C) Install AWS CLI v2
- Download: AWS CLI v2 MSI Installer
- Run installer
- 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
→ containsresource_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
- ACL should not be
- Adds messages to
deny
list if violations are found.
No comments:
Post a Comment