Example policies

Realistic patterns for gating Terraform plans, GitHub PRs, Kubernetes manifests, and config files.

Terraform blast radius

Deny large destructive changes unless the author is on the platform team.

forbid "blast-radius" {
  description "Large destructive changes require platform-team approval"
  owner       "platform"

  count(plan.destroys) > 5

  unless author.teams contains "platform-team"

  message "too many destroys ({count(plan.destroys)}) — needs platform-team"
}

Weighted risk score

Use arithmetic to build a composite risk metric.

forbid "risk-score" {
  description "Composite risk score: destroys weighted 3x, creates 1x"

  count(plan.destroys) * 3 + count(plan.creates) > 20

  unless author.teams contains "platform-team"

  message "risk score exceeded"
}

IAM changes need security review

forbid "sensitive-iam" {
  description "IAM changes require security team or explicit approval label"
  owner       "security"
  link        "https://wiki.example.com/iam-change-policy"

  resource.type matches "aws_iam_*"

  unless author.teams contains "security"
  unless labels contains "security-approved"
  unless pr.approvals >= 2

  message "{resource.type}.{resource.name} requires security approval"
}

Naming convention

warn "naming-convention" {
  description "Resources should follow kebab-case naming"

  not resource.name matches_regex "^[a-z][a-z0-9-]+$"

  message "{resource.name} doesn't follow naming convention"
}

No public S3 buckets

forbid "no-public-buckets" {
  description "S3 buckets must not be publicly accessible"
  owner       "platform-security"

  resource.type == "aws_s3_bucket"
  resource.change.after.acl in ["public-read", "public-read-write"]

  unless labels contains "public-data-approved"

  message "{resource.name} cannot be public"
}

GitHub draft PR gate

forbid "no-draft-production" {
  description "Draft PRs cannot target production"

  pr.draft == true
  project.workspace == "production"

  message "draft PRs cannot target production"
}

forbid "production-approvals" {
  description "Production deploys require at least 2 approvals"

  project.workspace == "production"
  pr.approvals < 2

  message "production requires 2 approvals (currently {pr.approvals})"
}

Infra file gate

forbid "infra-file-gate" {
  description "Infra file changes require platform team"

  any pr.changed_files matches "infra/*"

  unless author.teams contains "platform-team"

  message "infra file changes require platform-team"
}

Kubernetes: no :latest tags in prod

forbid "no-latest-prod" {
  description "Production workloads must pin image tags"

  resource.kind == "Deployment"
  resource.namespace == "production"
  any resource.containers matches "*:latest"

  message "production deployments must not use :latest image tags"
}

Config file must have owner

forbid "service-must-have-owner" {
  description "Every service must declare an owner"

  resource.kind == "Service"
  not has resource.metadata.owner

  message "service {resource.metadata.name} is missing an owner field"
}

Permit as audit trail

Use permit rules to emit positive audit messages when a specific allowance applies.

permit "security-iam-override" {
  description "Security team can modify IAM resources"

  resource.type matches "aws_iam_*"
  author.teams contains "security"

  message "IAM change permitted by security team member {author.name}"
}