PRACTITIONER GUIDE
Practitioner Guide11 min read

OPA Gatekeeper vs Kyverno: Kubernetes Policy Enforcement for Security and Compliance

Validating
admission webhook type used by both Gatekeeper and Kyverno to reject non-compliant Kubernetes resources before they are persisted to etcd, enforcing policies at the API server layer
Rego
OPA's policy language used by Gatekeeper ConstraintTemplates; a declarative query language with a learning curve but full Boolean logic for complex multi-condition security rules
warn
Kyverno enforcement action that allows the resource but adds a warning to the API response; used for gradual policy rollout before switching to the deny enforcement action that blocks creation
Audit mode
Gatekeeper feature that continuously scans existing cluster resources against all active Constraints and reports violations for resources already running before the policy was deployed

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

The first time I deployed OPA Gatekeeper into a production Kubernetes cluster, I broke the cluster within 20 minutes. The admission webhook was configured with failurePolicy: Fail (the secure default), the Gatekeeper pods crashed due to a resource limit misconfiguration, and every new pod creation request was rejected by the API server because the webhook was unavailable. The lesson was not that Gatekeeper was wrong for the environment — it was that admission controllers require careful deployment sequencing, liveness probe configuration, and replica counts that prevent the enforcer from becoming a single point of failure.

Kyverno is gentler in its defaults and has a faster time-to-first-policy for teams new to Kubernetes policy enforcement. Gatekeeper provides more expressive power for complex organizational policies that Rego handles better than Kyverno's YAML pattern matching. Both tools deployed with their community policy libraries produce a Kubernetes environment where security requirements are enforced at the API layer rather than hoped for in CI/CD pipeline documentation.

Kyverno: policy-as-YAML for fast Kubernetes security enforcement

Kyverno's primary advantage over Gatekeeper is that its policies are ordinary Kubernetes YAML resources — security engineers who know Kubernetes can write their first policy in minutes without learning a new programming language. The policy structure mirrors the resources it validates: the match block uses the same selector syntax as Kubernetes NetworkPolicy, the validate block uses the same field paths as kubectl describe, and the test framework uses the same resource format as kubectl apply. This familiarity dramatically reduces the time from policy idea to deployed enforcement.

Deploy Kyverno with three replicas and PodDisruptionBudgets to prevent admission webhook outages

Install Kyverno with helm install kyverno kyverno/kyverno --namespace kyverno --create-namespace --set replicaCount=3 to run three webhook replicas and ensure admission requests can be served if one replica is unavailable during node maintenance or rolling updates. Add a PodDisruptionBudget that requires at least two replicas available: spec.minAvailable: 2 targeting the kyverno pods. Set the webhook failurePolicy to Ignore on non-production clusters during initial policy development to prevent a Kyverno pod failure from blocking all workload changes — switch to Fail on production clusters after policies are validated. Without three replicas and a PDB, a single Kyverno pod failure during node drain can prevent any new pods from being scheduled until the Kyverno pod is replaced, creating a cluster-wide scheduling outage.

Use Kyverno generate rules to automatically create NetworkPolicies in new namespaces

Kyverno generate rules solve one of Kubernetes' most common security gaps: new namespaces are created without NetworkPolicies, leaving pods open to unrestricted cluster-internal traffic until someone manually adds policies. Write a generate ClusterPolicy that triggers on namespace creation and automatically creates a default-deny NetworkPolicy in the new namespace: spec.rules with a generate rule that selects Namespace resources and generates a NetworkPolicy resource in the same namespace using a fixed policy spec that denies all ingress and egress traffic. Every new namespace receives a default-deny policy automatically, and teams must explicitly add NetworkPolicies that allow required traffic — the zero-trust networking baseline is enforced without requiring developers to remember the requirement.

OPA Gatekeeper: Rego-powered policies for complex organizational requirements

Gatekeeper's strength is Rego's expressiveness for policies that require multi-condition logic, cross-resource data lookups, or parameterized rules that are instantiated with different values across different namespaces. A ConstraintTemplate that blocks images from unauthorized registries and accepts a registry allowlist as a Constraint parameter can be deployed once and instantiated with different allowlists for production, staging, and development namespaces without duplicating the policy logic. This parameterization makes Gatekeeper well-suited for large organizations with different security tiers across namespace groups.

Write a parameterized Gatekeeper ConstraintTemplate to restrict container images to approved registries

Create a ConstraintTemplate for image registry enforcement that accepts an allowedRegistries list as a Constraint parameter, enabling the same template to enforce different registry policies for different namespace groups. The Rego violation rule iterates over containers: container := input.review.object.spec.containers[_] and checks whether the container image prefix matches any entry in input.parameters.allowedRegistries. If no allowed registry prefix matches, the violation fires with a message specifying the disallowed image and the allowed registries. Deploy the template, then instantiate it with a production Constraint using allowedRegistries: [company-registry.example.com/prod/] and a development Constraint using allowedRegistries: [company-registry.example.com/dev/, docker.io/] — developers get more flexibility in dev namespaces while production workloads are restricted to the internal registry.

Configure Gatekeeper external data providers to validate images against a real-time vulnerability feed

Gatekeeper's external data provider (ExternalData) feature allows Rego policies to make synchronous HTTP calls to external services during admission evaluation, enabling policies that check a real-time database rather than static parameters. Configure an external data provider that calls a vulnerability API with the image digest and returns a block/allow verdict based on current CVE severity. The Rego policy makes an external_data call with the image reference, receives the API response, and fires a violation if the response indicates the image contains unacceptable CVEs. This approach enables admission-time vulnerability enforcement — a pod trying to deploy a newly discovered critical-CVE image is blocked at the API server — but requires careful latency management since external calls add to admission webhook response time. Set a timeout of 2-3 seconds on the external data provider and configure the Constraint's failurePolicy to handle provider outages without blocking all admission requests.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

The bottom line

OPA Gatekeeper and Kyverno both enforce Kubernetes security policies as admission controllers, but they suit different teams and requirements. Kyverno's YAML-native policy syntax and generate rules make it the faster choice for teams new to admission control who need common security policies deployed within hours. Gatekeeper's Rego language provides the expressiveness needed for parameterized, multi-condition policies in organizations with complex security tiering requirements. Deploy either tool with three replicas and PodDisruptionBudgets to prevent the admission webhook from becoming a single point of failure. Start with community policy libraries (Kyverno Policies or Gatekeeper Policy Library) to cover the standard Kubernetes security baseline immediately, then add application-specific policies over time. Use audit mode or warn enforcement to discover existing violations before switching to deny, so the first production enforcement run does not cause unexpected disruption.

Frequently asked questions

Should I use OPA Gatekeeper or Kyverno for Kubernetes policy enforcement?

Choose Kyverno if your team prefers native Kubernetes YAML syntax and needs faster policy authoring — Kyverno policies are Kubernetes resources written in YAML with familiar field selectors and no new language to learn. Kyverno also supports generate rules (automatically create ConfigMaps, NetworkPolicies, or RoleBindings in new namespaces) and has built-in image verification and mutating rules that Gatekeeper requires additional tooling for. Choose OPA Gatekeeper if your organization already uses OPA elsewhere (infrastructure policy as code with Terraform or Conftest) and wants a unified policy language across environments, or if your policies require complex multi-resource logic that benefits from Rego's full query capabilities. In practice, Kyverno has faster policy iteration for the most common Kubernetes security use cases (require non-root, require resource limits, block privileged containers), while Gatekeeper provides more expressive power for multi-condition policies that cross-reference multiple resource types. Either tool deployed with community policy libraries covers 90% of Kubernetes security requirements.

How do I write a Kyverno ClusterPolicy to require non-root containers?

Write a Kyverno ClusterPolicy that validates all pods in non-system namespaces require non-root container security context. The policy uses apiVersion: kyverno.io/v1, kind: ClusterPolicy, with a spec.rules section containing a validate rule named require-non-root-user. The match block selects resources with kinds: [Pod] in any namespace. The validate block uses the pattern field to specify that containers[*].securityContext.runAsNonRoot must be true: pattern.spec.containers[*].securityContext.runAsNonRoot: true. Add a second condition for initContainers: pattern.spec.initContainers[*].securityContext.runAsNonRoot: true. Set spec.validationFailureAction to Enforce for hard blocking or Audit to log violations without blocking. Test locally with kyverno test . before deploying to the cluster. Add a namespace exclusion in the match.exclude block for kube-system and kyverno namespaces to avoid breaking system components that require root.

How do I write a Gatekeeper ConstraintTemplate to block privileged containers?

Write a Gatekeeper ConstraintTemplate that defines the policy logic in Rego, then deploy a Constraint resource that instantiates the template and targets the resource scope. The ConstraintTemplate defines spec.crd.spec.names.kind as BlockPrivilegedContainers and the spec.targets Rego logic: violation[{msg}] { container := input.review.object.spec.containers[_]; container.securityContext.privileged == true; msg := sprintf('Container %v is privileged. Privileged containers are not allowed.', [container.name]) }. Add a second violation rule for initContainers using input.review.object.spec.initContainers[_]. Deploy the template, then deploy the Constraint resource with kind: BlockPrivilegedContainers, metadata.name: no-privileged-containers, spec.match.kinds selecting Pod resources, and spec.enforcementAction set to deny. Verify the constraint is active with kubectl get blockprivilegedcontainers and test by attempting to deploy a pod with securityContext.privileged: true — it should be rejected with the custom violation message.

How do I use Kyverno mutating policies to automatically add required security labels?

Use Kyverno mutating ClusterPolicies to automatically add required security context fields that developers commonly omit rather than blocking the entire deployment. A mutate policy that adds readOnlyRootFilesystem: true and allowPrivilegeEscalation: false to all containers uses spec.rules with a mutate rule type: the patchStrategicMerge block specifies spec.containers[*].securityContext.readOnlyRootFilesystem: true and spec.containers[*].securityContext.allowPrivilegeEscalation: false. Kubernetes will merge these fields into any pod spec that does not already set them, without overriding values that the application explicitly sets. Mutating policies run before validating policies, so you can chain them: a mutate policy adds default security context fields, and a validate policy then checks that all required fields are present (catching cases where the mutation did not apply due to explicit false values). This approach reduces developer friction compared to blocking deployments for missing security context fields while still ensuring all running pods have the required security posture.

How do I test Kyverno policies locally before deploying to a cluster?

Test Kyverno policies locally using the kyverno test command, which evaluates policy rules against test resource files without requiring a running Kubernetes cluster. Create a test directory containing your ClusterPolicy YAML, a test manifest file (the resource to test), and a kyverno-test.yaml file that defines test cases with their expected results. The kyverno-test.yaml specifies policies (list of policy file paths), resources (list of test resource file paths), and results (expected rule results: pass or fail for each rule-resource combination). Run kyverno test . from the directory to execute all test cases — it reports pass/fail for each expected result. Add a CI/CD pipeline step that runs kyverno test on the policy directory to catch policy syntax errors and logic mistakes before deployment. For Gatekeeper, use conftest with the gatekeeper rego policies directly: conftest test pod.yaml --policy policies/ evaluates the resource YAML against the Rego policy files and reports violations.

How do I use Gatekeeper audit mode to find existing policy violations in the cluster?

Gatekeeper audit mode automatically scans all existing resources in the cluster against active Constraints and populates the Constraint status field with violation details for resources that do not comply with the policy. After deploying a new Constraint, wait for the audit cycle to complete (default 60 seconds) and check violations with kubectl get constraint constraint-name -o yaml which shows the status.violations field listing each non-compliant resource's namespace, name, message, and enforcement action. For a comprehensive view across all constraints, run kubectl get k8sconstrainttemplates -A and then describe each active constraint: resources that existed before the constraint was deployed will appear in the audit violations even though they were not blocked at creation time. This gives security teams a full inventory of existing policy violations to remediate, rather than discovering them only when those resources are next updated. Configure the auditInterval in the Gatekeeper helm chart values to control how frequently the audit cycle runs.

How do I handle exceptions for specific workloads that legitimately need privileged access?

Handle policy exceptions for legitimate privileged workloads using Kyverno's PolicyException resource, which grants named resources explicit exclusions from specific policy rules without modifying the policy itself. Create a PolicyException resource in the namespace of the excepted workload: spec.exceptions lists the policy name and rule names to exclude, and spec.match selects the specific deployment or daemonset by name and namespace. For DaemonSets that require host access (log collectors like Fluentd, security agents like Falco), create a PolicyException in the kube-system or monitoring namespace referencing the specific workload name. In OPA Gatekeeper, handle exceptions by adding exclusion conditions to the Constraint's spec.match.excludedNamespaces list (namespace-level exclusions) or by adding a match.scope condition in the Rego template that skips resources with specific labels (resource-level exclusions). Document every exception with a business justification and scheduled review date — a growing list of undocumented exceptions is a sign that policy is not calibrated to the environment's actual security requirements.

Sources & references

  1. OPA Gatekeeper Documentation
  2. Kyverno Documentation
  3. Kyverno Policy Library
  4. Gatekeeper Policy Library

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.