Applying Validating Admission Policies using Kyverno CLI

Using Kyverno CLI to apply Validating Admission Policies

The Kyverno Command Line Interface (CLI) allows applying policies outside of Kubernetes clusters and can validate and test policy behavior prior to adding them to a cluster.

The two commands used for testing are apply and test:

  • The apply command is used to perform a dry run on one or more policies for the given manifest(s).
  • The test command is used to test a given set of resources against one or more policies to check the desired results defined in a special test manifest.

In this post, I will show you how you can apply/test Kubernetes ValidatingAdmissionPolicies that were first introduced in 1.26 with the enhancements to the Kyverno CLI in v1.11.

Applying ValidatingAdmissionPolicies using kyverno apply

In this section, you will create a ValidatingAdmissionPolicy that checks the number of Deployment replicas. You will then apply this policy to two Deployments, one of which violates the policy:

1cat << EOF > check-deployment-replicas.yaml 2apiVersion: admissionregistration.k8s.io/v1alpha1 3kind: ValidatingAdmissionPolicy 4metadata: 5 name: check-deployments-replicas 6spec: 7 failurePolicy: Fail 8 matchConstraints: 9 resourceRules: 10 - apiGroups: ["apps"] 11 apiVersions: ["v1"] 12 operations: ["CREATE", "UPDATE"] 13 resources: ["deployments"] 14 validations: 15 - expression: "object.spec.replicas <= 2" 16 message: "Replicas must be less than or equal 2" 17EOF
bash

The following deployment satisfies the rules declared in the above policy.

1cat << EOF > deployment-pass.yaml 2apiVersion: apps/v1 3kind: Deployment 4metadata: 5 name: nginx-pass 6spec: 7 replicas: 2 8 selector: 9 matchLabels: 10 app: nginx-pass 11 template: 12 metadata: 13 labels: 14 app: nginx-pass 15 spec: 16 containers: 17 - name: nginx-server 18 image: nginx 19EOF
bash

Let’s apply the policy to the resource using kyverno apply as follows.

1kyverno apply ./check-deployment-replicas.yaml --resource deployment-pass.yaml
bash

The output should be the following.

1Applying 1 policy rule(s) to 1 resource(s)... 2 3pass: 1, fail: 0, warn: 0, error: 0, skip: 0
bash

Let’s try to create another deployment that violates the policy.

1cat << EOF > deployment-fail.yaml 2apiVersion: apps/v1 3kind: Deployment 4metadata: 5 name: nginx-fail 6spec: 7 replicas: 3 8 selector: 9 matchLabels: 10 app: nginx-fail 11 template: 12 metadata: 13 labels: 14 app: nginx-fail 15 spec: 16 containers: 17 - name: nginx-server 18 image: nginx 19EOF
bash

Then apply the policy to the resource as follows.

1kyverno apply ./check-deployment-replicas.yaml --resource deployment-fail.yaml
bash

The output should be as shown.

1Applying 1 policy rule(s) to 1 resource(s)... 2 3pass: 0, fail: 1, warn: 0, error: 0, skip: 0
bash

Testing ValidatingAdmissionPolicies using kyverno test

In this section, you will create a ValidatingAdmissionPolicy that ensures no hostPath volumes are in use for Deployments. You will then create two Deployments to test them against the policy and check the desired results.

To proceed, you need to create a directory containing the necessary manifests. In this example, I created a directory called test-dir.

Let’s start with creating the policy.

1cat << EOF > ./test-dir/disallow-host-path.yaml 2apiVersion: admissionregistration.k8s.io/v1alpha1 3kind: ValidatingAdmissionPolicy 4metadata: 5 name: disallow-host-path 6spec: 7 failurePolicy: Fail 8 matchConstraints: 9 resourceRules: 10 - apiGroups: ["apps"] 11 apiVersions: ["v1"] 12 operations: ["CREATE", "UPDATE"] 13 resources: ["deployments"] 14 validations: 15 - expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))" 16 message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset." 17EOF
bash

Then, create the two Deployments, one of which violates the policy.

1cat << EOF > ./test-dir/deployments.yaml 2apiVersion: apps/v1 3kind: Deployment 4metadata: 5 name: deployment-pass 6spec: 7 replicas: 1 8 selector: 9 matchLabels: 10 app: nginx 11 template: 12 metadata: 13 labels: 14 app: nginx 15 spec: 16 containers: 17 - name: nginx-server 18 image: nginx 19 volumeMounts: 20 - name: temp 21 mountPath: /scratch 22 volumes: 23 - name: temp 24 emptyDir: {} 25--- 26apiVersion: apps/v1 27kind: Deployment 28metadata: 29 name: deployment-fail 30spec: 31 replicas: 1 32 selector: 33 matchLabels: 34 app: nginx 35 template: 36 metadata: 37 labels: 38 app: nginx 39 spec: 40 containers: 41 - name: nginx-server 42 image: nginx 43 volumeMounts: 44 - name: udev 45 mountPath: /data 46 volumes: 47 - name: udev 48 hostPath: 49 path: /etc/udev 50EOF
bash

The tests are defined in a file named kyverno-test.yaml so you will create two tests, one for each Deployment and test them against the policy. Notice the use of a new field in the test manifest called isValidatingAdmissionPolicy.

1cat << EOF > ./test-dir/kyverno-test.yaml 2name: disallow-host-path-test 3policies: 4 - disallow-host-path.yaml 5resources: 6 - deployments.yaml 7results: 8 - policy: disallow-host-path 9 resource: deployment-pass 10 isValidatingAdmissionPolicy: true 11 kind: Deployment 12 result: pass 13 - policy: disallow-host-path 14 resource: deployment-fail 15 isValidatingAdmissionPolicy: true 16 kind: Deployment 17 result: fail 18EOF
bash

Now, we’re ready to test the two Deployments against a ValidatingAdmissionPolicy.

1kyverno test ./test-dir
bash

The output should be as shown below.

1Executing disallow-host-path-test... 2 3│────│────────────────────│──────│────────────────────────────│────────│────────│ 4│ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON │ 5│────│────────────────────│──────│────────────────────────────│────────│────────│ 61 │ disallow-host-path │ │ Deployment/deployment-pass │ Pass │ Ok │ 72 │ disallow-host-path │ │ Deployment/deployment-fail │ Pass │ Ok │ 8│────│────────────────────│──────│────────────────────────────│────────│────────│ 9 10Test Summary: 2 tests passed and 0 tests failed
bash

As expected, the two tests passed because the actual result of each test matches the desired result as defined in the test manifest.

Conclusion

This blog post explains how to apply ValidatingAdmissionPolicies to resources using the Kyverno CLI. With Kyverno, it’s easy to apply Kubernetes ValidatingAdmissionPolicies in your CI/CD pipelines and to test new ValidatingAdmissionPolicies before they are deployed to your clusters. This is one of many exciting features coming with Kyverno v1.11.