Policy as Code: Sentinel und OPA
Compliance-Checks vor Apply.
Lernziele
Nach dieser Lektion kannst du erklären, warum Policy as Code über bloße Reviews hinausgeht, und die Unterschiede zwischen Sentinel (Terraform Cloud) und OPA/Conftest (Open Source) benennen. Du schreibst eine einfache Regel, die Pläne vor dem Apply blockiert, und weißt, wo im CI/CD-Flow Policies eingreifen.
Das Problem: Review allein reicht nicht
Dein Kollege öffnet einen PR: ein neuer S3-Bucket, eine Security Group mit 0.0.0.0/0 auf Port 22, eine RDS-Instanz ohne Verschlüsselung. Im Review steht „LGTM” — niemand hat die 400 Zeilen Plan-Diff Zelle für Zelle gelesen. Drei Tage später findet Security den offenen SSH-Port.
Manuelle Reviews skalieren nicht und sind fehleranfällig. Policy as Code codifiziert Regeln — „kein öffentlicher SSH”, „Verschlüsselung Pflicht”, „nur approved Instance-Types” — und prüft sie automatisch gegen jeden Plan, bevor Apply möglich ist.
Wo Policies eingreifen
Zwei Einhängepunkte:
- Pre-Apply (Plan-Phase): Policy evaluiert den JSON-Plan — welche Ressourcen würden erstellt/geändert? Blockiert oder warnt vor dem Apply.
- Static (HCL-Phase): Tools wie checkov/tfsoc scannen die
.tf-Dateien ohne Plan — ergänzend, nicht ersetzend (Lektion 11).
Policy-as-Code auf Plan-Ebene sieht effektive Werte nach Variablen-Auflösung — genau das, was wirklich in der Cloud landen würde.
Sentinel — HashiCorps Policy-Sprache
Sentinel läuft nativ in HCP Terraform / Terraform Cloud. Du definierst Policies in .sentinel-Dateien und enforcest sie pro Workspace:
# deny-public-sg.sentinel
import "tfplan/v2" as tfplan
public_ingress = filter tfplan.resource_changes as _, rc {
rc.type is "aws_security_group_rule" and
rc.change.after.cidr_blocks contains "0.0.0.0/0" and
rc.change.after.from_port is 22
}
main = rule {
length(public_ingress) is 0
}
Enforcement Levels:
- advisory — Warnung, Apply erlaubt
- soft-mandatory — Override mit Begründung möglich
- hard-mandatory — Apply blockiert, keine Ausnahme
Sentinel ist mächtig und an Terraform Cloud gebunden. Für Teams, die ohne TFC arbeiten, ist es keine Option — dann kommt OPA.
OPA / Conftest — cloud- und tool-agnostisch
Open Policy Agent evaluiert Regeln in Rego gegen JSON — unter anderem Terraform-Pläne, Kubernetes-Manifeste, CloudFormation. Conftest ist das CLI dafür:
# policy/deny_public_ssh.rego
package terraform.analysis
deny contains msg if {
some rc in input.resource_changes
rc.type == "aws_security_group_rule"
rc.change.actions[_] == "create"
rc.change.after.cidr_blocks[_] == "0.0.0.0/0"
rc.change.after.from_port == 22
msg := sprintf("SSH offen ins Internet: %s", [rc.address])
}
In CI:
terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
conftest test plan.json --policy policy/
Conftest scheitert mit Exit Code 1 bei Verletzungen — der PR blockiert. Kein Vendor-Lock-in, funktioniert in GitHub Actions, GitLab CI und lokal.
Sentinel vs. OPA — wann was?
| Sentinel | OPA/Conftest | |
|---|---|---|
| Laufzeit | Terraform Cloud | Überall (CI, lokal, Admission Controller) |
| Sprache | Sentinel | Rego |
| Input | tfplan/v2 nativ | JSON (Plan exportieren) |
| Kosten | TFC-Lizenz | Open Source |
| K8s Policies | Nein | Ja (gleiche Engine) |
Platform-Teams mit TFC und ohne Kubernetes-Fokus: Sentinel ist integriert. Teams mit Multi-Tool-Landschaft (TF + K8s + Helm): OPA amortisiert sich über mehrere Use Cases.
Praxis: Conftest lokal gegen Plan
mkdir policy-lab && cd policy-lab
cat > main.tf <<'EOF'
resource "random_pet" "server" { length = 2 }
output "name" { value = random_pet.server.id }
EOF
cat > policy/deny_pet_prefix.rego <<'EOF'
package terraform.analysis
deny contains msg if {
some rc in input.resource_changes
rc.type == "random_pet"
startswith(rc.change.after.prefix, "prod")
msg := "random_pet mit prod-prefix nicht erlaubt in dev"
}
EOF
terraform init
terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
conftest test plan.json --policy policy/ # sollte passieren
# Prefix auf prod setzen, erneut planen → conftest schlägt fehl
Für echte Security-Regeln ersetzt du random_pet durch aws_security_group_rule — das Pattern bleibt gleich.
Typische Stolperfallen
Policies nur in Prod, nicht in Dev: Regeln gelten überall — sonst testet niemand gegen sie, bis Prod blockiert.
Nur warnen, nie blocken: Advisory Policies werden ignoriert. Für Compliance-relevante Regeln: hard-mandatory oder CI-Exit 1.
Plan-JSON-Schema-Änderungen: Provider-Upgrades können Plan-JSON-Struktur ändern. Policies brauchen Wartung wie Code.
Policy-Sprache und Team-Skills: Rego hat Lernkurve. Starte mit 3–5 klaren Regeln, nicht mit 200 Zeilen Policy-Framework am ersten Tag.
Policies vs. IAM verwechseln: IAM verhindert API-Calls — Policy-as-Code verhindert, dass der Plan überhaupt approved wird. Beides ergänzt sich; Policy ersetzt keine least-privilege IAM-Rollen.
Interview-Vorbereitung
„Was ist Policy as Code bei Terraform?” — Automatische Durchsetzung von Compliance-Regeln gegen den Plan vor Apply; Sentinel in TFC, OPA/Conftest open source in CI.
Follow-ups:
- „Sentinel vs. OPA?” — TFC-integriert vs. überall; Sentinel vs. Rego; OPA auch für K8s.
- „Warum Plan-basiert statt HCL-basiert?” — Plan enthält aufgelöste Werte — was wirklich deployed wird.
- „Wie integrierst du Conftest in CI?” — plan → show -json → conftest test → Exit 1 blockiert Merge.
- „Unterschied advisory vs. mandatory?” — Warnung vs. harter Block.
Zusammenfassung
Policy as Code automatisiert Compliance-Checks auf Terraform-Plänen — jenseits dessen, was menschliche Reviews leisten. Sentinel ist die integrierte Lösung in Terraform Cloud; OPA/Conftest ist der offene Standard für CI-Pipelines und Multi-Tool-Umgebungen. Regeln gehören auf Plan-Ebene, werden hard enforced für kritische Controls und brauchen Pflege wie jeder andere Code.
In der nächsten Lektion holen wir bestehende Infrastruktur unter Terraform-Verwaltung — Import und Migration.