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.
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
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 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.
Note
Kyverno CLI in bothapply
and validate
commands 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 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 (Kyverno 1.3.6), and API call context data (Kyverno 1.3.6).
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
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>
23labels:
24 <label key>: <label value>
25- name: <namespace2 name>
26labels:
27 <label key>: <label value>
Example:
Policy manifest (add_network_policy.yaml
):
1apiVersion: kyverno.io/v1
2kind: ClusterPolicy
3metadata:
4 name: add-networkpolicy
5 annotations:
6 policies.kyverno.io/category: Workload Management
7 policies.kyverno.io/description: By default, Kubernetes allows communications across
8 all pods within a cluster. Network policies and, a CNI that supports network policies,
9 must be used to restrict communications. A default NetworkPolicy should be configured
10 for each namespace to default deny all ingress traffic to the pods in the namespace.
11 Application teams can then configure additional NetworkPolicy resources to allow
12 desired traffic to application pods from select sources.
13spec:
14 rules:
15 - name: default-deny-ingress
16 match:
17 resources:
18 kinds:
19 - Namespace
20 generate:
21 kind: NetworkPolicy
22 name: default-deny-ingress
23 namespace: "{{request.object.metadata.name}}"
24 synchronize: true
25 data:
26 spec:
27 # select all pods in the namespace
28 podSelector: {}
29 policyTypes:
30 - 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 resources:
12 kinds:
13 - Pod
14 validate:
15 message: "The value {{ request.mode }} for val1 is not equal to 'dev'."
16 deny:
17 conditions:
18 - key: "{{ request.mode }}"
19 operator: NotEquals
20 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 selector.
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 resources:
12 kinds:
13 - Pod
14 namespaceSelector:
15 matchExpressions:
16 - key: foo.com/managed-state
17 operator: In
18 values:
19 - managed
20 validate:
21 message: "The Pod must end with -nginx"
22 pattern:
23 metadata:
24 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 resources:
19 kinds:
20 - Pod
21 mutate:
22 patchStrategicMerge:
23 metadata:
24 labels:
25 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
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
5 annotations:
6 policies.kyverno.io/category: Workload Management
7 policies.kyverno.io/description: >-
8 As application workloads share cluster resources, it is important to limit resources
9 requested and consumed by each pod. It is recommended to require 'resources.requests'
10 and 'resources.limits' per pod. If a namespace level request or limit is specified,
11 defaults are automatically applied to each pod based on the 'LimitRange' configuration.
12spec:
13 validationFailureAction: audit
14 rules:
15 - name: validate-resources
16 match:
17 resources:
18 kinds:
19 - Pod
20 validate:
21 message: "CPU and memory resource requests and limits are required"
22 pattern:
23 spec:
24 containers:
25 - resources:
26 requests:
27 memory: "?*"
28 cpu: "?*"
29 limits:
30 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 can test multiple policy resources from a Git repository or local folders. The command recursively looks for YAML files with policy test declarations (described below) and then executes those tests. test
is useful when you wish to declare, in advance, what your expected results should be by defining the intent in a manifest. 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.
Run tests on a set of local files:
1kyverno test /path/to/folderContainingTestYamls
Run tests on a Git repo:
Testing on an entire repo by specifying branch name within repo URL:
1kyverno test https://github.com/<ORG>/<REPO>/<BRANCH>
Example:
1kyverno test https://github.com/kyverno/policies/release-1.5
Note
If<BRANCH>
is not provided in this case, the default branch is assumed to be main
.
Testing on a specific directory of the repo by specifying the directory within repo URL, and the branch with --git-branch
flag (shorthand -b
):
1kyverno test https://github.com/<ORG>/<REPO>/<DIR> --git-branch <BRANCH>
Example:
1kyverno test https://github.com/kyverno/policies/pod-security/restricted --git-branch release-1.5
Note
While providing<DIR>
within the repo URL, it is necessary to provide the branch using the --git-branch
or -b
flag, even if it is main
.
Use the -f <fileName.yaml>
flag to set a custom file name which includes test cases. By default, test
will search for a file called kyverno-test.yaml
. The previous file name of test.yaml
is deprecated.
The test declaration file format must be of the following format.
1name: mytests
2policies:
3 - <path/to/policy.yaml>
4 - <path/to/policy.yaml>
5resources:
6 - <path/to/resource.yaml>
7 - <path/to/resource.yaml>
8# optional file for declaring variables. see below for example.
9variables: variables.yaml
10results:
11- policy: <name>
12 rule: <name>
13 resource: <name>
14 kind: <kind>
15 result: pass
16- policy: <name>
17 rule: <name>
18 resource: <name>
19 kind: <kind>
20 result: fail
If needing to pass variables, 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.
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\"]"
The test declaration consists of three (optionally four) 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
results
element which declares the expected results. - The
variables
element which defines a file in which variables and their values are stored for use in the policy test.
The test command executes a test declaration by applying the policies to the resources and comparing the results with the expected results. The test passes if the actual results match the expected results.
Example:
Policy manifest (disallow_latest_tag.yaml
):
1apiVersion: kyverno.io/v1
2kind: ClusterPolicy
3metadata:
4 name: disallow-latest-tag
5 annotations:
6 policies.kyverno.io/category: Best Practices
7 policies.kyverno.io/description: >-
8 The ':latest' tag is mutable and can lead to unexpected errors if the
9 image changes. A best practice is to use an immutable tag that maps to
10 a specific version of an application pod.
11spec:
12 validationFailureAction: audit
13 rules:
14 - name: require-image-tag
15 match:
16 resources:
17 kinds:
18 - Pod
19 validate:
20 message: "An image tag is required."
21 pattern:
22 spec:
23 containers:
24 - image: "*:*"
25 - name: validate-image-tag
26 match:
27 resources:
28 kinds:
29 - Pod
30 validate:
31 message: "Using a mutable image tag e.g. 'latest' is not allowed."
32 pattern:
33 spec:
34 containers:
35 - 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
1kyverno test <PathToDirs>
The example above applies a test on the policy and the resource defined in the test YAML.
# | TEST | RESULT |
---|---|---|
1 | myapp-pod with disallow-latest-tag/require-image-tag | pass |
2 | myapp-pod with disallow-latest-tag/validate-image-tag | pass |
Validate
The validate
command validates that a policy is syntactically valid. It can validate multiple policy resource description files or even an entire folder containing policy resource description files. Currently supports files with resource description in YAML. The policies can also be passed from stdin.
Example:
1kyverno validate /path/to/policy1.yaml /path/to/policy2.yaml /path/to/folderFullOfPolicies
Passing policy from stdin:
1kustomize build nginx/overlays/envs/prod/ | kyverno validate -
Use the -o <yaml/json>
flag to display the mutated policy.
Example:
1kyverno validate /path/to/policy1.yaml /path/to/policy2.yaml /path/to/folderFullOfPolicies -o yaml
Policy can also be validated with CRDs. Use the -c
flag to pass the CRD. You can pass multiple CRD files or even an entire folder containing CRDs.
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 documents and expressions, the jp
subcommand will evaluate any JMESPath expression and supply the output.
Example:
List available Kyverno custom JMESPath filters.
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.
1$ cat foo
2{"foo": "this-is-a-dashed-string"}
3
4$ kyverno jp -f foo "split(foo, '-')"
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(foo, '-') | 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
Version
Prints the version of Kyverno used by the CLI.
Example:
1kyverno version
2Version: 1.4.2
3Time: 2021-08-11T20:09:26Z
4Git commit ID: fb6e0f18ea89c9b60c604e5135f38040fafbc1e4