Generate ValidatingAdmissionPolicies

Generate Kubernetes ValidatingAdmissionPolicies based on validate.cel subrules.

Kubernetes ValidatingAdmissionPolicy was first introduced in 1.26, and it’s not fully enabled by default as of Kubernetes versions up to and including 1.28. While it provides a declarative, in-process option for validating admission webhooks and uses the Common Expression Language (CEL) to perform resource validation checks directly in the API server, it falls short of the features that can be provided by Kyverno policies. Kyverno policies are capable of performing complex validation, mutation, generation, image verification, reporting, and off-cluster validation, whereas ValidatingAdmissionPolicies cannot. Since it is important to unify the policy management used in clusters, Kyverno policies can be used to generate Kubernetes ValidatingAdmissionPolicies. This feature allows the process of resource validation to take place in the API server instead.

Because Kyverno can be used to generate ValidatingAdmissionPolicies and their bindings it is necessary to grant the Kyverno admission controller’s ServiceAccount additional permissions. To enable Kyverno to generate these types, see the section on customizing permissions. Kyverno will assist you in these situations by validating and informing you if the admission controller does not have the level of permissions required at the time the policy is installed.

To generate ValidatingAdmissionPolicies, make sure to:

  1. enable ValidatingAdmissionPolicy feature gate.
  2. enable either admissionregistration.k8s.io/v1alpha1 or admissionregistration.k8s.io/v1beta1 API depending on the version of Kubernetes you are running.

The ValidatingAdmissionPolicies can only be generated from the validate.cel subrules in Kyverno policies. Refer to the CEL subrule section on the validate page for more information.

Below is an example of a Kyverno policy that can be used to generate a ValidatingAdmissionPolicy and its binding:

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: disallow-host-path
 5spec:
 6  validationFailureAction: Enforce
 7  background: false
 8  rules:
 9    - name: host-path
10      match:
11        any:
12        - resources:
13            kinds:
14              - Deployment
15      validate:
16        cel:
17          expressions:
18            - expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
19              message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

Once the policy is created, it is possible to check whether there is a corresponding ValidatingAdmissionPolicy was generated under the status object.

1status:
2  validatingadmissionpolicy:
3    generated: true
4    message: ""

The generated ValidatingAdmissionPolicy:

 1apiVersion: admissionregistration.k8s.io/v1beta1
 2kind: ValidatingAdmissionPolicy
 3metadata:
 4  labels:
 5    app.kubernetes.io/managed-by: kyverno
 6  name: disallow-host-path
 7  ownerReferences:
 8  - apiVersion: kyverno.io/v1
 9    kind: ClusterPolicy
10    name: disallow-host-path
11spec:
12  failurePolicy: Fail
13  matchConstraints:
14    matchPolicy: Equivalent
15    namespaceSelector: {}
16    objectSelector: {}
17    resourceRules:
18    - apiGroups:
19      - apps
20      apiVersions:
21      - v1
22      operations:
23      - CREATE
24      - UPDATE
25      resources:
26      - deployments
27      scope: '*'
28  validations:
29  - expression: '!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume,
30      !has(volume.hostPath))'
31    message: HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath
32      must be unset.

The generated ValidatingAdmissionPolicyBinding:

 1apiVersion: admissionregistration.k8s.io/v1beta1
 2kind: ValidatingAdmissionPolicyBinding
 3metadata:
 4  labels:
 5    app.kubernetes.io/managed-by: kyverno
 6  name: disallow-host-path-binding
 7  ownerReferences:
 8  - apiVersion: kyverno.io/v1
 9    kind: ClusterPolicy
10    name: disallow-host-path
11spec:
12  policyName: disallow-host-path
13  validationActions:
14  - Deny

Both the ValidatingAdmissionPolicy and its binding have the same naming convention as the Kyverno policy they originate from, with the binding having a “-binding” suffix.

If there is a request to create the following deployment given the generated ValidatingAdmissionPolicy above, it will be denied by the API server.

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: nginx
 5spec:
 6  replicas: 2
 7  selector:
 8    matchLabels:
 9      app: nginx
10  template:
11    metadata:
12      labels:
13        app: nginx
14    spec:
15      containers:
16      - name: nginx-server
17        image: nginx
18        volumeMounts:
19          - name: udev
20            mountPath: /data
21      volumes:
22      - name: udev
23        hostPath:
24          path: /etc/udev

The response returned from the API server.

1The deployments "nginx" is invalid:  ValidatingAdmissionPolicy 'disallow-host-path' with binding 'disallow-host-path-binding' denied request: HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset.

The generated ValidatingAdmissionPolicy with its binding is totally managed by the Kyverno admission controller which means deleting/modifying these generated resources will be reverted. Any updates to Kyverno policy triggers synchronization in the corresponding ValidatingAdmissionPolicy.

Last modified December 01, 2023 at 3:31 PM PST: add docs for validate.cel subrule (#1005) (caa8553)