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:\Terraformto 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:\OPAto 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 applyif 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_changesarray). - Loops through resources with
some resource. - Checks only
aws_s3_buckettype. - Validates:
- ACL should not be
public-read - Versioning must be enabled
- Server-side encryption must be enabled
- ACL should not be
- Adds messages to
denylist if violations are found.
No comments:
Post a Comment