OPA Gatekeeper in der Praxis
ConstraintTemplates, Audit-Mode und wann Rego sich lohnt.
von PlatPrep
Rego ist eine Programmiersprache. Das ist das Erste, was man akzeptieren muss, wenn man mit OPA Gatekeeper arbeitet. Nicht ein YAML-Format mit Schlüsselwörtern, nicht ein Annotation-System — eine eigene, logik-deklarative Sprache, die ein Umdenken erfordert.
Das macht den Einstieg schwerer als bei Kyverno. Aber es macht OPA auch mächtiger für komplexe Policy-Logik.
Template und Constraint: die Zwei-Schichten-Architektur
Eine ConstraintTemplate definiert zwei Dinge: den kind der neuen Constraint-Ressource (z.B. K8sRequiredLabels) und die Rego-Logik, die entscheidet, ob eine Ressource die Policy erfüllt. Gatekeeper erzeugt aus dem Template eine eigene CRD — deine Policies werden zu first-class Kubernetes-Objekten.
violation[{"msg": msg}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("fehlende Labels: %v", [missing])
}
input.review.object ist die eingehende Ressource, input.parameters kommen aus der Constraint-Instanz. Die violation-Regel feuert, wenn alle Bedingungen im Body wahr sind — das ist die logik-deklarative Denkweise: du beschreibst, wann etwas falsch ist, nicht wie geprüft wird.
Eine zugehörige Constraint-Instanz:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
enforcementAction: dryrun
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["team", "environment"]
Die Trennung ist clever: das Template ist die wiederverwendbare Policy-Logik, die Constraint ist die Instanz mit Parametern und Scope. Das gleiche Template läuft in mehreren Constraints — etwa strenge Label-Pflichten in Produktions-Namespaces, lockere in Dev.
enforcementAction: der wichtigste Hebel beim Rollout
Das Feld enforcementAction kennt drei Werte, und die Reihenfolge, in der du sie nutzt, entscheidet über die Akzeptanz im Unternehmen:
dryrun blockiert nichts, sammelt aber Violations im Status der Constraint. warn lässt die Ressource durch, gibt dem User aber eine Warnung im kubectl-Output zurück — unterschätzt nützlich, weil Entwickler die Meldung direkt sehen. deny (der Default) blockiert hart.
Parallel prüft der Audit-Controller bestehende Ressourcen periodisch gegen alle Constraints (Standard-Intervall: 60 Sekunden) und schreibt Violations in den Constraint-Status. Der typische Rollout-Pfad: Policy in dryrun deployen, eine Woche Audit-Ergebnisse beobachten, betroffene Teams informieren, Altlasten bereinigen, dann auf deny schalten. Wer den Schritt überspringt und direkt blockiert, produziert den klassischen Incident: ein CI-Deployment schlägt freitags um 17 Uhr fehl, weil ein drei Jahre altes Deployment kein team-Label hat.
Ein Detail, das in Interviews gern abgefragt wird: Gatekeepers Admission-Webhook steht per Default auf failurePolicy: Ignore. Wenn die Gatekeeper-Pods nicht erreichbar sind, gehen Requests ungeprüft durch. Fail-open ist die richtige Default-Entscheidung für Verfügbarkeit — aber es bedeutet, dass deine Policies keine harte Sicherheitsgarantie sind, solange du nicht bewusst auf fail-closed umstellst und die Konsequenzen (Gatekeeper-Ausfall = Cluster-weiter Deployment-Stopp) trägst.
Referential Policies: wenn eine Ressource nicht reicht
Manche Policies brauchen Kontext über die geprüfte Ressource hinaus: “Kein Ingress darf einen Hostnamen verwenden, den ein anderer Ingress schon belegt.” Dafür repliziert Gatekeeper auf Wunsch Cluster-Ressourcen in den OPA-Cache — konfiguriert über eine Config-Ressource (oder neuere SyncSet-Objekte). In Rego greifst du dann über data.inventory auf den Cache zu.
Das ist mächtig, hat aber Kosten: jede replizierte Ressourcenart erhöht den Memory-Verbrauch der Gatekeeper-Pods. Wer alle Secrets in den Cache synct, hat außerdem ein Sicherheitsproblem geschaffen, kein gelöstes.
Testen, bevor es in den Cluster geht
Der eigentliche Grund, die Rego-Lernkurve zu akzeptieren: Policies sind voll testbar. opa test führt Unit-Tests gegen die Rego-Logik aus, und das gator-CLI testet komplette ConstraintTemplates samt Constraints gegen Beispiel-Manifeste — in CI, vor dem Merge:
gator verify ./policies/...
Das ist eine andere Qualität als manuelle YAML-Reviews. Eine Policy-Änderung durchläuft denselben Review-und-Test-Zyklus wie Applikationscode. Bei zwanzig Policies und fünf Teams, die Änderungen vorschlagen, ist das der Unterschied zwischen beherrschbar und chaotisch.
Seit einigen Versionen kann Gatekeeper übrigens auch mutieren — Assign, AssignMetadata und ModifySet sind eigene CRDs, die ohne Rego auskommen. Wer aber primär mutieren und generieren will, ist bei Kyverno meist schneller am Ziel.
Wann sich Rego lohnt — und wann nicht
Die ehrliche Abwägung: für “alle Pods brauchen Resource-Limits” und ähnliche Standard-Checks ist die Rego-Investition übertrieben; das löst Kyverno mit zehn Zeilen YAML. OPA spielt seine Stärke aus, wenn Policy-Logik echte Logik ist — Mengenoperationen, Cross-Resource-Checks, Ausnahmeregeln mit mehreren Bedingungen. Und wenn Policies über Kubernetes hinaus wiederverwendet werden sollen: OPA läuft auch in CI-Pipelines, API-Gateways und Terraform-Checks mit derselben Sprache.
Für große Organisationen mit komplexen Anforderungen ist Gatekeeper die mächtigste Option. Die Lernkurve ist real — aber Policy-as-Code mit Tests zahlt sich aus, sobald Policies geschäftskritisch werden. Die Grundlagen von Rego und OPA kannst du im OPA-Lernpfad strukturiert durcharbeiten.