What is Policy as Code?
Policy as Code (PaC) means writing your compliance and security requirements as machine-readable rules that are enforced automatically in your CI/CD pipeline โ not discovered in a quarterly audit. Instead of a checklist a human reviews, PaC tools scan your Terraform plans before apply and block non-compliant changes.
Common frameworks: OPA/Rego (Open Policy Agent), Sentinel (HashiCorp), Checkov (Bridgecrew), and tfsec.
OPA/Rego Policies
OPA is a general-purpose policy engine. Write Rego policies to enforce rules on Terraform plans:
# policies/no_public_s3.rego
package terraform.aws.s3
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket_public_access_block"
resource.change.after.block_public_acls != true
msg := sprintf("S3 bucket public ACLs must be blocked: %v", [resource.address])
}
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket"
not block_public_access_configured(resource.address)
msg := sprintf("S3 bucket %v must have a public access block resource", [resource.address])
}
Checkov for CIS Compliance
Checkov scans Terraform files directly and maps findings to compliance frameworks:
# Run Checkov with CIS AWS Benchmark
checkov -d . --framework terraform --check CKV_AWS_18,CKV_AWS_19,CKV_AWS_20 \ # S3 checks
--check CKV_AWS_7,CKV_AWS_145 # KMS and encryption
--output sarif --output-file results.sarif
# In GitHub Actions
- name: Checkov Scan
uses: bridgecrewio/checkov-action@master
with:
directory: .
framework: terraform
output_format: sarif
soft_fail: false # fail the build on violations
PCI-DSS Controls with Terraform
PCI-DSS requires encryption at rest, encryption in transit, network segmentation, and access logging. Enforce these with Terraform:
# PCI-DSS Req 3: Encryption at rest
resource "aws_rds_cluster" "main" {
storage_encrypted = true # Required
kms_key_id = aws_kms_key.rds.arn
deletion_protection = true # Prevent accidental deletion
backup_retention_period = 7 # At least 7 days for PCI
}
# PCI-DSS Req 4: Encryption in transit
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.main.arn
port = "443"
protocol = "HTTPS" # Never HTTP in PCI scope
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = aws_acm_certificate.main.arn
}
# PCI-DSS Req 10: Audit logging
resource "aws_cloudtrail" "main" {
name = "${var.project}-trail"
s3_bucket_name = aws_s3_bucket.audit_logs.id
include_global_service_events = true
is_multi_region_trail = true
enable_log_file_validation = true # Tamper detection
}
Sentinel Policies (Terraform Cloud/Enterprise)
# sentinel.hcl โ enforce policies in Terraform Cloud
policy "no-public-s3" {
source = "./policies/no-public-s3.sentinel"
enforcement_level = "hard-mandatory" # blocks apply if violated
}
policy "require-encryption" {
source = "./policies/require-encryption.sentinel"
enforcement_level = "hard-mandatory"
}
policy "check-cost-estimate" {
source = "./policies/cost-limit.sentinel"
enforcement_level = "soft-mandatory" # requires override to bypass
}
CI/CD Integration
# .github/workflows/terraform.yml โ add security scanning
- name: tfsec Security Scan
uses: aquasecurity/tfsec-action@v1.0.0
with:
soft_fail: false
- name: Checkov Compliance Scan
uses: bridgecrewio/checkov-action@master
with:
framework: terraform
check: CKV_AWS_*
output_format: cli,sarif
output_file_path: checkov_results.sarif
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: checkov_results.sarif
Try CloudFormation Free
Design infrastructure visually and generate production-ready Terraform in seconds โ 693 resources across 9 cloud providers.
๐ Open the Designer โ