OPA Gatekeeper vs Kyverno compared for 2026: Rego vs YAML, mutation, reporting, and operations, plus how to pick a Kubernetes policy engine.
A platform team standardizing admission control across dozens of clusters hits the same fork. Gatekeeper's Rego promises one policy language for Kubernetes, CI and Terraform, but nobody on the team knows Rego and onboarding keeps slipping. Kyverno would ship policies this week in YAML, but it is a Kubernetes-only tool.
Both are mature, Apache 2.0, CNCF-hosted admission controllers that validate and mutate resources at the API server. So the decision comes down to policy language, mutation workflow, reporting and how much operational weight you want to carry. This post walks through each, with working policies you can test.
Gatekeeper is a Kubernetes admission controller built on Open Policy Agent, where you write rules in Rego. Kyverno is built only for Kubernetes, where policies are YAML resources. Both sit behind the same admission webhook flow and decide whether a request is allowed.
In practice you run one of the two, not both. Running two engines doubles webhook latency and failure surface.
Maturity differs slightly. OPA is a CNCF graduated project, and Gatekeeper is its Kubernetes sub-project. Kyverno is a CNCF project that was at incubating level at the last check, so confirm its current status if your procurement process depends on it.
Writing the same policy takes noticeably more concepts in Gatekeeper, because it splits logic from usage and adds Rego. Kyverno needs one resource and no new language. Here is "every Pod must have a team label" in both.
Gatekeeper uses a ConstraintTemplate for the logic:
apiVersion: templates.gatekeeper.sh/v1kind: ConstraintTemplatemetadata: name: k8srequiredlabelsspec: crd: spec: names: kind: K8sRequiredLabels validation: openAPIV3Schema: type: object properties: labels: type: array items: type: string targets: - target: admission.k8s.gatekeeper.sh rego: | package k8srequiredlabels violation[{"msg": msg}] { provided := {l | input.review.object.metadata.labels[l]} required := {l | l := input.parameters.labels[_]} missing := required - provided count(missing) > 0 msg := sprintf("missing labels: %v", [missing]) }Then a Constraint applies it to Pods:
apiVersion: constraints.gatekeeper.sh/v1beta1kind: K8sRequiredLabelsmetadata: name: pods-need-teamspec: enforcementAction: warn match: kinds: - apiGroups: [""] kinds: ["Pod"] parameters: labels: ["team"]Kyverno does it in one resource:
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: require-team-labelspec: validationFailureAction: Audit rules: - name: check-team match: any: - resources: kinds: ["Pod"] validate: message: "The label 'team' is required." pattern: metadata: labels: team: "?*"The two-resource split in Gatekeeper is deliberate: one template can power many constraints with different parameters. It pays off at scale, but it is a real learning cost on day one. Gatekeeper also has a public policy library of ready-made templates, which softens the Rego burden.
Kyverno's mutation is simpler to adopt because it lives in the same policy as validation. Gatekeeper supports mutation too, through separate Assign, AssignMetadata and ModifySet resources, and is less commonly used for it. Check the maturity of mutation in your Gatekeeper version before depending on it.
A common Kyverno mutation is defaulting a cost-attribution label when a developer forgets it:
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: default-team-labelspec: rules: - name: add-team-label match: any: - resources: kinds: ["Pod"] mutate: patchStrategicMerge: metadata: labels: +(team): unassignedThe +(team) anchor means "add this label only if it is absent", so existing values are never overwritten.
Kyverno also offers generate rules (create a NetworkPolicy or quota when a namespace appears), verifyImages for image signature checks, and cleanup policies. These go beyond admit-or-deny and are often the deciding factor for platform teams.
Kyverno publishes results as PolicyReport resources, a format from the Kubernetes Policy Working Group that dashboards such as Policy Reporter can read. Gatekeeper runs a separate audit controller and records violations in each Constraint's status. Operationally, Kyverno has more controllers and Gatekeeper has two moving parts to understand plus Rego.
## Gatekeeper: list violations for one constraintkubectl get k8srequiredlabels pods-need-team \ -o jsonpath='{.status.violations}' ## Kyverno: list policy reports across namespaceskubectl get policyreport -AResource footprint depends on your cluster size, policy count and settings, so measure it instead of trusting a published number:
kubectl top pods -n gatekeeper-systemkubectl top pods -n kyvernoKyverno runs several controllers (admission, background, cleanup and reports), while Gatekeeper runs a controller manager and an audit pod. On a large cluster the difference is small next to everything else you run. On a small cluster, check it.
Whichever you pick, the failure mode to plan for is the webhook itself. If it is unreachable and failurePolicy is Fail, API requests are rejected. Exclude kube-system and the engine's own namespace, run multiple replicas with a PodDisruptionBudget, and alert on webhook latency.
For simple validation rules, possibly. Kubernetes' built-in ValidatingAdmissionPolicy evaluates CEL expressions inside the API server, with no webhook to run, and mutating equivalents are arriving in newer releases. Both Gatekeeper and Kyverno are adding CEL support, so check each project's current documentation.
Keep an engine when you need generation, image verification, lookups across resources, audit reporting at scale, or one policy language across several systems.
Language and fit:
| Factor | Gatekeeper | Kyverno |
|---|---|---|
| Policy language | Rego | YAML |
| Policy objects | Template plus constraint | One ClusterPolicy |
| Reuse beyond K8s | Yes, via OPA | No |
Features and operations:
| Factor | Gatekeeper | Kyverno |
|---|---|---|
| Mutation | Separate CRDs | Same policy |
| Generate and verify images | Limited | Built in |
| Reporting | Constraint status | PolicyReport |
Choose Kyverno if your team is Kubernetes-native, wants YAML policies, and needs mutation, resource generation or image verification as first-class features. It usually has the shortest path to a first working policy.
Choose Gatekeeper if you already have Rego skills, want rules that also run in CI and other systems, or need the expressiveness of a full policy language. Cross-platform reuse only pays off if you will actually enforce policy outside the cluster.
Whichever you choose, roll out the same way:
Audit or Gatekeeper dryrun and warn, so nothing is blocked while you learn what would be.The two are not mutually exclusive to evaluate in sequence. Start with the one that matches your team's skills, and revisit if your governance needs change.
References and Further Reading
- Kyverno Documentation - Official ClusterPolicy, mutation and reporting reference
- OPA Gatekeeper Documentation - ConstraintTemplates, constraints and mutation
- Open Policy Agent - Rego language reference
- Validating Admission Policy - Built-in CEL-based validation
Yes, that is the main argument for Gatekeeper. Rego is OPA's general policy language, so related rules can run in CI with conftest against Terraform plan output or in an API gateway. The Kubernetes wrappers (ConstraintTemplates) still have to be written, so reuse covers the logic, not the whole policy object.
Yes. Mutation lives in the same ClusterPolicy as validation and is widely used, for example to default a team label or add security context fields. Gatekeeper also mutates, through Assign, AssignMetadata and ModifySet resources, but most teams reach for Kyverno first for mutation-heavy work.
If the webhook is unreachable and failurePolicy is Fail, API requests are rejected, including system pods. Exclude kube-system and the engine's own namespace, run multiple replicas with a PodDisruptionBudget, set short timeouts, and start every policy in audit or warn mode before enforcing.
Start in report-only mode (Kyverno Audit, Gatekeeper dryrun or warn), review violations for a week or two, fix or exempt the offenders, then switch to enforce. Enforce namespace by namespace, starting with non-production.
For simple validation they can. ValidatingAdmissionPolicy runs in the API server with no webhook to operate. You still need an engine for richer needs such as generation, image signature verification, cross-resource lookups, audit reporting and cross-platform policy. Check each project's current CEL support.
Discussion0