Kyverno CLI

Apply and test policies outside a cluster.

The Kyverno Command Line Interface (CLI) is designed to validate and test policy behavior to resources prior to adding them to a cluster. The CLI can be used in CI/CD pipelines to assist with the resource authoring process to ensure they conform to standards prior to them being deployed. It can be used as a kubectl plugin or as a standalone CLI. The CLI, although composed of the same Kyverno codebase, is a purpose-built binary available via multiple installation methods but is distinct from the Kyverno container image which runs as a Pod in a target Kubernetes cluster.

Building and Installing the CLI

Install via Krew

You can use Krew to install the Kyverno CLI:

1# Install Kyverno CLI using kubectl krew plugin manager
2kubectl krew install kyverno
3
4# test the Kyverno CLI
5kubectl kyverno version  

Install via AUR (archlinux)

You can install the Kyverno CLI via your favorite AUR helper (e.g. yay)

1yay -S kyverno-git

Install via Homebrew

The Kyverno CLI can also be installed with Homebrew as a formula.

1brew install kyverno

Install in GitHub Actions

The Kyverno CLI can be installed in GitHub Actions using kyverno-cli-installer from the GitHub Marketplace. Please refer to kyverno-cli-installer for more information.

Manual Binary Installation

The Kyverno CLI may also be installed by manually downloading the compiled binary available on the releases page. An example of installing the Kyverno CLI v1.10.0 on a Linux x86_64 system is shown below.

1curl -LO https://github.com/kyverno/kyverno/releases/download/v1.10.0/kyverno-cli_v1.10.0_linux_x86_64.tar.gz
2tar -xvf kyverno-cli_v1.10.0_linux_x86_64.tar.gz
3sudo cp kyverno /usr/local/bin/

Building the CLI from source

You can also build the CLI binary from the Git repository (requires Go).

1git clone https://github.com/kyverno/kyverno
2cd kyverno
3make build-cli
4sudo mv ./cmd/cli/kubectl-kyverno/kubectl-kyverno /usr/local/bin/

CLI Commands

When using the Kyverno CLI with kustomize, it is recommended to use the “standalone” version as opposed to the version embedded inside kubectl.

apply

The apply command is used to perform a dry run on one or more policies with a given set of input resources. This can be useful to determine a policy’s effectiveness prior to committing to a cluster. In the case of mutate policies, the apply command can show the mutated resource as an output. The input resources can either be resource manifests (one or multiple) or can be taken from a running Kubernetes cluster. The apply command supports files from URLs both as policies and resources.

Apply to a resource:

1kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml

Apply a policy to all matching resources in a cluster based on the current kubectl context:

1kyverno apply /path/to/policy.yaml --cluster

The resources can also be passed from stdin:

1kustomize build nginx/overlays/envs/prod/ | kyverno apply /path/to/policy.yaml --resource -

Apply all cluster policies in the current cluster to all matching resources in a cluster based on the current kubectl context:

1kubectl get clusterpolicies -o yaml | kyverno apply - --cluster

Apply multiple policies to multiple resources:

1kyverno apply /path/to/policy1.yaml /path/to/folderFullOfPolicies --resource /path/to/resource1.yaml --resource /path/to/resource2.yaml --cluster

Apply a mutation policy to a specific resource:

1kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml
2
3applying 1 policy to 1 resource... 
4
5mutate policy <policy_name> applied to <resource_name>:
6<final mutated resource output>

Save the mutated resource to a file:

1kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml -o newresource.yaml

Save the mutated resource to a directory:

1kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml -o foo/

Apply a policy containing variables using the --set or -s flag to pass in the values. Variables that begin with {{request.object}} normally do not need to be specified as these will be read from the resource.

1kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml --set <variable1>=<value1>,<variable2>=<value2>

Use -f or --values-file for applying multiple policies to multiple resources while passing a file containing variables and their values. Variables specified can be of various types include AdmissionReview fields, ConfigMap context data, and API call context data.

Use -u or --userinfo for applying policies while passing an optional user_info.yaml file which contains necessary admission request data made during the request.

1kyverno apply /path/to/policy1.yaml /path/to/policy2.yaml --resource /path/to/resource1.yaml --resource /path/to/resource2.yaml -f /path/to/value.yaml --userinfo /path/to/user_info.yaml

Format of value.yaml with all possible fields:

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5policies:
 6  - name: <policy1 name>
 7    rules:
 8    - name: <rule1 name>
 9      values:
10        <context variable1 in policy1 rule1>: <value>
11        <context variable2 in policy1 rule1>: <value>
12    - name: <rule2 name>
13      values:
14        <context variable1 in policy1 rule2>: <value>
15        <context variable2 in policy1 rule2>: <value>
16    resources:
17    - name: <resource1 name>
18      values:
19        <variable1 in policy1>: <value>
20        <variable2 in policy1>: <value>
21    - name: <resource2 name>
22      values:
23        <variable1 in policy1>: <value>
24        <variable2 in policy1>: <value>
25namespaceSelector:
26- name: <namespace1 name>
27  labels:
28    <label key>: <label value>
29- name: <namespace2 name>
30  labels:
31    <label key>: <label value>

Format of user_info.yaml:

1apiVersion: cli.kyverno.io/v1alpha1
2kind: UserInfo
3metadata:
4  name: user-info
5clusterRoles:
6- admin
7userInfo:
8  username: molybdenum@somecorp.com

Example:

Policy manifest (add_network_policy.yaml):

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: add-networkpolicy
 5spec:
 6  background: false
 7  rules:
 8  - name: default-deny-ingress
 9    match:
10      any:
11      - resources:
12          kinds:
13          - Namespace
14        clusterRoles:
15        - cluster-admin
16    generate:
17      apiVersion: networking.k8s.io/v1
18      kind: NetworkPolicy
19      name: default-deny-ingress
20      namespace: "{{request.object.metadata.name}}"
21      synchronize: true
22      data:
23        spec:
24          # select all pods in the namespace
25          podSelector: {}
26          policyTypes:
27          - Ingress

Resource manifest (required_default_network_policy.yaml):

1kind: Namespace
2apiVersion: v1
3metadata:
4  name: devtest

Apply a policy to a resource using the --set or -s flag to pass a variable directly:

1kyverno apply /path/to/add_network_policy.yaml --resource /path/to/required_default_network_policy.yaml -s request.object.metadata.name=devtest

Apply a policy to a resource using the --values-file or -f flag:

YAML file containing variables (value.yaml):

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5policies:
 6  - name: add-networkpolicy
 7    resources:
 8      - name: devtest
 9        values:
10          request.namespace: devtest
1kyverno apply /path/to/add_network_policy.yaml --resource /path/to/required_default_network_policy.yaml -f /path/to/value.yaml

On applying the above policy to the mentioned resources, the following output will be generated:

1Applying 1 policy to 1 resource... 
2(Total number of result count may vary as the policy is mutated by Kyverno. To check the mutated policy please try with log level 5)
3
4pass: 1, fail: 0, warn: 0, error: 0, skip: 0 

The summary count is based on the number of rules applied on the number of resources.

Value files also support global values, which can be passed to all resources the policy is being applied to.

Format of value.yaml:

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5policies:
 6  - name: <policy1 name>
 7    resources:
 8      - name: <resource1 name>
 9        values:
10          <variable1 in policy1>: <value>
11          <variable2 in policy1>: <value>
12      - name: <resource2 name>
13        values:
14          <variable1 in policy1>: <value>
15          <variable2 in policy1>: <value>
16  - name: <policy2 name>
17    resources:
18      - name: <resource1 name>
19        values:
20          <variable1 in policy2>: <value>
21          <variable2 in policy2>: <value>
22      - name: <resource2 name>
23        values:
24          <variable1 in policy2>: <value>
25          <variable2 in policy2>: <value>
26globalValues:
27  <global variable1>: <value>
28  <global variable2>: <value>

If a resource-specific value and a global value have the same variable name, the resource value takes precedence over the global value. See the Pod test-global-prod in the following example.

Example:

Policy manifest (add_dev_pod.yaml):

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: cm-globalval-example
 5spec:
 6  validationFailureAction: Enforce
 7  background: false
 8  rules:
 9    - name: validate-mode
10      match:
11        any:
12        - resources:
13            kinds:
14              - Pod
15      validate:
16        message: "The value {{ request.mode }} for val1 is not equal to 'dev'."
17        deny:
18          conditions:
19            any:
20              - key: "{{ request.mode }}"
21                operator: NotEquals
22                value: dev

Resource manifest (dev_prod_pod.yaml):

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: test-global-prod
 5spec:
 6  containers:
 7    - name: nginx
 8      image: nginx:latest
 9---
10apiVersion: v1
11kind: Pod
12metadata:
13  name: test-global-dev
14spec:
15  containers:
16    - name: nginx
17      image: nginx:1.12

YAML file containing variables (value.yaml):

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5policies:
 6  - name: cm-globalval-example
 7    resources:
 8      - name: test-global-prod
 9        values:
10          request.mode: prod
11globalValues:
12  request.mode: dev
1kyverno apply /path/to/add_dev_pod.yaml --resource /path/to/dev_prod_pod.yaml -f /path/to/value.yaml

The Pod test-global-dev passes the validation, and test-global-prod fails.

Apply a policy with the Namespace selector:

Use --values-file or -f for passing a file containing Namespace details. Check here to know more about Namespace selectors.

1kyverno apply /path/to/policy1.yaml /path/to/policy2.yaml --resource /path/to/resource1.yaml --resource /path/to/resource2.yaml -f /path/to/value.yaml

Format of value.yaml:

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5namespaceSelector:
 6  - name: <namespace1 name>
 7    labels:
 8      <namespace label key>: <namespace label value>
 9  - name: <namespace2 name>
10    labels:
11      <namespace label key>: <namespace label value>

Example:

Policy manifest (enforce-pod-name.yaml):

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: enforce-pod-name
 5spec:
 6  validationFailureAction: Audit
 7  background: true
 8  rules:
 9    - name: validate-name
10      match:
11        any:
12        - resources:
13            kinds:
14              - Pod
15            namespaceSelector:
16              matchExpressions:
17              - key: foo.com/managed-state
18                operator: In
19                values:
20                - managed
21      validate:
22        message: "The Pod must end with -nginx"
23        pattern:
24          metadata:
25            name: "*-nginx"

Resource manifest (nginx.yaml):

1kind: Pod
2apiVersion: v1
3metadata:
4  name: test-nginx
5  namespace: test1
6spec:
7  containers:
8  - name: nginx
9    image: nginx:latest

Namespace manifest (namespace.yaml):

1apiVersion: v1
2kind: Namespace
3metadata:
4  name: test1
5  labels:
6    foo.com/managed-state: managed

YAML file containing variables (value.yaml):

1apiVersion: cli.kyverno.io/v1alpha1
2kind: Value
3metadata:
4  name: values
5namespaceSelector:
6  - name: test1
7    labels:
8      foo.com/managed-state: managed

To test the above policy, use the following command:

1kyverno apply /path/to/enforce-pod-name.yaml --resource /path/to/nginx.yaml -f /path/to/value.yaml

Apply a resource to a policy which uses a context variable:

Use --values-file or -f for passing a file containing the context variable.

1kyverno apply /path/to/policy1.yaml --resource /path/to/resource1.yaml -f /path/to/value.yaml

policy1.yaml

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: cm-variable-example
 5  annotations:
 6    pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,StatefulSet
 7spec:
 8  validationFailureAction: Enforce
 9  background: false
10  rules:
11    - name: example-configmap-lookup
12      context:
13      - name: dictionary
14        configMap:
15          name: mycmap
16          namespace: default
17      match:
18        any:
19        - resources:
20            kinds:
21            - Pod
22      mutate:
23        patchStrategicMerge:
24          metadata:
25            labels:
26              my-environment-name: "{{dictionary.data.env}}"

resource1.yaml

1apiVersion: v1
2kind: Pod
3metadata:
4  name: nginx-config-test
5spec:
6  containers:
7  - image: nginx:latest
8    name: test-nginx

value.yaml

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5policies:
 6  - name: cm-variable-example
 7    rules:
 8      - name: example-configmap-lookup
 9        values:
10          dictionary.data.env: dev1

Policies that have their validationFailureAction set to Audit can be set to produce a warning instead of a failure using the --audit-warn flag. This will also cause a non-zero exit code if no enforcing policies failed.

1kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml --audit-warn

Additionally, you can use the --warn-exit-code flag with the apply command to control the exit code when warnings are reported. This is useful in CI/CD systems when used with the --audit-warn flag to treat Audit policies as warnings. When no failures or errors are found, but warnings are encountered, the CLI will exit with the defined exit code.

1kyverno apply disallow-latest-tag.yaml --resource=echo-test.yaml --audit-warn --warn-exit-code 3
2echo $?
33

You can also use --warn-exit-code in combination with --warn-no-pass flag to make the CLI exit with the warning code if no objects were found that satisfy a policy. This may be useful during the initial development of a policy or if you want to make sure that an object exists in the Kubernetes manifest.

1kyverno apply disallow-latest-tag.yaml --resource=empty.yaml --warn-exit-code 3 --warn-no-pass
2echo $?
33

Policy Report

Policy reports provide information about policy execution and violations. Use --policy-report with the apply command to generate a policy report for validate policies. mutate and generate policies do not trigger policy reports.

Policy reports can also be generated for a live cluster. While generating a policy report for a live cluster the -r flag, which declares a resource, is assumed to be globally unique. And it doesn’t support naming the resource type (ex., Pod/foo when the cluster contains resources of different types with the same name). To generate a policy report for a live cluster use --cluster with --policy-report.

1kyverno apply policy.yaml --cluster --policy-report

Above example applies a policy.yaml to all resources in the cluster.

Below are the combination of inputs that can be used for generating the policy report from the Kyverno CLI.

PolicyResourceClusterNamespaceInterpretation
policy.yaml-r resource.yamlfalseApply policy from policy.yaml to the resources specified in resource.yaml
policy.yaml-r resourceNametrueApply policy from policy.yaml to the resource with a given name in the cluster
policy.yamltrueApply policy from policy.yaml to all the resources in the cluster
policy.yaml-r resourceNametrue-n=namespaceNameApply policy from policy.yaml to the resource with a given name in a specific Namespace
policy.yamltrue-n=namespaceNameApply policy from policy.yaml to all the resources in a specific Namespace

Example:

Consider the following policy and resources:

policy.yaml

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: require-pod-requests-limits
 5spec:
 6  validationFailureAction: Audit
 7  rules:
 8  - name: validate-resources
 9    match:
10      any:
11      - resources:
12          kinds:
13          - Pod
14    validate:
15      message: "CPU and memory resource requests and limits are required"
16      pattern:
17        spec:
18          containers:
19          - resources:
20              requests:
21                memory: "?*"
22                cpu: "?*"
23              limits:
24                memory: "?*"

resource1.yaml

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: nginx1
 5  labels:
 6    env: test
 7spec:
 8  containers:
 9  - name: nginx
10    image: nginx
11    imagePullPolicy: IfNotPresent
12    resources:
13      requests:
14        memory: "64Mi"
15        cpu: "250m"
16      limits:
17        memory: "128Mi"
18        cpu: "500m"

resource2.yaml

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: nginx2
 5  labels:
 6    env: test
 7spec:
 8  containers:
 9  - name: nginx
10    image: nginx
11    imagePullPolicy: IfNotPresent

Case 1: Apply a policy manifest to multiple resource manifests

1kyverno apply policy.yaml -r resource1.yaml -r resource2.yaml --policy-report

Case 2: Apply a policy manifest to multiple resources in the cluster

Create the resources by first applying manifests resource1.yaml and resource2.yaml.

1kyverno apply policy.yaml -r nginx1 -r nginx2 --cluster --policy-report

Case 3: Apply a policy manifest to all resources in the cluster

1kyverno apply policy.yaml --cluster --policy-report

Given the contents of policy.yaml shown earlier, this will produce a report validating against all Pods in the cluster.

Case 4: Apply a policy manifest to multiple resources by name within a specific Namespace

1kyverno apply policy.yaml -r nginx1 -r nginx2 --cluster --policy-report -n default

Case 5: Apply a policy manifest to all resources within the default Namespace

1kyverno apply policy.yaml --cluster --policy-report -n default

Given the contents of policy.yaml shown earlier, this will produce a report validating all Pods within the default Namespace.

On applying policy.yaml to the mentioned resources, the following report will be generated:

 1apiVersion: wgpolicyk8s.io/v1alpha1
 2kind: ClusterPolicyReport
 3metadata:
 4  name: clusterpolicyreport
 5results:
 6- message: Validation rule 'validate-resources' succeeded.
 7  policy: require-pod-requests-limits
 8  resources:
 9  - apiVersion: v1
10    kind: Pod
11    name: nginx1
12    namespace: default
13  rule: validate-resources
14  scored: true
15  status: pass
16- message: 'Validation error: CPU and memory resource requests and limits are required; Validation rule validate-resources failed at path /spec/containers/0/resources/limits/'
17  policy: require-pod-requests-limits
18  resources:
19  - apiVersion: v1
20    kind: Pod
21    name: nginx2
22    namespace: default
23  rule: validate-resources
24  scored: true
25  status: fail
26summary:
27  error: 0
28  fail: 1
29  pass: 1
30  skip: 0
31  warn: 0

Applying ValidatingAdmissionPolicies

With the apply command, Kubernetes ValidatingAdmissionPolicies can be applied to resources as follows:

Policy manifest (check-deployment-replicas.yaml):

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

Resource manifest (deployment.yaml):

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: nginx-pass
 5spec:
 6  replicas: 2
 7  selector:
 8    matchLabels:
 9      app: nginx-pass
10  template:
11    metadata:
12      labels:
13        app: nginx-pass
14    spec:
15      containers:
16      - name: nginx-server
17        image: nginx

Apply the ValidatingAdmissionPolicy to the resource:

1kyverno apply /path/to/check-deployment-replicas.yaml --resource /path/to/deployment.yaml

The following output will be generated:

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

create

The Kyverno CLI has a create subcommand which makes it possible to create various Kyverno resources. You can create:

  1. metrics-config file: Helps you create a configmap with namespaces to include or exclude for kyverno-metrics
  2. test file: Helps you create test files to use with kyverno test command
  3. user-info file: Helps you create a userinfo file which contains user name, group, role and clusterrole
  4. values file: Helps you create a file that specifies global as well as local policy values
  5. exception file: Helps you create an exception to an existing policy using a Policy Exception

Examples:

To create a metrics-config file

 1$ kyverno create metrics-config -i ns-included-1 -i ns-included-2 -e ns-excluded
 2
 3apiVersion: v1
 4kind: ConfigMap
 5metadata:
 6  name: kyverno-metrics
 7  namespace: kyverno
 8data:
 9  namespaces: |
10    {
11      "include": [
12        "ns-included-1",
13        "ns-included-2"
14      ],
15      "exclude": [
16        "ns-excluded"
17      ]
18    }

To create a values file

 1$ kyverno create values -g request.mode=dev -n prod,env=prod --rule policy,rule,env=demo --resource policy,resource,env=demo
 2
 3# list of policy values
 4policies:
 5  - name: policy
 6    rules:
 7      - name: rule
 8        values:
 9          env: demo
10  - name: policy
11    resources:
12      - name: resource
13        values:
14          env: demo
15
16# list of global values
17globalValues:
18  request.mode: dev
19
20# list of namespace selectors
21namespaceSelector:
22  - name: prod
23    labels:
24      env: prod

To create a policy exception file

 1$ kyverno create exception my-exception --namespace my-ns --policy-rules "policy,rule-1,rule-2" --any "kind=Pod,kind=Deployment"
 2
 3apiVersion: kyverno.io/v2beta1
 4kind: PolicyException
 5metadata:
 6  name: my-exception
 7  namespace: my-ns
 8spec:
 9  background: true
10  match:
11    any:
12    - kinds:
13        - Pod
14        - Deployment
15  exceptions:
16    - policyName: policy
17      ruleNames:
18        - rule-1
19        - rule-2

To create a test file

 1$ kyverno create test -p policy.yaml -r resource.yaml -f values.yaml --pass policy-name,rule-name,resource-name,resource-namespace,resource-kind
 2
 3# test name
 4name: test-name
 5
 6# list of policy files
 7policies:
 8  - policy.yaml
 9
10# list of resource files
11resources:
12  - resource.yaml
13
14# variables file (optional)
15variables: values.yaml
16
17# list of expected results
18results:
19  - policy: policy-name
20    rule: rule-name
21    resource: resource-name
22    namespace: resource-namespace
23    kind: resource-kind
24    result: pass

To create a user-info file

 1$ kyverno create user-info -u molybdenum@somecorp.com -g basic-user -c admin  
 2
 3# list of roles
 4roles:
 5
 6# list of cluster roles
 7clusterRoles:
 8  - admin
 9
10userInfo:
11  # user name
12  username: molybdenum@somecorp.com
13
14  # list of groups
15  groups:
16    - basic-user

docs

The Kyverno CLI has a docs subcommand which makes it possible to generate Kyverno CLI reference documentation. It can be used to generate simple markdown files or markdown to be used for the website.

Examples:

To generate simple markdown documentation

1$ kyverno docs -o . --autogenTag=false

test

The test command is used to test a given set of resources against one or more policies to check desired results, declared in advance in a separate test manifest file, against the actual results. test is useful when you wish to declare what your expected results should be by defining the intent which then assists with locating discrepancies should those results change.

test works by scanning a given location, which can be either a Git repository or local folder, and executing the tests defined within. The rule types validate, mutate, and generate are currently supported. The command recursively looks for YAML files with policy test declarations (described below) with a specified file name and then executes those tests. All files applicable to the same test must be co-located. Directory recursion is supported. test supports the auto-gen feature making it possible to test, for example, Deployment resources against a Pod policy.

test will search for a file named kyverno-test.yaml and, if found, will execute the tests within.

In each test, there are four desired results which can be tested for. If the actual result of the test, once executed, matches the desired result as defined in the test manifest, it will be scored as a pass in the command output. For example, if the specified result of a given test of a resource against a policy is declared to be a pass and the actual result when tested is also a pass, the command output will show as pass. If the actual result was instead a skip, the command output will show as fail because the two results do not agree. The following are the desired results which can be specified in a test manifest.

  1. pass: The resource passes the policy definition. For validate rules which are written with a deny statement, this will not be a possible result. mutate and generate rules can declare a pass.
  2. skip: The resource does not meet either the match or exclude block, or does not pass the preconditions statements. For validate rules which are written with a deny statement, this is a possible result. If a rule contains certain conditional anchors which are not satisfied, the result may also be scored as a skip.
  3. fail: The resource does not pass the policy definition. Typically used for validate rules with pattern-style policy definitions.
  4. warn: Setting the annotation policies.kyverno.io/scored to "false" on a resource or policy which would otherwise fail will be considered a warn.

Use --detailed-results for a comprehensive output (default value false). For help with the test command, pass the -h flag for extensive output including usage, flags, and sample manifests.

Test File Structures

The test declaration file format of kyverno-test.yaml must be of the following format.

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Test
 3metadata:
 4  name: kyverno-test
 5policies:
 6  - <path/to/policy.yaml>
 7  - <path/to/policy.yaml>
 8resources:
 9  - <path/to/resource.yaml>
10  - <path/to/resource.yaml>
11variables: variables.yaml # optional file for declaring variables. see below for example.
12userinfo: user_info.yaml # optional file for declaring admission request information (roles, cluster roles and subjects). see below for example.
13results:
14- policy: <name>
15  isValidatingAdmissionPolicy: false # when the policy is ValidatingAdmissionPolicy, this field is required.
16  rule: <name> # when the policy is a Kyverno policy, this field is required.
17  resources: # optional, primarily for `validate` rules.
18  - <namespace_1/name_1>
19  - <namespace_2/name_2>
20  patchedResource: <file_name.yaml> # when testing a mutate rule this field is required.
21  generatedResource: <file_name.yaml> # when testing a generate rule this field is required.
22  cloneSourceResource: <file_name.yaml> # when testing a generate rule that uses `clone` object this field is required.
23  kind: <kind>
24  result: pass

The test declaration consists of the following parts:

  1. The policies element which lists one or more policies to be applied.
  2. The resources element which lists one or more resources to which the policies are applied.
  3. The variables element which defines a file in which variables and their values are stored for use in the policy test. Optional depending on policy content.
  4. The userinfo element which declares admission request data for subjects and roles. Optional depending on policy content.
  5. The results element which declares the expected results. Depending on the type of rule being tested, this section may vary.

If needing to pass variables, such as those from external data sources like context variables built from API calls or others, a variables.yaml file can be defined with the same format as accepted with the apply command. If a variable needs to contain an array of strings, it must be formatted as JSON encoded. Like with the apply command, variables that begin with request.object normally do not need to be specified in the variables file as these will be sourced from the resource. Policies which trigger based upon request.operation equaling CREATE do not need a variables file. The CLI will assume a value of CREATE if no variable for request.operation is defined.

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5policies:
 6  - name: exclude-namespaces-example
 7    rules:
 8      - name: exclude-namespaces-dynamically
 9        values:
10          namespacefilters.data.exclude: asdf
11    resources:
12      - name: nonroot-pod
13        values:
14          namespacefilters.data.exclude: foo
15      - name: root-pod
16        values:
17          namespacefilters.data.exclude: "[\"cluster-admin\", \"cluster-operator\", \"tenant-admin\"]"

A variables file may also optionally specify global variable values without the need to name specific rules or resources avoiding repetition for the same variable and same value.

1apiVersion: cli.kyverno.io/v1alpha1
2kind: Value
3metadata:
4  name: values
5globalValues:
6  request.operation: UPDATE

If policies use a namespaceSelector, these can also be specified in the variables file.

1apiVersion: cli.kyverno.io/v1alpha1
2kind: Value
3metadata:
4  name: values
5namespaceSelector:
6  - name: test1
7    labels:
8      foo.com/managed-state: managed

The user can also declare a user_info.yaml file that can be used to pass admission request information such as roles, cluster roles, and subjects.

1apiVersion: cli.kyverno.io/v1alpha1
2kind: UserInfo
3metadata:
4  name: user-info
5clusterRoles:
6- admin
7userInfo:
8  username: someone@somecorp.com

Testing for subresources in Kind/Subresource matching format also requires a subresources{} section in the values file.

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5subresources:
 6  - subresource:
 7      name: <name of subresource>
 8      kind: <kind of subresource>
 9      group: <group of subresource>
10      version: <version of subresource>
11    parentResource:
12      name: <name of parent resource>
13      kind: <kind of parent resource>
14      group: <group of parent resource>
15      version: <version of parent resource>

Here is an example when testing for subresources:

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5subresources:
 6  - subresource:
 7      name: "deployments/scale"
 8      kind: "Scale"
 9      group: "autoscaling"
10      version: "v1"
11    parentResource:
12      name: "deployments"
13      kind: "Deployment"
14      group: "apps"
15      version: "v1"

Test Against Local Files

Test a set of local files in the working directory.

1kyverno test .

Test a set of local files by specifying the directory.

1kyverno test /path/to/folderContainingTestYamls

Test Against Git Repositories

Test an entire Git repository by specifying the branch name within the repo URL. If branch is not specified, main will be used as a default.

1kyverno test https://github.com/kyverno/policies/release-1.6

Test a specific directory of the repository by specifying the directory within repo URL and the branch with the --git-branch or -b flag. Even if testing against main, when using a directory in the URL of the repo requires passing the --git-branch or -b flag.

1kyverno test https://github.com/kyverno/policies/pod-security/restricted -b release-1.6

Use the -f flag to set a custom file name which includes test cases. By default, test will search for a file called kyverno-test.yaml.

Testing Policies with Image Registry Access

For policies which require image registry access to set context variables, those variables may be sourced from a variables file (defined below) or from a “live” registry by passing the --registry flag.

Test Subset of Resources

In some cases, you may wish to only test a subset of policy, rules, and/ resource combination rather than all those defined in a test manifest. Use the --test-case-selector flag to specify the exact tests you wish to execute.

1kyverno test . --test-case-selector "policy=add-default-resources, rule=add-default-requests, resource=nginx-demo2"

Examples

The test command executes a test declaration by applying the policies to the resources and comparing the actual results with the desired/expected results. The test passes if the actual results match the expected results.

Below is an example of testing a policy containing two validate rules against the same resource where each is supposed to pass the policy.

Policy manifest (disallow_latest_tag.yaml):

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: disallow-latest-tag
 5spec:
 6  validationFailureAction: Audit
 7  rules:
 8  - name: require-image-tag
 9    match:
10      any:
11      - resources:
12          kinds:
13          - Pod
14        clusterRoles:
15        - cluster-admin
16    validate:
17      message: "An image tag is required."  
18      pattern:
19        spec:
20          containers:
21          - image: "*:*"
22  - name: validate-image-tag
23    match:
24      any:
25      - resources:
26          kinds:
27          - Pod
28    validate:
29      message: "Using a mutable image tag e.g. 'latest' is not allowed."
30      pattern:
31        spec:
32          containers:
33          - image: "!*:latest"

Resource manifest (resource.yaml):

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: myapp-pod
 5  labels:
 6    app: myapp
 7spec: 
 8  containers:
 9  - name: nginx
10    image: nginx:1.12

Test manifest (kyverno-test.yaml):

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Test
 3metadata:
 4  name: disallow_latest_tag
 5policies:
 6  - disallow_latest_tag.yaml
 7resources:
 8  - resource.yaml
 9results:
10  - policy: disallow-latest-tag
11    rule: require-image-tag
12    resource: myapp-pod
13    kind: Pod
14    result: pass
15  - policy: disallow-latest-tag
16    rule: validate-image-tag
17    resource: myapp-pod
18    kind: Pod
19    result: pass
 1$ kyverno test .
 2
 3Executing disallow_latest_tag...
 4applying 1 policy to 1 resource... 
 5
 6│───│─────────────────────│────────────────────│───────────────────────│────────│
 7# │ POLICY              │ RULE               │ RESOURCE              │ RESULT │
 8│───│─────────────────────│────────────────────│───────────────────────│────────│
 91 │ disallow-latest-tag │ require-image-tag  │ default/Pod/myapp-pod │ Pass   │
102 │ disallow-latest-tag │ validate-image-tag │ default/Pod/myapp-pod │ Pass   │
11│───│─────────────────────│────────────────────│───────────────────────│────────│
12
13Test Summary: 2 tests passed and 0 tests failed

In the below case, a mutate policy which adds default resources to a Pod is being tested against two resources. Notice the addition of the patchedResource field in the results[] array, which is a requirement when testing mutate rules.

Policy manifest (add-default-resources.yaml):

 1apiVersion : kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: add-default-resources
 5spec:
 6  background: false
 7  rules:
 8  - name: add-default-requests
 9    match:
10      any:
11      - resources:
12          kinds:
13          - Pod
14    preconditions:
15      any:
16      - key: "{{request.operation}}"
17        operator: AnyIn
18        value:
19        - CREATE
20        - UPDATE
21    mutate:
22      patchStrategicMerge:
23        spec:
24          containers:
25            - (name): "*"
26              resources:
27                requests:
28                  +(memory): "100Mi"
29                  +(cpu): "100m"

Resource manifest (resource.yaml):

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: nginx-demo1
 5spec:
 6  containers:
 7  - name: nginx
 8    image: nginx:1.14.2
 9---
10apiVersion: v1
11kind: Pod
12metadata:
13  name: nginx-demo2
14spec:
15  containers:
16  - name: nginx
17    image: nginx:latest
18    resources:
19      requests:
20        memory: "200Mi" 
21        cpu: "200m"

Variables manifest (values.yaml):

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5policies:
 6- name: add-default-resources
 7  resources:
 8  - name: nginx-demo1
 9    values:
10      request.operation: CREATE
11  - name: nginx-demo2
12    values:
13      request.operation: UPDATE

Test manifest (kyverno-test.yaml):

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Test
 3metadata:
 4  name: add-default-resources
 5policies:
 6  - add-default-resources.yaml
 7resources:
 8  - resource.yaml
 9variables: values.yaml
10results:
11  - policy: add-default-resources
12    rule: add-default-requests
13    resource: nginx-demo1
14    patchedResource: patchedResource1.yaml
15    kind: Pod
16    result: pass
17  - policy: add-default-resources
18    rule: add-default-requests
19    resource: nginx-demo2
20    patchedResource: patchedResource2.yaml
21    kind: Pod
22    result: skip
 1$ kyverno test .
 2
 3Executing add-default-resources...
 4applying 1 policy to 2 resources... 
 5
 6skipped mutate policy add-default-resources -> resource default/Pod/nginx-demo2
 7│───│───────────────────────│──────────────────────│─────────────────────────│────────│
 8# │ POLICY                │ RULE                 │ RESOURCE                │ RESULT │
 9│───│───────────────────────│──────────────────────│─────────────────────────│────────│
101 │ add-default-resources │ add-default-requests │ default/Pod/nginx-demo1 │ Pass   │
112 │ add-default-resources │ add-default-requests │ default/Pod/nginx-demo2 │ Pass   │
12│───│───────────────────────│──────────────────────│─────────────────────────│────────│
13
14Test Summary: 2 tests passed and 0 tests failed

In the following policy test, a generate policy rule is applied which generates a new resource from an existing resource present in resource.yaml. To test the generate policy, the addition of a generatedResource field in the results[] array is required which is used to test against the resource generated by the policy.

Policy manifest (add_network_policy.yaml):

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: add-networkpolicy
 5spec:
 6  rules:
 7  - name: default-deny
 8    match:
 9      any:
10      - resources:
11          kinds:
12          - Namespace
13    generate:
14      apiVersion: networking.k8s.io/v1
15      kind: NetworkPolicy
16      name: default-deny
17      namespace: "{{request.object.metadata.name}}"
18      synchronize: true
19      data:
20        spec:
21          podSelector: {}
22          policyTypes:
23          - Ingress
24          - Egress

Resource manifest (resource.yaml):

1apiVersion: v1
2kind: Namespace
3metadata:
4  name: hello-world-namespace

Generated Resource (generatedResource.yaml):

 1apiVersion: networking.k8s.io/v1
 2kind: NetworkPolicy
 3metadata:
 4  name: default-deny
 5  namespace: hello-world-namespace
 6spec:
 7  podSelector: {}
 8  policyTypes:
 9  - Ingress
10  - Egress

Test manifest (kyverno-test.yaml):

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Test
 3metadata:
 4  name: deny-all-traffic
 5policies:
 6  - add_network_policy.yaml
 7resources:
 8  - resource.yaml
 9results:
10  - policy: add-networkpolicy
11    rule: default-deny
12    resource: hello-world-namespace
13    generatedResource: generatedResource.yaml
14    kind: Namespace
15    result: pass
 1$ kyverno test .
 2Executing deny-all-traffic...
 3applying 1 policy to 1 resource...
 4
 5│───│───────────────────│──────────────│──────────────────────────────────│────────│
 6# │ POLICY            │ RULE         │ RESOURCE                         │ RESULT │
 7│───│───────────────────│──────────────│──────────────────────────────────│────────│
 81 │ add-networkpolicy │ default-deny │ /Namespace/hello-world-namespace │ Pass   │
 9│───│───────────────────│──────────────│──────────────────────────────────│────────│
10Test Summary: 1 tests passed and 0 tests failed

For many more examples of test cases, please see the kyverno/policies repository which strives to have test cases for all the sample policies which appear on the website.

Testing ValidatingAdmissionPolicies

Below is an example of testing a ValidatingAdmissionPolicy against two resources, one of which violates the policy.

Policy manifest (disallow-host-path.yaml):

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

Resource manifest (deployments.yaml):

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: deployment-pass
 5spec:
 6  replicas: 1
 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: temp
20            mountPath: /scratch
21      volumes:
22      - name: temp
23        emptyDir: {}
24---
25apiVersion: apps/v1
26kind: Deployment
27metadata:
28  name: deployment-fail
29spec:
30  replicas: 1
31  selector:
32    matchLabels:
33      app: nginx
34  template:
35    metadata:
36      labels:
37        app: nginx
38    spec:
39      containers:
40      - name: nginx-server
41        image: nginx
42        volumeMounts:
43          - name: udev
44            mountPath: /data
45      volumes:
46      - name: udev
47        hostPath:
48          path: /etc/udev

Test manifest (kyverno-test.yaml):

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Test
 3metadata:
 4  name: disallow-host-path-test
 5policies:
 6  - disallow-host-path.yaml
 7resources:
 8  - deployments.yaml
 9results:
10  - policy: disallow-host-path
11    resource: deployment-pass
12    isValidatingAdmissionPolicy: true
13    kind: Deployment
14    result: pass
15  - policy: disallow-host-path
16    resource: deployment-fail
17    isValidatingAdmissionPolicy: true
18    kind: Deployment
19    result: fail
 1$ kyverno test .
 2
 3Loading test  ( kyverno-test.yaml ) ...
 4  Loading values/variables ...
 5  Loading policies ...
 6  Loading resources ...
 7  Applying 1 policy to 2 resources ...
 8  Checking results ...
 9
10│────│────────────────────│──────│────────────────────────────│────────│────────│
11│ ID │ POLICY             │ RULE │ RESOURCE                   │ RESULT │ REASON │
12│────│────────────────────│──────│────────────────────────────│────────│────────│
131 │ disallow-host-path │      │ Deployment/deployment-pass │ Pass   │ Ok     │
142 │ disallow-host-path │      │ Deployment/deployment-fail │ Pass   │ Ok     │
15│────│────────────────────│──────│────────────────────────────│────────│────────│
16
17
18Test Summary: 2 tests passed and 0 tests failed

jp

The Kyverno CLI has a jp subcommand which makes it possible to test not only the custom filters endemic to Kyverno but also the full array of capabilities of JMESPath included in the jp tool itself here. By passing in either through stdin or a file, both for input JSON or YAML documents and expressions, the jp subcommand will evaluate any JMESPath expression and supply the output.

Examples:

List available Kyverno custom JMESPath filters. Please refer to the JMESPath documentation page here for extensive details on each custom filter. Note this does not show the built-in JMESPath filters available upstream, only the custom Kyverno filters.

 1$ kyverno jp function
 2Name: add
 3  Signature: add(any, any) any
 4  Note:      does arithmetic addition of two specified values of numbers, quantities, and durations
 5
 6Name: base64_decode
 7  Signature: base64_decode(string) string
 8  Note:      decodes a base 64 string
 9
10Name: base64_encode
11  Signature: base64_encode(string) string
12  Note:      encodes a regular, plaintext and unencoded string to base64
13
14Name: compare
15  Signature: compare(string, string) number
16  Note:      compares two strings lexicographically
17<snip>

Test a custom JMESPath filter using stdin inputs.

1$ echo '{"foo": "BAR"}' | kyverno jp query 'to_lower(foo)'
2Reading from terminal input.
3Enter input object and hit Ctrl+D.
4# to_lower(foo)
5"bar"

Test a custom JMESPath filter using an input JSON file. YAML files are also supported.

 1$ cat foo.json
 2{"bar": "this-is-a-dashed-string"}
 3
 4$ kyverno jp query -i foo.json "split(bar, '-')"
 5# split(bar, '-')
 6[
 7  "this",
 8  "is",
 9  "a",
10  "dashed",
11  "string"
12]

Test a custom JMESPath filter as well as an upstream JMESPath filter.

1$ kyverno jp query -i foo.json "split(bar, '-') | length(@)"
2# split(bar, '-') | length(@)
35

Test a custom JMESPath filter using an expression from a file.

1$ cat add
2add(`1`,`2`)
3
4$ echo {} | kyverno jp query -q add
5Reading from terminal input.
6Enter input object and hit Ctrl+D.
7# add(`1`,`2`)
83

Test upstream JMESPath functionality using an input JSON file and show cleaned output.

 1$ cat pod.json
 2{
 3  "apiVersion": "v1",
 4  "kind": "Pod",
 5  "metadata": {
 6    "name": "mypod",
 7    "namespace": "foo"
 8  },
 9  "spec": {
10    "containers": [
11      {
12        "name": "busybox",
13        "image": "busybox"
14      }
15    ]
16  }
17}
18
19$ kyverno jp query -i pod.json 'spec.containers[0].name' -u
20# spec.containers[0].name
21busybox

Parse a JMESPath expression and show the corresponding AST to see how it was interpreted.

 1$ kyverno jp parse 'request.object.metadata.name | truncate(@, `9`)'
 2# request.object.metadata.name | truncate(@, `9`)
 3ASTPipe {
 4  children: {
 5    ASTSubexpression {
 6      children: {
 7        ASTSubexpression {
 8          children: {
 9            ASTSubexpression {
10              children: {
11                ASTField {
12                  value: "request"
13                }
14                ASTField {
15                  value: "object"
16                }
17            }
18            ASTField {
19              value: "metadata"
20            }
21        }
22        ASTField {
23          value: "name"
24        }
25    }
26    ASTFunctionExpression {
27      value: "truncate"
28      children: {
29        ASTCurrentNode {
30        }
31        ASTLiteral {
32          value: 9
33        }
34    }
35}

For more specific information on writing JMESPath for use in Kyverno, see the JMESPath page.

oci

The Kyverno CLI has experimental ability to now push and pull Kyverno policies as OCI artifacts from an OCI-compliant registry. This ability allows one to store policies in a registry similar to how they are commonly stored in a git repository today. In a future release, the Kyverno admission controller will be able to directly reference this OCI image bundle to fetch policies.

To use the oci command, set the environment variable KYVERNO_EXPERIMENTAL to a value of 1 or true.

Pushing

Kyverno policies may be pushed to an OCI-compliant registry by using the push subcommand. Use the -i flag for the image repository reference and --policy or -p to reference one or more policies which should be bundled and pushed. The -p flag also supports a directory containing Kyverno policies. The directory must only contain Kyverno ClusterPolicy or Policy resources. Policies will be serialized and validated by the CLI first to ensure they are correct prior to pushing. This also means YAML comments will be lost.

Push a single Kyverno ClusterPolicy named require-labels.yaml to GitHub Container Registry at the acme organization in a repository named mypolicies with tag 0.0.1.

1kyverno oci push -i ghcr.io/acme/mypolicies:0.0.1 --policy require-labels.yaml

Push a directory named mydirofpolicies containing multiple Kyverno ClusterPolicy and Policy resources to GitHub Container Registry at the acme organization in a repository named mypolicybundle with tag 0.0.1.

1kyverno oci push -i ghcr.io/acme/mypolicybundle:0.0.1 --policy mydirofpolicies/

Pulling

Similar to the push subcommand, the kyverno oci command can pull the policies which were stored from a push. The -i flag is again used to reference the OCI artifact representing the Kyverno policies. The --directory or -d flag is used to set the output directory. Policies will be output as separate YAML files in the directory specified.

Pull the ghcr.io/acme/mypolicybundle:0.0.1 Kyverno policy bundle to the working directory.

1kyverno oci pull -i ghcr.io/acme/mypolicybundle:0.0.1

Pull the ghcr.io/acme/mypolicybundle:0.0.1 Kyverno policy bundle to a directory named foodir.

1kyverno oci pull -i ghcr.io/acme/mypolicybundle:0.0.1 -d foodir/

version

Prints the version of Kyverno CLI.

Example:

1$ kyverno version
2Version: 1.6.0
3Time: 2022-02-08T07:49:45Z
4Git commit ID: 5b4d4c266353981a559fe210b4e85100fa3bf397

Last modified December 18, 2023 at 9:52 PM PST: cherry-pick #1068 to Release 1 11 0 (#1069) (5a63aec)