Compare Sentinel and OPA (Open Policy Agent) for Terraform policy enforcement. How would you implement a policy that prevents any S3 bucket from being created without encryption, versioning, and a lifecycle policy?
Quick Answer
Sentinel is HashiCorp's proprietary policy language (Terraform Cloud/Enterprise only), while OPA uses Rego language and works with any Terraform workflow via conftest or terraform-compliance. OPA is more portable and widely adopted; Sentinel has deeper Terraform integration but vendor lock-in.
Detailed Answer
Sentinel vs OPA Comparison
Sentinel (HashiCorp)
- Proprietary language, only works with HashiCorp products - Deep integration with Terraform Cloud/Enterprise (runs between plan and apply) - Access to tfplan, tfconfig, tfstate, and tfrun imports - Three enforcement levels: advisory (warn), soft-mandatory (override with approval), hard-mandatory (cannot override) - Easier to learn for simple policies but limited ecosystem
OPA/Rego
- Open source, CNCF graduated project - Works with any tool that produces JSON (terraform plan -out=plan.json -> terraform show -json plan.json) - Use conftest for CLI-based policy checks, or OPA server for runtime evaluation - Rich ecosystem: used for Kubernetes admission (Gatekeeper), API authorization, CI/CD gates - Steeper learning curve but more powerful and portable
Decision Framework
- Using Terraform Cloud/Enterprise? Sentinel is the path of least resistance - Multi-tool environment (Terraform + K8s + CI/CD)? OPA for unified policy language - Open-source Terraform or OpenTofu? OPA is the only option
Implementation Architecture
In CI/CD: Run terraform plan -out=plan.tfplan, convert to JSON with terraform show -json plan.tfplan > plan.json, then evaluate with conftest test plan.json --policy ./policies/. Block the pipeline if policies fail. For Terraform Cloud: Upload Sentinel policies to policy sets linked to workspaces.
Code Example
# OPA/Rego policy: Enforce S3 encryption, versioning, and lifecycle
# policies/s3_compliance.rego
package terraform.s3
import rego.v1
resource_changes := input.resource_changes
s3_buckets := [rc |
rc := resource_changes[_]
rc.type == "aws_s3_bucket"
rc.change.actions[_] == "create"
]
# Check encryption is enabled
deny contains msg if {
bucket := s3_buckets[_]
not has_encryption(bucket.change.after)
msg := sprintf("S3 bucket '%s' must have server-side encryption enabled", [bucket.address])
}
# Check versioning is enabled
deny contains msg if {
bucket := s3_buckets[_]
not has_versioning(bucket.change.after)
msg := sprintf("S3 bucket '%s' must have versioning enabled", [bucket.address])
}
has_encryption(config) if {
config.server_side_encryption_configuration[_].rule[_].apply_server_side_encryption_by_default[_].sse_algorithm
}
has_versioning(config) if {
config.versioning[_].enabled == true
}
# Run with conftest
# terraform plan -out=plan.tfplan
# terraform show -json plan.tfplan > plan.json
# conftest test plan.json --policy ./policies/ --output table
# Sentinel equivalent (for Terraform Cloud)
# s3_encryption.sentinel
import "tfplan/v2" as tfplan
s3_buckets = filter tfplan.resource_changes as _, rc {
rc.type is "aws_s3_bucket" and
rc.change.actions contains "create"
}
encryption_enabled = rule {
all s3_buckets as _, bucket {
bucket.change.after.server_side_encryption_configuration is not empty
}
}
main = rule {
encryption_enabled
}
# GitHub Actions integration
# - name: Policy Check
# run: |
# terraform show -json plan.tfplan > plan.json
# conftest test plan.json --policy ./policies/ --output json
# if [ $? -ne 0 ]; then echo "Policy violations found"; exit 1; fiInterview Tip
Policy-as-code is a hot topic. Know both Sentinel and OPA but recommend OPA for most scenarios due to portability. The key differentiator is that OPA works everywhere (K8s, CI/CD, API gateways, Terraform) while Sentinel only works with HashiCorp products. Show you can write actual Rego, not just talk about it conceptually.