Policy-as-code is now a baseline expectation for any production Kubernetes platform — the guardrail that stops a mislabeled, over-privileged, or non-compliant workload from ever reaching the cluster. Two tools dominate this space: Gatekeeper and Kyverno. This is a practical look at how they differ and how to decide which one fits your team.
Gatekeeper is a general-purpose policy engine built on the Open Policy Agent (OPA). It lets you define and enforce custom policies across a wide range of Kubernetes resources — and, thanks to OPA's general-purpose nature, beyond Kubernetes too.
Kyverno is purpose-built for Kubernetes. It focuses on validating and mutating resources to enforce the configurations and security policies you want, using a policy language that will feel immediately familiar to anyone who already writes Kubernetes manifests.
| Gatekeeper | Kyverno |
|---|---|
| Acts as an admission controller — it evaluates policies during the admission of resources. | Built using Custom Resource Definitions (CRDs) and operates as a validating and mutating webhook. |
| Uses the powerful Rego language, part of the OPA project, to define policies. | Uses a declarative YAML/JSON policy language that many users find easier to read and write. |
| Requires prior knowledge of Rego to understand and author policies. | Leans on Kubernetes YAML/JSON that teams already know, lowering the learning curve. |
| Ships no built-in policies out of the box, though community-contributed policies exist to get started. | Comes with a library of built-in policies and examples covering common use cases. |
| More extensible — its general-purpose nature lets you enforce policy beyond Kubernetes. | Kubernetes-first, making it highly optimised for Kubernetes resources and scenarios. |
Gatekeeper supports three installation methods.
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yamlhelm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper --name-template=gatekeeper \
--namespace gatekeeper-system --create-namespacegit clone https://github.com/open-policy-agent/gatekeeper.git
export DESTINATION_GATEKEEPER_IMAGE=<registry, e.g. "myregistry.docker.io/gatekeeper">
make docker-buildx REPOSITORY=$DESTINATION_GATEKEEPER_IMAGE OUTPUT_TYPE=type=registry
make deploy REPOSITORY=$DESTINATION_GATEKEEPER_IMAGEOnce installed, you create a template and a constraint to enforce a policy. In this example we block any Deployment that is missing the label app.
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: kubernetesvalidatinglabel
spec:
crd:
spec:
names:
kind: KubernetesValidatingLabel
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package kubernetes.validating.labels
import future.keywords.contains
import future.keywords.if
import future.keywords.in
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("you must provide labels: %v", [missing])
}apiVersion: constraints.gatekeeper.sh/v1beta1
kind: KubernetesValidatingLabel
metadata:
name: require-deployment-labels
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment"]
parameters:
labels:
- appNow try to create a Deployment that has a test label but no app label:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
test: prod
spec:
replicas: 2
selector:
matchLabels:
test: prod
template:
metadata:
labels:
test: prod
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80Applying it is rejected at admission:
Error from server (Forbidden): error when creating "deploy.yaml":
admission webhook "validation.gatekeeper.sh" denied the request:
[require-deployment-labels] you must provide labels: {"app"}Installation is equally quick.
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno -n kyverno --create-namespacekubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.10.0/install.yamlkubectl create -f https://github.com/kyverno/kyverno/raw/main/config/install-latest-testing.yamlWith Kyverno you author the policy directly — no separate template and constraint. Here is the equivalent of the Gatekeeper policy above: a ClusterPolicy that requires the label app on every Deployment.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-deployment-labels
spec:
# Enforce = block the request; Audit = allow but report.
validationFailureAction: Enforce
rules:
- name: check-app-label
match:
any:
- resources:
kinds:
- Deployment
validate:
message: "You must set the label `app` on all Deployments."
pattern:
metadata:
labels:
# "?*" means any non-empty value must be present.
app: "?*"Notice this is a single file, versus the template + constraint pair Gatekeeper needs. Apply the same non-compliant Deployment and Kyverno blocks it:
Error from server: error when creating "deploy.yaml":
admission webhook "validate.kyverno.svc-fail" denied the request:
resource Deployment/default/nginx-deployment was blocked due to the following policies:
require-deployment-labels:
check-app-label: 'validation error: You must set the label `app` on all
Deployments. rule check-app-label failed at path /metadata/labels/app/'Add the app label to the Deployment's metadata and it is admitted successfully.
Both examples enforce exactly the same rule — "every Deployment must carry an app label." Gatekeeper expresses it as a reusable Rego template plus a constraint that parameterises it; Kyverno expresses it as one declarative YAML pattern. That contrast is the whole decision in miniature.
For simple, general-purpose policies — label hygiene, resource limits, image-registry allow-lists — Kyverno is usually the faster path: familiar YAML, built-in policies, and a single manifest to apply. Its support for mutating, generating, and image-verification rules also covers a broad range of platform needs out of the box.
When you need complex, expressive logic — or you want one policy engine that spans Kubernetes and other systems — Gatekeeper and the full power of Rego are hard to beat. The cost is a steeper learning curve and the template-plus-constraint model.
Both are excellent, CNCF-backed tools with real trade-offs. Pick based on your team's Rego appetite and the complexity of the policies you actually need to enforce — and remember, there's nothing stopping you from running both for different jobs.
BootLabs designs and operates secure, policy-driven Kubernetes platforms for enterprises. If you're standing up policy-as-code guardrails on your clusters, our platform team can help you get it right.
Talk to our platform engineering team — we'll help you design admission policies, secure your Kubernetes estate, and automate compliance from day one.