Join our Newsletter — 33% off our NHI Course
Home› Guides› Kubernetes Admission Control Guide: OPA Gatekeeper and Kyverno
Guide Cloud Security

Kubernetes Admission Control Guide: OPA Gatekeeper and Kyverno

PDF for newsletter subscribers · free to read online

← All guides
By Lalit Choda, NHI Mgmt Group Updated 24 October 2026 14 min read
On this page

Kubernetes RBAC decides who may create a pod, but not what that pod may contain, so without admission control any user or service account allowed to deploy can run a privileged container from any registry. Admission control is the policy checkpoint inside the API server that inspects every create and update request after authentication and authorisation, and can reject or modify it before it is stored. This guide explains how the admission chain works, compares the built-in options (Pod Security Admission and ValidatingAdmissionPolicy with CEL) with the two main open source policy engines, OPA Gatekeeper and Kyverno, and covers failure policies, exemptions, rollout, measurement and the bypasses attackers look for. It is written for platform engineers and security architects who own cluster guardrails. Wider cluster hardening is in the Kubernetes Security Guide, and permissions in the Kubernetes RBAC Guide.

Key takeaways

  • Admission is the only place to enforce what is deployed. It runs after RBAC on every write to the API, so it can block privileged pods, untrusted images and missing controls regardless of who submits them.
  • Start with what is built in. Pod Security Admission (stable since v1.25) covers pod hardening, and ValidatingAdmissionPolicy (stable since v1.30) runs CEL rules in the API server with no webhook to keep alive.
  • Gatekeeper and Kyverno add what CEL alone does not. Audit of existing resources, mutation, generation, image signature verification, reporting and policy libraries; both can now generate ValidatingAdmissionPolicies from their own policies.
  • Failure policy is a security decision. A webhook that fails open (Ignore) silently stops enforcing when it is down; Gatekeeper's webhook defaults to fail open, Kyverno's to fail closed.
  • Exemptions are the attack surface. Excluded namespaces, ignore labels and broad exceptions are where policy is bypassed, so they need owners, review and alerting.

How the admission chain works

A request to the API server passes authentication, then authorisation (RBAC), then admission, and only then is persisted to etcd. Admission runs in two phases: mutating controllers first, then validating controllers. If any controller in either phase rejects the request, the whole request is rejected. Admission applies to create, update and delete requests and some connect requests such as pods/exec; it does not apply to reads.

There are four extension points, all enabled by default in current Kubernetes releases:

Extension pointPhaseHow it worksNotes
MutatingAdmissionWebhookMutatingAPI server calls an external HTTPS service with an AdmissionReview and applies the returned patchUsed by Gatekeeper mutation, Kyverno mutate rules, sidecar injectors
MutatingAdmissionPolicyMutatingCEL mutations in the API server, as an apply configuration or JSON patchNewer feature; check its maturity and feature gate in your Kubernetes version before relying on it
ValidatingAdmissionPolicyValidatingCEL expressions evaluated in-process in the API serverStable since v1.30; no network call, so it can fail closed without availability risk from a webhook
ValidatingAdmissionWebhookValidatingExternal service returns allowed or denied, optionally with warningsUsed by Gatekeeper and Kyverno validation; sees the object after all mutations

Compiled-in controllers also matter for security. PodSecurity, ServiceAccount, LimitRanger and ResourceQuota are on by default. NodeRestriction (limits what a kubelet can modify), AlwaysPullImages (forces image pulls so cached private images cannot be reused without credentials), EventRateLimit and DenyServiceExternalIPs must be enabled with --enable-admission-plugins. Managed Kubernetes services decide this list for you, so check what your provider enables.

Built-in options: Pod Security Admission and ValidatingAdmissionPolicy

Pod Security Admission

Pod Security Admission enforces the three Pod Security Standards (privileged, baseline, restricted) per namespace using labels of the form pod-security.kubernetes.io/<mode>: <level>, with an optional <mode>-version label to pin the standard to a Kubernetes version.

  • Modes: enforce rejects violating pods; audit adds an annotation to the audit log event; warn returns a warning to the client. A namespace can set different levels per mode, for example enforce baseline while warning on restricted.
  • Workload resources: audit and warn are applied to Deployments, Jobs and other workload objects, but enforce applies only to the resulting pods. A non-compliant Deployment is accepted and its pods then fail, which shows up in ReplicaSet events, not in kubectl apply output.
  • Exemptions: configured statically in the API server's AdmissionConfiguration by usernames, runtimeClassNames or namespaces. Exempt requests skip all three modes, and the metric pod_security_exemptions_total counts them.
  • Limits: fixed rule sets only, no registry or label rules, no mutation, and namespace labels can be changed by anyone with update rights on the namespace.

ValidatingAdmissionPolicy

A ValidatingAdmissionPolicy holds CEL validations, optional matchConditions, variables, messageExpression and auditAnnotations. A ValidatingAdmissionPolicyBinding attaches it to resources and chooses validationActions: Deny, Warn or Audit (Deny and Warn cannot be combined). Policies can be parameterised with paramKind and a binding's paramRef, whose parameterNotFoundAction must be set. Because evaluation is in-process, a failurePolicy: Fail policy does not depend on an external service, and CEL has cost limits that stop runaway expressions.

What it does not do on its own: audit resources that already exist, mutate (that is MutatingAdmissionPolicy), look up other cluster objects beyond its parameters, verify image signatures or produce compliance reports.

OPA Gatekeeper and Kyverno compared

Both engines are CNCF projects that run as admission webhooks plus background controllers. They differ mainly in policy language and in how much beyond validation they do.

CapabilityOPA GatekeeperKyverno
Policy modelConstraintTemplate (logic and parameter schema) plus Constraint instances (match scope and parameters)ClusterPolicy or Policy with rules, plus newer CEL-based kinds such as ValidatingPolicy, MutatingPolicy, GeneratingPolicy, DeletingPolicy and ImageValidatingPolicy
LanguageRego; CEL in templates via the K8sNativeValidation engine (stable since Gatekeeper v3.18)YAML patterns (pattern, anyPattern, deny, foreach), JMESPath, CEL
Enforcement modesenforcementAction: deny (default), dryrun, warn, or scoped with per-enforcement-point actionsPer-rule failureAction: Enforce or Audit, with failureActionOverrides per namespace (the older validationFailureAction field is deprecated); emitWarning for audit warnings
Audit of existing resourcesPeriodic audit, every 60 seconds by default, results in constraint statusBackground scans producing PolicyReport and ClusterPolicyReport resources
Mutation and generationMutation CRDs (Assign, AssignMetadata, ModifySet); no generationMutate (including existing resources), generate (for example default NetworkPolicies per namespace), cleanup
Image verificationThrough external data providersBuilt-in verify image rules for Sigstore and Notary signatures and attestations
Native VAP integrationGenerates ValidatingAdmissionPolicies from CEL templates (beta in v3.20, enabled by default)ValidatingPolicy can generate a ValidatingAdmissionPolicy via autogen.validatingAdmissionPolicy.enabled
Testing toolsgator CLI (gator verify, gator test)Kyverno CLI to apply and test policies against manifests
Default webhook failure policyIgnore (fail open); can be changed to FailFail (fail closed); forceFailurePolicyIgnore switches to fail open

Choosing between them

  • Built-in only: small clusters or a single team, where Pod Security Admission at restricted plus a handful of CEL policies (allowed registries, required labels) covers the need with nothing extra to operate.
  • Gatekeeper: organisations already using OPA and Rego elsewhere (API authorisation, Terraform checks), who want one policy language across systems and strong separation between policy logic and parameters.
  • Kyverno: platform teams who want policies written as Kubernetes YAML, need mutation, generation or image signature verification in the same tool, and want reports as Kubernetes resources.
  • Large and multi-cluster estates: standardise on one engine, distribute policy through GitOps, and push simple, high-volume checks down to ValidatingAdmissionPolicy where possible, keeping the webhook for checks CEL cannot express.

Running two engines on the same resources is possible but doubles the latency, failure modes and places to look when a deployment is rejected.

Policies that matter most

PolicyThreat addressedATT&CK v20
Images only from approved registries, by digest, with valid signaturesMalicious or implanted imagesT1204.003 Malicious Image, T1525 Implant Internal Image
No privileged containers, host namespaces, hostPath or dangerous capabilitiesEscape from container to nodeT1611 Escape to Host
Restrict who can create pods in system namespaces and block new privileged DaemonSetsAttacker-deployed workloadsT1610 Deploy Container, T1543.005 Container Service
Restrict CronJob and Job creation outside approved namespacesScheduled persistenceT1053.007 Container Orchestration Job
Deny bindings to cluster-admin and wildcard roles except from the platform pipelinePrivilege escalation through RBACT1098.006 Additional Container Cluster Roles
Require resource limits and deny unexpected nodeSelector to GPU poolsCryptomining on cluster capacityT1496.001 Compute Hijacking
Deny environment variables that look like static cloud keys; require automountServiceAccountToken: false unless annotatedCredential theft from podsT1552.007 Container API

The Kubeflow cryptomining attacks illustrate the first and third rows: attackers created notebook servers running an image from a public repository and used a mounted service account to deploy miners. An allowed-registry policy and a rule that notebook namespaces cannot create arbitrary workloads would have blocked both routes. The Tesla Kubernetes cryptojacking case, where a pod held AWS credentials, is the argument for the last row. Pair these with the Container Image Security Guide for signing, and the Helm Security Guide for chart-level checks.

Webhook reliability and failure policy

  • failurePolicy: Fail rejects requests when the webhook cannot be reached, times out or returns a malformed response; Ignore lets them through. The Kubernetes default for a webhook configuration is Fail, but Gatekeeper ships its validating webhook as Ignore. An explicit denial always blocks, whatever the failure policy.
  • Timeouts: the default webhook timeout is 10 seconds. Shorter timeouts (Gatekeeper's fail-closed example uses 3 seconds; Kyverno's webhookTimeout accepts 1 to 30) limit how long a slow engine can stall every deployment.
  • Scope: use namespaceSelector, objectSelector, rules and CEL matchConditions (up to 64 per webhook) so the webhook sees only what it needs. Excluding the engine's own namespace prevents a deadlock where the engine cannot restart because its own webhook rejects its pods.
  • Availability: run multiple replicas across zones with a PodDisruptionBudget and a high priority class, and alert on webhook latency and rejection errors in API server metrics.
  • Side effects and mutation order: declare sideEffects: None where true, make mutating webhooks idempotent, and do security validation in a validating webhook or policy, which sees the final object after all mutations. reinvocationPolicy: IfNeeded lets a mutating webhook run again if later plugins change the object.

The decision is a trade-off: fail closed for production namespaces where an unchecked privileged pod is worse than a delayed deployment, with fail-open or narrower scope for system components that must always be able to start. Moving critical checks to ValidatingAdmissionPolicy removes the dilemma for those checks, which is a major reason both engines now generate VAPs.

Common bypasses and failure patterns

  • Fail-open during an outage: with failurePolicy: Ignore, deleting or overloading the policy engine pods turns enforcement off. Audit catches the result later, not at admission time. Alert on engine pod restarts and on webhook configuration changes.
  • Exemption labels and namespaces: Gatekeeper's admission.gatekeeper.sh/ignore namespace label and Kyverno's default exclusion of kube-system and its own namespace are needed for stability, but anyone who can label a namespace or deploy into an excluded one bypasses policy. Gatekeeper requires the matching --exempt-namespace flag before it honours the label for this reason; restrict namespace update rights with RBAC.
  • Policy on pods only: rules written for Pod but not for Deployments, Jobs and CronJobs give late, confusing failures, and rules written only for controllers miss bare pods. Use Kyverno autogen, Gatekeeper expansion or match both.
  • Webhook configuration as a target: an identity that can edit ValidatingWebhookConfiguration or delete a policy can remove the control entirely. Treat those permissions as cluster-admin equivalent and monitor them in the audit log.
  • Audit mode forever: policies deployed in dryrun, warn or Audit to avoid breaking teams, then never promoted to enforcement, produce reports nobody acts on.
  • Mutable tags: allowing registry/app:latest from an approved registry still lets the image change after review. Require digests or signature verification.

How to implement

  1. Baseline the cluster: label every namespace with Pod Security Admission warn and audit at restricted, and read the audit annotations and client warnings for two weeks to find non-compliant workloads.
  2. Enforce built-in standards: set enforce: baseline on all application namespaces, then restricted where workloads comply. Rollback is removing or downgrading one namespace label.
  3. Choose and install the engine: if Gatekeeper or Kyverno is needed, install with multiple replicas, exclude its own namespace, and keep every policy in audit or dry-run mode at first (enforcementAction: dryrun or failureAction: Audit).
  4. Test policies as code: store policies in Git, run gator verify or the Kyverno CLI against known-good and known-bad manifests in CI, and run the same checks against Helm and Kustomize output before it reaches the cluster.
  5. Promote to enforcement by ring: warn first so developers see messages at deploy time, then enforce in development clusters, then one production cluster, then all. Each step needs a named owner and an exception process.
  6. Decide failure policy explicitly: document fail-closed or fail-open per webhook, test it by scaling the engine to zero in a staging cluster, and confirm the result matches the decision.
  7. Govern exceptions: use scoped exception resources with an owner and expiry date rather than namespace-wide exclusions, and review them quarterly.

Detection and measurement

  • Policy coverage: percentage of namespaces with Pod Security Admission enforce labels and percentage of the agreed policy set in enforce mode.
  • Open violations: count of existing resources failing policy (Gatekeeper constraint status, Kyverno PolicyReports), trending down.
  • Exemption count and age: number of exempt namespaces, users and exceptions, and how many are past their expiry date; track pod_security_exemptions_total.
  • Webhook health: admission webhook latency, timeout and rejection rates from API server metrics; any period where an Ignore webhook was unavailable is an enforcement gap.
  • Time to enforce: days from a policy entering audit mode to enforcement.

In the Kubernetes audit log, watch for changes to validatingwebhookconfigurations, mutatingwebhookconfigurations, validatingadmissionpolicies and their bindings, constraint and policy deletions, and namespace label changes on pod-security.kubernetes.io/* or ignore labels. Gatekeeper's --log-denies flag logs every deny, dry-run and warn result for SIEM ingestion. Runtime detection is the backstop when admission is bypassed; see the Container Runtime Security Guide.

Where identity fits

Admission control is also an identity control for workloads. Policies can require that pods use a dedicated service account rather than default, disable token automounting where the API is not used, block static cloud keys in specs and enforce that workload identity annotations point only to approved cloud roles. The policy engines themselves are high-value non-human identities: their service accounts can read most cluster objects, and in Kyverno's case generate and mutate resources, so scope their RBAC tightly. See the Kubernetes NHI Security Guide.

Framework mapping

FrameworkReferenceHow admission control supports it
NIST CSF 2.0PR.PS-01, PR.PS-05, PR.AA-05, GV.PO-01Configuration management enforced at deploy time; blocking unauthorised software; enforcing access policy; policy established and enforced
NIST SP 800-53 Rev. 5CM-2, CM-3, CM-6, CM-7, CM-14, SI-7, AC-6Baselines; change control; configuration settings; least functionality; signed components; integrity; least privilege
NIST SP 800-190Orchestrator and image countermeasuresControls on which images may run and how workloads are configured
CIS Controls v8.1Control 2, Control 4Inventory and control of software assets; secure configuration
ISO/IEC 27001:2022 Annex AA.8.9, A.8.19, A.8.32Configuration management; installation of software on operational systems; change management
MITRE D3FENDD3-EALExecutable allowlisting applied to container images

Practitioner checklist

  • Label every namespace with Pod Security Admission levels, enforcing at least baseline and restricted wherever workloads comply.
  • Confirm which admission plugins your API server or managed service enables, including NodeRestriction.
  • Use ValidatingAdmissionPolicy for simple, high-volume checks and a policy engine only for what CEL cannot do.
  • Enforce approved registries, image digests or signatures, and no privileged or host-namespace pods.
  • Set and test each webhook's failurePolicy deliberately; run engines highly available with tight timeouts.
  • Treat webhook configurations, policies and namespace label rights as privileged, and alert on changes.
  • Keep policies in Git with CI tests using gator or the Kyverno CLI.
  • Promote policies from warn or audit to enforce on a dated plan, ring by ring.
  • Replace namespace-wide exclusions with scoped, expiring exceptions that have owners.

Standards and references

Related NHI Mgmt Group resources: Kubernetes Security Guide · Kubernetes RBAC Guide · Container Security Buyer's Guide · Top 10 Kubernetes Security Risks · Helm Security Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 24 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.