Gatekeeper ConstraintTemplates at scale
Templates, constraints, and syncing data.
In short. Gatekeeper wraps OPA for Kubernetes with ConstraintTemplates (Rego + schema) and Constraints (parameters + selectors).
Gatekeeper wraps OPA for Kubernetes with ConstraintTemplates (Rego + schema) and Constraints (parameters + selectors). At scale the template is the product: one well-tested template parameterized many ways beats twenty near-copies. Syncing cluster data into OPA (config.gatekeeper.sh) lets policies reason about existing Inventory — for example, denying Services that reference non-existent Secrets is a data problem, not just an input problem.
Start in dry-run (enforcementAction: dryrun), watch violations, then flip to deny by namespace wave. Treat template upgrades like schema migrations.
Template + constraint
apiVersion: templates.gatekeeper.sh/v1kind: ConstraintTemplatemetadata:name: k8sallowedreposspec:crd:spec:names:kind: K8sAllowedReposvalidation:openAPIV3Schema:type: objectproperties:repos:type: arrayitems: { type: string }targets:- target: admission.k8s.gatekeeper.shrego: |package k8sallowedreposviolation[{"msg": msg}] {container := input.review.object.spec.containers[_]satisfied := [r | r := input.parameters.repos[_]; startswith(container.image, r)]not count(satisfied)msg := sprintf("image %v not from allowed repos", [container.image])}
kubectl apply -f template.yamlkubectl apply -f constraint.yamlkubectl get K8sAllowedReposkubectl get constraints -o wide 2>/dev/null | head
NAME ENFORCEMENT-ACTIONallowed-repos-prod dryrun
Going deeper
Match constraints with label selectors and namespace selectors to avoid boiling the ocean on day one. Platform namespaces often need different parameters than product namespaces. Multi-tenant clusters benefit from templates that take repos as parameters rather than hardcoding.
Watch Gatekeeper audit and webhook latency SLOs. Slow admission is an availability incident. Profile expensive Rego (unbounded comprehensions over large lists) before enforcing in prod.
Backup ConstraintTemplates in Git even if the live cluster is the apply target. Disaster recovery of policy is part of cluster DR — empty Gatekeeper after rebuild means open floodgates.
Use enforcementAction: dryrun and warn thoughtfully: warn can train teams to ignore. Publish a date when dry-run becomes deny, and meet it. Rolling forever in dry-run is how risk becomes culture.
Separate mutating admission from validating Gatekeeper policies operationally — ordering and failure modes differ. Document which webhook fails open vs closed in an outage.
Name constraints after the control (deny-privileged-prod), not after the requester. Inventory them in a catalog page so app teams can discover standards before they invent exceptions.
When upgrading Gatekeeper, read the release notes for Rego/API changes and re-run opa test plus a canary cluster. Policy engines are load-bearing infrastructure.
Keep a lab cluster on the next Gatekeeper version ahead of prod so template upgrades are rehearsed. Policy control planes deserve the same canary discipline as application runtimes.
Try this
Install Gatekeeper in a kind cluster (or use an existing lab), apply a dry-run allowed-repos constraint, and create a violating Pod to see the violation object.
kubectl get k8sallowedreposallowedrepos.constraints.gatekeeper.sh -o yaml | head -40
status:totalViolations: 1violations:- …
Takeaway
Gatekeeper scales when templates are libraries, constraints are parameters, dry-run precedes deny, and Rego stays under unit test outside the cluster.
Next: Kyverno's mutate, generate, and verifyImages — policy that fixes and proves, not only rejects.