Blog & Press Releases
Kubernetes Policy as Code DevSecOps

Gatekeeper vs Kyverno: Choosing a Kubernetes Policy Engine

BootLabs Engineering July 2023 6 min read
Kubernetes policy enforcement with Gatekeeper and Kyverno

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.

Side-by-Side Comparison

GatekeeperKyverno
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.

Key Points You Don't Want to Miss

  • Gatekeeper is a general-purpose OPA engine; Kyverno is Kubernetes-specific.
  • Gatekeeper supports validating webhooks; Kyverno supports validating, mutating, generating, and image-verification webhooks.
  • Gatekeeper can feel heavy for a simple policy; Kyverno is generally quicker to implement.
  • For genuinely complex custom rules, Rego (the language behind OPA/Gatekeeper) can express logic that is harder to model in Kyverno.
  • Kyverno applies policies in a single, straightforward manifest; Gatekeeper requires you to create CRDs — both a ConstraintTemplate and a Constraint.

Implementing Gatekeeper

Gatekeeper supports three installation methods.

Install from a release manifest
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml
Install with Helm
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper --name-template=gatekeeper \
  --namespace gatekeeper-system --create-namespace
Build & deploy HEAD with make
git 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_IMAGE

Once 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.

template.yaml — the reusable rule (in Rego)
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])
        }
constraint.yaml — apply the rule to Deployments
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: KubernetesValidatingLabel
metadata:
  name: require-deployment-labels
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
  parameters:
    labels:
      - app

Now try to create a Deployment that has a test label but no app label:

deploy.yaml — a non-compliant Deployment
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: 80

Applying 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"}

Implementing Kyverno

Installation is equally quick.

Install with Helm
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
Install from a release manifest
kubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.10.0/install.yaml
Test the latest unreleased code
kubectl create -f https://github.com/kyverno/kyverno/raw/main/config/install-latest-testing.yaml

With 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.

require-deployment-labels.yaml — a Kyverno ClusterPolicy
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.

Same policy, two philosophies

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.

Summary: Which Should You Choose?

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.

Put policy-as-code guardrails on your clusters.

Talk to our platform engineering team — we'll help you design admission policies, secure your Kubernetes estate, and automate compliance from day one.