Kyverno CLI
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
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.7.2 on a Linux x86_64 system is shown below.
1curl -LO https://github.com/kyverno/kyverno/releases/download/v1.7.2/kyverno-cli_v1.7.2_linux_x86_64.tar.gz
2tar -xvf kyverno-cli_v1.7.2_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
4mv ./cmd/cli/kubectl-kyverno/kyverno /usr/local/bin/kyverno
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.
Note
When passing ConfigMap array data into the values file, the data must be formatted as JSON outlined here.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:
1policies:
2 - name: <policy1 name>
3 rules:
4 - name: <rule1 name>
5 values:
6 <context variable1 in policy1 rule1>: <value>
7 <context variable2 in policy1 rule1>: <value>
8 - name: <rule2 name>
9 values:
10 <context variable1 in policy1 rule2>: <value>
11 <context variable2 in policy1 rule2>: <value>
12 resources:
13 - name: <resource1 name>
14 values:
15 <variable1 in policy1>: <value>
16 <variable2 in policy1>: <value>
17 - name: <resource2 name>
18 values:
19 <variable1 in policy1>: <value>
20 <variable2 in policy1>: <value>
21namespaceSelector:
22- name: <namespace1 name>
23 labels:
24 <label key>: <label value>
25- name: <namespace2 name>
26 labels:
27 <label key>: <label value>
Format of user_info.yaml
:
1clusterRoles:
2- admin
3userInfo:
4 username: molybdenum@somecorp.com
Example:
Policy manifest (add_network_policy.yaml
):
1apiVersion: kyverno.io/v1
2kind: ClusterPolicy
3metadata:
4 name: add-networkpolicy
5spec:
6 rules:
7 - name: default-deny-ingress
8 match:
9 any:
10 - resources:
11 kinds:
12 - Namespace
13 clusterRoles:
14 - cluster-admin
15 generate:
16 apiVersion: networking.k8s.io/v1
17 kind: NetworkPolicy
18 name: default-deny-ingress
19 namespace: "{{request.object.metadata.name}}"
20 synchronize: true
21 data:
22 spec:
23 # select all pods in the namespace
24 podSelector: {}
25 policyTypes:
26 - 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
):
1policies:
2 - name: add-networkpolicy
3 resources:
4 - name: devtest
5 values:
6 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
:
1policies:
2 - name: <policy1 name>
3 resources:
4 - name: <resource1 name>
5 values:
6 <variable1 in policy1>: <value>
7 <variable2 in policy1>: <value>
8 - name: <resource2 name>
9 values:
10 <variable1 in policy1>: <value>
11 <variable2 in policy1>: <value>
12 - name: <policy2 name>
13 resources:
14 - name: <resource1 name>
15 values:
16 <variable1 in policy2>: <value>
17 <variable2 in policy2>: <value>
18 - name: <resource2 name>
19 values:
20 <variable1 in policy2>: <value>
21 <variable2 in policy2>: <value>
22globalValues:
23 <global variable1>: <value>
24 <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
):
1policies:
2 - name: cm-globalval-example
3 resources:
4 - name: test-global-prod
5 values:
6 request.mode: prod
7globalValues:
8 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
:
1namespaceSelector:
2 - name: <namespace1 name>
3 labels:
4 <namespace label key>: <namespace label value>
5 - name: <namespace2 name>
6 labels:
7 <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
):
1namespaceSelector:
2 - name: test1
3 labels:
4 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
1policies:
2 - name: cm-variable-example
3 rules:
4 - name: example-configmap-lookup
5 values:
6 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
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.
Policy | Resource | Cluster | Namespace | Interpretation |
---|---|---|---|---|
policy.yaml | -r resource.yaml | false | Apply policy from policy.yaml to the resources specified in resource.yaml | |
policy.yaml | -r resourceName | true | Apply policy from policy.yaml to the resource with a given name in the cluster | |
policy.yaml | true | Apply policy from policy.yaml to all the resources in the cluster | ||
policy.yaml | -r resourceName | true | -n=namespaceName | Apply policy from policy.yaml to the resource with a given name in a specific Namespace |
policy.yaml | true | -n=namespaceName | Apply 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
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.
- pass: The resource passes the policy definition. For
validate
rules which are written with adeny
statement, this will not be a possible result.mutate
andgenerate
rules can declare a pass. - skip: The resource does not meet either the
match
orexclude
block, or does not pass thepreconditions
statements. Forvalidate
rules which are written with adeny
statement, this is a possible result. If a rule contains certain conditional anchors which are not satisfied, the result may also be scored as askip
. - fail: The resource does not pass the policy definition. Typically used for
validate
rules with pattern-style policy definitions. - warn: Setting the annotation
policies.kyverno.io/scored
to"false"
on a resource or policy which would otherwise fail will be considered awarn
.
For help with the test
command, pass the -h
flag for extensive output including usage, flags, and sample manifests.
Note
The Kyverno CLI via thetest
command does not embed the Kubernetes control plane components and therefore is not able to perform the types of initial mutations subjected to a resource as part of an in-cluster creation flow. Take care to ensure the manifests you test account for these modifications.Test File Structures
The test declaration file format of kyverno-test.yaml
must be of the following format. In order to quickly generate a sample manifest which you can populate with your specified inputs, use either the --manifest-mutate
or --manifest-validate
command and output the result to a kyverno-test.yaml
file.
1name: mytests
2policies:
3 - <path/to/policy.yaml>
4 - <path/to/policy.yaml>
5resources:
6 - <path/to/resource.yaml>
7 - <path/to/resource.yaml>
8variables: variables.yaml # optional file for declaring variables. see below for example.
9userinfo: user_info.yaml # optional file for declaring admission request information (roles, cluster roles and subjects). see below for example.
10results:
11- policy: <name>
12 rule: <name>
13 resource: <name>
14 resources: # optional, primarily for `validate` rules. One of either `resource` or `resources[]` must be specified. Use `resources[]` when a number of different resources should all share the same test result.
15 - <name_1>
16 - <name_2>
17 namespace: <name> # when testing for a resource in a specific Namespace
18 patchedResource: <file_name.yaml> # when testing a mutate rule this field is required.
19 generatedResource: <file_name.yaml> # when testing a generate rule this field is required.
20 kind: <kind>
21 result: pass
The test declaration consists of the following parts:
- The
policies
element which lists one or more policies to be applied. - The
resources
element which lists one or more resources to which the policies are applied. - 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. - The
userinfo
element which declares admission request data for subjects and roles. Optional depending on policy content. - 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.
1policies:
2 - name: exclude-namespaces-example
3 rules:
4 - name: exclude-namespaces-dynamically
5 values:
6 namespacefilters.data.exclude: asdf
7 resources:
8 - name: nonroot-pod
9 values:
10 namespacefilters.data.exclude: foo
11 - name: root-pod
12 values:
13 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.
1globalValues:
2 request.operation: UPDATE
If policies use a namespaceSelector, these can also be specified in the variables file.
1namespaceSelector:
2 - name: test1
3 labels:
4 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.
1clusterRoles:
2- admin
3userInfo:
4 username: someone@somecorp.com
Testing for subresources in Kind/Subresource
matching format also requires a subresources{}
section in the values file.
1subresources:
2 - subresource:
3 name: <name of subresource>
4 kind: <kind of subresource>
5 group: <group of subresource>
6 version: <version of subresource>
7 parentResource:
8 name: <name of parent resource>
9 kind: <kind of parent resource>
10 group: <group of parent resource>
11 version: <version of parent resource>
Here is an example when testing for subresources:
1subresources:
2 - subresource:
3 name: "deployments/scale"
4 kind: "Scale"
5 group: "autoscaling"
6 version: "v1"
7 parentResource:
8 name: "deployments"
9 kind: "Deployment"
10 group: "apps"
11 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
):
1name: disallow_latest_tag
2policies:
3 - disallow_latest_tag.yaml
4resources:
5 - resource.yaml
6results:
7 - policy: disallow-latest-tag
8 rule: require-image-tag
9 resource: myapp-pod
10 kind: Pod
11 result: pass
12 - policy: disallow-latest-tag
13 rule: validate-image-tag
14 resource: myapp-pod
15 kind: Pod
16 result: pass
1$ kyverno test .
2
3Executing disallow_latest_tag...
4applying 1 policy to 1 resource...
5
6│───│─────────────────────│────────────────────│───────────────────────│────────│
7│ # │ POLICY │ RULE │ RESOURCE │ RESULT │
8│───│─────────────────────│────────────────────│───────────────────────│────────│
9│ 1 │ disallow-latest-tag │ require-image-tag │ default/Pod/myapp-pod │ Pass │
10│ 2 │ 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
):
1policies:
2- name: add-default-resources
3 resources:
4 - name: nginx-demo1
5 values:
6 request.operation: CREATE
7 - name: nginx-demo2
8 values:
9 request.operation: UPDATE
Test manifest (kyverno-test.yaml
):
1name: add-default-resources
2policies:
3 - add-default-resources.yaml
4resources:
5 - resource.yaml
6variables: values.yaml
7results:
8 - policy: add-default-resources
9 rule: add-default-requests
10 resource: nginx-demo1
11 patchedResource: patchedResource1.yaml
12 kind: Pod
13 result: pass
14 - policy: add-default-resources
15 rule: add-default-requests
16 resource: nginx-demo2
17 patchedResource: patchedResource2.yaml
18 kind: Pod
19 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│───│───────────────────────│──────────────────────│─────────────────────────│────────│
10│ 1 │ add-default-resources │ add-default-requests │ default/Pod/nginx-demo1 │ Pass │
11│ 2 │ 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
):
1name: deny-all-traffic
2policies:
3 - add_network_policy.yaml
4resources:
5 - resource.yaml
6results:
7 - policy: add-networkpolicy
8 rule: default-deny
9 resource: hello-world-namespace
10 generatedResource: generatedResource.yaml
11 kind: Namespace
12 result: pass
1$ kyverno test .
2Executing deny-all-traffic...
3applying 1 policy to 1 resource...
4
5│───│───────────────────│──────────────│──────────────────────────────────│────────│
6│ # │ POLICY │ RULE │ RESOURCE │ RESULT │
7│───│───────────────────│──────────────│──────────────────────────────────│────────│
8│ 1 │ 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.
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.
Example:
List available Kyverno custom JMESPath filters. Please refer to the JMESPath documentation page here for extensive details on each custom filter.
1$ kyverno jp -l
2add(any, any) any
3base64_decode(string) string
4base64_encode(string) string
5compare(string, string) bool
6<output abbreviated>
Test a custom JMESPath filter using stdin inputs.
1$ echo '{"foo": "BAR"}' | kyverno jp 'to_lower(foo)'
2"bar"
Test a custom JMESPath filter using an input JSON file. YAML files are also supported.
1$ cat foo
2{"bar": "this-is-a-dashed-string"}
3
4$ kyverno jp -f foo "split(bar, '-')"
5[
6 "this",
7 "is",
8 "a",
9 "dashed",
10 "string"
11]
Test a custom JMESPath filter as well as an upstream JMESPath filter.
1$ kyverno jp -f foo "split(bar, '-') | length(@)"
25
Test a custom JMESPath filter using an expression from a file.
1$ cat add
2add(`1`,`2`)
3
4$ echo {} | kyverno jp -e add
53
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 -f pod.json 'spec.containers[0].name' -u
20busybox
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.
Warning
Theoci
command is experimental and changes to the command and structure may change at any time.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