What is Kubernetes Validating Admission Policy?
Updated Ritesh Patel

What is Kubernetes Validating Admission Policy?
A Kubernetes ValidatingAdmissionPolicy is a built-in way to validate API requests at admission without running a webhook. You write the validation rules in Common Expression Language (CEL) in a ValidatingAdmissionPolicy resource, then attach it to resources with a ValidatingAdmissionPolicyBinding. The API server evaluates the rules in-process and rejects requests that fail.
Validating Admission Policy was introduced in Kubernetes 1.26 as a declarative, in-process alternative to dynamic admission webhooks. Before it, custom validation of Kubernetes API requests required dynamic admission webhooks. This post explains CEL, shows how a policy and its binding validate resources, and covers where the approach falls short.
How does Common Expression Language work in a policy?
Common Expression Language (CEL) is an open-source, non-Turing complete language that implements common semantics for expression evaluation. Kubernetes first used CEL for validation rules in CustomResourceDefinitions. Validating Admission Policies adopted it in version 1.26. The syntax is simple and close to expressions in C, C++, Java, JavaScript and Go.
With CEL expressions you can do the following:
- Define policies that take into account multiple fields and values in a resource, and make decisions based on the outcome of those conditions.
- Use logical operators, comparison operators, and custom functions to create policies that are easier to read and understand.
- Define your own custom functions and operators, which can be used to customize the behavior of your policies.
Here is an example of a CEL expression:
self.health.startsWith('ok')
The above expression validates a ‘health’ string field has the prefix ‘ok’
What resources make up a Validating Admission Policy?
A Validating Admission Policy lets policy authors write policies that cluster administrators can parameterize and scope to the resources they care about. The policy logic and its scope live in separate objects, so one policy can be bound in different ways across a cluster.
| Resource | Required | What it does |
|---|---|---|
| ValidatingAdmissionPolicy | Yes | Defines the logic of the policy using CEL |
| ValidatingAdmissionPolicyBinding | Yes | Connects the policy to a scope (e.g. Pod or Secret) |
| Parameter resource | No | Provides additional information to a ValidatingAdmissionPolicy |
If a ValidatingAdmissionPolicy doesn’t need to be configured through parameters, leave spec.paramKind unset in the policy.
Example: limiting Deployment replicas
Here is an example of a Validating Admission Policy. This policy limits the number of replicas in a Deployment to three or less.
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingAdmissionPolicy
metadata:
name: "limit-replicas-policy"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= 3"
message: "Deployment should not use more than 3 replicas"
This policy can be applied to specific resources by creating the Validating Admission Policy Binding. In the example below, the policy will be applied to deployments in namespaces that have the label “environment=test”
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "limit-replicas-policy"
spec:
policyName: "demo-policy.example.com"
validationActions: [Deny]
matchResources:
namespaceSelector:
matchLabels:
environment: test
Once, this policy and its binding are added, if a user tries to create a deployment with replicas greater than three in any namespace with environment label set to “test”, the request will be denied with the message “Deployment should not use more than 3 replicas”
What are the limitations of ValidatingAdmissionPolicy?
- VAP can be very effective in performing simple validation checks at admission without requiring additional admission controllers.
- CEL is easy to learn and flexible for simple policies but writing more complex policies could be challenging.
- More advanced validation checks such as image signature verification, or checks which require API lookups, are not possible.
- Since ValidatingAdmissionPolicy focuses on validation checks, a different solution is required for policies that mutate and generate resources.
- Managing multiple policy resources (ValidatingAdmissionPolicy, ValidatingAdmissionPolicyBindings) introduces some overhead and requires automation. Nirmata Control Hub for Kubernetes policy management can be instrumental here.
- Currently ValidatingAdmissionPolicy can make “allow” or “deny” decisions but in case the policy requirements change the new policy cannot be applied to existing cluster resources.
- Policy exception management is not very straightforward, as it requires managing bindings or creating multiple policies
- Policy reports for ValidatingAdmissionPolicy are not available.
- ValidatingAdmissionPolicy cannot be applied in a CI/CD pipeline via a CLI.
When should you use ValidatingAdmissionPolicy?
Writing validation checks with ValidatingAdmissionPolicy is easy, and CEL is quick to learn and flexible. Using ValidatingAdmissionPolicy to validate configuration can reduce the dependency on external admission webhooks such as Kyverno and OPA/Gatekeeper. But there are also several scenarios that ValidatingAdmissionPolicy does not currently address and require external admission controllers. We will discuss these in an upcoming series of blog posts, and show how CNCF policy engines like Kyverno are adding support for ValidatingAdmissionPolicy. Two follow-ups are already out: applying ValidatingAdmissionPolicies with the Kyverno CLI and generating ValidatingAdmissionPolicies from Kyverno policies. For more on CEL in Kyverno, see using Kubernetes CEL in Kyverno policies.
Any questions on what we have covered in this post? Feel free to reach-out to Nirmata for more information.
Frequently asked questions
Is ValidatingAdmissionPolicy still in beta?
No. This post was written when the API was beta and used admissionregistration.k8s.io/v1beta1. ValidatingAdmissionPolicy became generally available in Kubernetes 1.30, where it is served as admissionregistration.k8s.io/v1 and enabled by default. On current clusters, write new policies and bindings against the v1 API and check the Kubernetes documentation for the fields your version supports.
What do the validationActions in a binding do?
The binding's validationActions field decides what happens when a validation fails. Deny rejects the request. Warn returns the failure to the client as a warning while letting the request through. Audit records the failure in the API server audit event. You can combine Warn and Audit, which is a practical way to roll out a new policy before switching it to Deny.
What happens if a CEL expression fails to evaluate?
The policy's failurePolicy field controls this. With failurePolicy set to Fail, as in the replica example, a request is rejected when the policy is misconfigured or its CEL expression errors at runtime. With Ignore, the error is skipped and the request is admitted. Fail is the safer default for security policies, while Ignore suits checks you would rather not have block deployments.
Can Kyverno work with ValidatingAdmissionPolicy?
Yes. The Kyverno CLI can apply ValidatingAdmissionPolicies to resource manifests, so you can test them in a CI pipeline before they reach a cluster. Kyverno can also generate ValidatingAdmissionPolicies and bindings from Kyverno policies that use CEL. That lets you keep one policy source while the API server runs the simple checks in-process and Kyverno handles mutation, generation and image verification.