Announcing Kyverno Release 1.13!

Kyverno 1.13 released with Sigstore bundle verification, exceptions for validatingAdmissionPolicies, new assertion trees, generate enhancments, enhanced ValidatingAdmissionPolicy and PolicyException support, and tons more!

Kyverno 1.13 contains over 700 changes from 39 contributors! In this blog, we will highlight some of the major changes and enhancements for the release.

kyverno

Major Features

Sigstore Bundle Verification

Kyverno 1.13 introduces support for verifying container images signatures that use the sigstore bundle format. This enables seamless support for GitHub Artifact Attestations to be verified using verification type SigstoreBundle

The following example verifies images containing SLSA Provenance created and signed using GitHub Artifact Attestation.

Here is an example policy:

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4 name: sigstore-image-verification
 5spec:
 6 validationFailureAction: Enforce
 7 webhookTimeoutSeconds: 30
 8 rules:
 9 - match:
10     any:
11     - resources:
12         kinds:
13         - Pod
14   name: sigstore-image-verification
15   verifyImages:
16   - imageReferences:
17     - "*"
18     type: SigstoreBundle
19     attestations:
20     - type: https://slsa.dev/provenance/v1
21       attestors:
22       - entries:
23         - keyless:
24             issuer: https://token.actions.githubusercontent.com
25             subject: https://github.com/nirmata/github-signing-demo/.github/workflows/build-attested-image.yaml@refs/heads/main
26             rekor:
27                 url: https://rekor.sigstore.dev
28             additionalExtensions:
29               githubWorkflowTrigger: push
30               githubWorkflowName: build-attested-image
31               githubWorkflowRepository: nirmata/github-signing-demo
32       conditions:
33       - all:
34         - key: "{{ buildDefinition.buildType }}"
35           operator: Equals
36           value: "https://actions.github.io/buildtypes/workflow/v1"
37         - key: "{{ buildDefinition.externalParameters.workflow.repository }}"
38           operator: Equals
39           value: "https://github.com/nirmata/github-signing-demo"

The demo repository is available at: https://github.com/nirmata/github-signing-demo.

Exceptions for ValidatingAdmissionPolicies

Kyverno 1.13 introduces the ability to leverage PolicyException declarations while auto-generating Kubernetes ValidatingAdmissionPolicies directly from Kyverno policies that use the validate.cel subrule.

The resources specified within the PolicyException are then used to populate the matchConstraints.excludeResourceRules field of the generated ValidatingAdmissionPolicy, effectively creating exclusions for those resources. This functionality is illustrated below with an example of a Kyverno ClusterPolicy and a PolicyException, along with the resulting ValidatingAdmissionPolicy.

Kyverno policy:

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: disallow-host-path
 5spec:
 6  background: false
 7  rules:
 8    - name: host-path
 9      match:
10        any:
11        - resources:
12            kinds:
13            - Deployment
14            - StatefulSet
15            operations:
16            - CREATE
17            - UPDATE
18            namespaceSelector:
19              matchExpressions:
20                - key: type 
21                  operator: In
22                  values: 
23                  - connector
24      validate:
25        failureAction: Audit
26        cel:
27          expressions:
28            - expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
29              message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

PolicyException:

 1apiVersion: kyverno.io/v2
 2kind: PolicyException
 3metadata:
 4  name: policy-exception
 5spec:
 6  exceptions:
 7  - policyName: disallow-host-path
 8    ruleNames:
 9    - host-path
10  match:
11    any:
12    - resources:
13        kinds:
14        - Deployment
15        names:
16        - important-tool
17        operations:
18        - CREATE
19        - UPDATE

The generated ValidatingAdmissionPolicy and its binding are as follows:

 1apiVersion: admissionregistration.k8s.io/v1
 2kind: ValidatingAdmissionPolicy
 3metadata:
 4  labels:
 5    app.kubernetes.io/managed-by: kyverno
 6  name: disallow-host-path
 7  ownerReferences:
 8  - apiVersion: kyverno.io/v1
 9    kind: ClusterPolicy
10    name: disallow-host-path
11spec:
12  failurePolicy: Fail
13  matchConstraints:
14    resourceRules:
15    - apiGroups:
16      - apps
17      apiVersions:
18      - v1
19      operations:
20      - CREATE
21      - UPDATE
22      resources:
23      - deployments
24      - statefulsets
25    namespaceSelector:
26      matchExpressions:
27      - key: type
28        operator: In
29        values:
30        - connector
31    excludeResourceRules:
32    - apiGroups:
33      - apps
34      apiVersions:
35      - v1
36      operations:
37      - CREATE
38      - UPDATE
39      resourceNames:
40      - important-tool
41      resources:
42      - deployments
43  validations:
44  - expression: '!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume,
45      !has(volume.hostPath))'
46    message: HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath
47      must be unset.
48---
49apiVersion: admissionregistration.k8s.io/v1
50kind: ValidatingAdmissionPolicyBinding
51metadata:
52  labels:
53    app.kubernetes.io/managed-by: kyverno
54  name: disallow-host-path-binding
55  ownerReferences:
56  - apiVersion: kyverno.io/v1
57    kind: ClusterPolicy
58    name: disallow-host-path
59spec:
60  policyName: disallow-host-path
61  validationActions: [Audit, Warn]

In addition, Kyverno policies targeting resources within a specific namespace will now generate a ValidatingAdmissionPolicy that utilizes the matchConstraints.namespaceSelector field to scope its enforcement to that namespace.

Policy snippet:

 1match:
 2  any:
 3  - resources:
 4      kinds:
 5      - Deployment
 6      operations:
 7      - CREATE
 8      - UPDATE
 9      namespaces:
10      - production
11      - staging

The generated ValidatingAdmissionPolicy:

 1matchConstraints:
 2  namespaceSelector:
 3    matchExpressions:
 4    - key: kubernetes.io/metadata.name
 5      operator: In
 6      values:
 7      - production
 8      - staging
 9  resourceRules:
10  - apiGroups:
11    - apps
12    apiVersions:
13    - v1
14    operations:
15    - CREATE
16    - UPDATE
17    resources:
18    - deployments

Validation Rules with Assertion Trees

Kyverno-JSON allows Kyverno policies to be used anywhere, even for non-Kubernetes workloads. It introduces the powerful concept of assertion trees.

Previously the Kyverno CLI added support for assertion trees, and now in Release 1.13 assertion trees can also be used in validation rules as a sub-type.

Here is an example of a policy that uses an assertion tree to deny pods from using the default service account:

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4 name: disallow-default-sa
 5spec:
 6 validationFailureAction: Enforce
 7 rules:
 8 - match:
 9     any:
10     - resources:
11         kinds:
12         - Pod
13   name: disallow-default-sa
14   validate:
15     message: default ServiceAccount should not be used
16     assert:
17       object:
18         spec:
19           (serviceAccountName == ‘default’): false

Other Features and Enhancements

Generate Changes

The foreach declaration allows the generation of multiple target resources of sub-elements in resource declarations. Each foreach entry must contain a list attribute, written as a JMESPath expression without braces, that defines sub-elements it processes.

Here is an example of creating networkpolicies for a list of Namespaces, the namespaces are stored in a ConfigMap which can be easily configured dynamically.

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4 name: foreach-generate-data
 5spec:
 6 rules:
 7 - match:
 8     any:
 9     - resources:
10         kinds:
11         - ConfigMap
12   name: k-kafka-address
13   generate:
14     generateExisting: false
15     synchronize: true
16     orphanDownstreamOnPolicyDelete: false
17     foreach:
18       - list: request.object.data.namespaces | split(@, ‘,’)
19         apiVersion: networking.k8s.io/v1
20         kind: NetworkPolicy
21         name: my-networkpolicy-{{element}}-{{ elementIndex }}
22         namespace: ‘{{ element }}’
23         data:
24           metadata:
25             labels:
26               request.namespace: ‘{{ request.object.metadata.name }}’
27               element: ‘{{ element }}’
28               elementIndex: ‘{{ elementIndex }}’
29           spec:
30             podSelector: {}
31             policyTypes:
32             - Ingress
33             - Egress

The triggering ConfigMap is defined as follows, the data contains a namespaces field that defines multiple namespaces.

1kind: ConfigMap
2apiVersion: v1
3metadata:
4  name: default-deny
5  namespace: default
6data:
7  namespaces: foreach-ns-1,foreach-ns-2

Similarly, below is an example of a clone source type of foreach declaration that clones the source Secret into a list of matching existing namespaces which is stored in the same ConfigMap as above.

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: foreach-clone
 5spec:
 6  rules:
 7  - match:
 8      any:
 9      - resources:
10          kinds:
11          - ConfigMap
12	   namespaces:
13          - default
14    name: k-kafka-address
15    generate:
16      generateExisting: false
17      synchronize: true
18      foreach:
19        - list: request.object.data.namespaces | split(@, ',')
20          apiVersion: v1
21          kind: Secret
22          name: cloned-secret-{{ elementIndex }}-{{ element }}
23          namespace: '{{ element }}'
24          clone:
25            namespace: default
26            name: source-secret

In addition, each foreach declaration supports the following declarations: Contex and Preconditions. For more information please see Kyverno documentation.

This release also allows updates to the generate rule pattern. In addition to deletion, if the triggering resource is altered in a way such that it no longer matches the definition in the rule, that too will cause the removal of the downstream resource.

API call enhancements

Default Values

In the case where the API server returns an error, apiCall.default can be used to provide a fallback value for the API call context entry.

The following example shows how to add default value to context entries:

1    context:
2    - name: currentnamespace
3      apiCall:
4        urlPath: “/api/v1/namespaces/{{ request.namespace }}”
5        jmesPath: metadata.name
6        default: default

Custom Headers

Kyverno Service API calls now also support custom headers. This can be useful for authentication or adding other HTTP request headers. Here is an example of adding a token in the HTTP Authorization header:

 1     context:
 2        - name: result
 3          apiCall:
 4            method: POST
 5            data:
 6              - key: foo
 7                value: bar
 8              - key: namespace
 9                value: "{{ `{{ request.namespace }}` }}"
10            service:
11              url: http://my-service.svc.cluster.local/validation
12              headers:
13                - key: "UserAgent"
14                  value: "Kyverno Policy XYZ"
15                - key: "Authorization"
16                  value: "Bearer {{ MY_SECRET }}"

Policy Report Enhancements

Reports for Mutate and Generate rules

In addition to validate and verifyImages rules, Kyverno 1.13 supports reporting for generate and mutate, including mutate existing policies, to record policy results. The container flag --enableReporting can be used to enable or disable reports for specific rule types. It allows the comma-separated values, validate, mutate, mutateExisting, generate, and imageVerify. See details here.

A result entry will be audited in the policy report for rule decision:

 1apiVersion: wgpolicyk8s.io/v1alpha2
 2kind: PolicyReport
 3metadata:
 4  labels:
 5    app.kubernetes.io/managed-by: kyverno
 6  namespace: default
 7results:
 8- message: mutated Pod/good-pod in namespace default
 9  policy: add-labels
10  result: pass
11  rule: add-labels
12  scored: true
13  source: kyverno
14scope:
15  apiVersion: v1
16  kind: Pod
17  name: good-pod
18  namespace: default
19...

Note that the proper permissions need to be granted to the reports controller, a warning message will be returned upon policy admission if no RBAC permission is configured.

Custom Data in Reports

A new field reportProperties is introduced to custom data in policy reports. For example, a validate rule below adds two additional entries operation and objName to the policy reports:

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: require-owner
 5spec:
 6  background: false
 7  rules:
 8  - match:
 9      any:
10      - resources:
11          kinds:
12          - Namespace
13    name: check-owner
14    context:
15    - name: objName
16      variable:
17        jmesPath: request.object.metadata.name
18    reportProperties:
19      operation: ‘{{ request.operation }}’
20      objName: ‘{{ objName }}’
21    validate:
22      validationFailureAction: Audit
23      message: The `owner` label is required for all Namespaces.
24      pattern:
25        metadata:
26          labels:
27            owner: ?*

You can find the two custom entries added to results.properties:

 1apiVersion: wgpolicyk8s.io/v1alpha2
 2kind: ClusterPolicyReport
 3metadata:
 4  ownerReferences:
 5  - apiVersion: v1
 6    kind: Namespace
 7    name: bar
 8results:
 9- message: validation rule ‘check-owner’ passed.
10  policy: require-owner
11  result: pass
12  rule: check-owner
13  scored: true
14  source: kyverno
15  properties:
16    objName: bar
17    operation: CREATE
18scope:
19  apiVersion: v1
20  kind: Namespace
21  name: bar

GlobalContextEntries Enhancements

API Call Retry

Kyverno’s GlobalContextEntry provides a powerful mechanism to fetch external data and use it within policies. When leveraging the apiCall feature to retrieve data from an API, transient network issues can sometimes hinder successful retrieval.

To address this, Kyverno now offers built-in retry logic for API calls within GlobalContextEntry. You can now optionally specify a retryLimit for your API calls:

1apiVersion: kyverno.io/v2alpha1
2kind: GlobalContextEntry
3metadata:
4  name: gctxentry-apicall-correct
5spec:
6  apiCall:
7    urlPath: "/apis/apps/v1/namespaces/test-globalcontext-apicall-correct/deployments"
8    refreshInterval: 1h
9    retryLimit: 3

The retryLimit field determines the number of times Kyverno will attempt to make the API call if it initially fails. This field is optional and defaults to 3, ensuring a reasonable level of resilience against temporary network hiccups.

By incorporating this retry mechanism, Kyverno further strengthens its ability to reliably fetch external data, ensuring your policies can function smoothly even in the face of occasional connectivity issues. This enhancement improves the overall robustness and dependability of your Kubernetes policy enforcement framework.

CLI-based Injection of Global Context Entries

Kyverno CLI now allows you to dynamically inject global context entries using a Values file. This feature facilitates flexible policy testing and execution by simulating different scenarios without modifying GlobalContextEntry resources in your cluster.

You can now define global values and rule-specific values within the Values file, providing greater control over policy evaluation during testing.

 1apiVersion: cli.kyverno.io/v1alpha1
 2kind: Value
 3metadata:
 4  name: values
 5globalValues:
 6  request.operation: CREATE
 7policies:
 8  - name: gctx
 9    rules:
10      - name: main-deployment-exists
11        values:
12          deploymentCount: 1

In this example, request.operation is set as a global value, and deploymentCount is set for a specific rule in the gctx policy. When using the Kyverno CLI, you can reference this Values file to inject these global context entries into your policy evaluation.

Security Hardening

The Kyverno project strives to be secure and production-ready, while providing ease of use. This release contains important changes to further enhance the security of the project.

Removal of wildcard roles

Prior versions of Kyverno included wildcard view permissions. These have been removed in 1.13 and replaced with a role binding to the system view role.

This change does not impact policy behaviors during admission controls, but may impact users with mutate and generate policies for custom resources, and may impact reporting of policy results for validation rules on custom resources A Helm option was added to upgrade Kyverno without breaking existing policies, see the upgrade guidance here.

Removal of insecure configuration for exceptions

In prior versions, policy exceptions were allowed in all namespaces. This creates a potential security issue, as any user with permission to create a policy exception can bypass policies, even in other namespaces. See CVE-2024-48921 for more details.

This release changes the defaults to disable the policy exceptions and only allows exceptions to be created in a specified namespace. To maintain backward compatibility follow the upgrade guidance.

Warnings for Policy Violations and Mutations

A warning message can now be returned along with admission responses by the policy setting spec.emitWarning, this can be used to report policy violations as well as mutations upon admission events.

Shallow evaluation of Variables

Kyverno performs nested variable substitution by default, this may not be desirable in certain situations. Take the following ConfigMap as an example, it defines a .hcl string content using the same {{ }} notation which is used in Kyverno for variable syntax. In this case, Kyverno needs to be instructed to not attempt to resolve variables in the HCL, this can be achieved by {{- ... }} notation for shallow (one time only) substitution of variables.

 1apiVersion: v1
 2data:
 3  config: |-
 4    from_string
 5    {{ some hcl tempalte }}    
 6kind: ConfigMap
 7metadata:
 8  annotations:
 9  labels:
10    argocd.development.cpl.<removed>.co.at/app: corp-tech-ap-team-ping-ep
11  name: vault-injector-config-http-echo
12  namespace: corp-tech-ap-team-ping-ep

To only substitute the rule data with the HCL, and not perform nested substitutions, the following policy uses the declaration {{- hcl }} for shallow substitution.

 1apiVersion: cli.kyverno.io/v1alphaapiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: vault-auth-backend
 5spec:
 6  validationFailureAction: Audit
 7  background: true
 8  mutateExistingOnPolicyUpdate: true
 9  rules:
10  - name: vault-injector-config-blue-to-green-auth-backend
11    context:
12    - name: hcl
13      variable:
14        jmesPath: replace_all( ‘{{ request.object.data.config }}’, ‘from_string’,‘to_string’)
15    match:
16      any:
17      - resources:
18          kinds:
19          - ConfigMap
20          names:
21          - test-*
22          namespaces:
23          - corp-tech-ap-team-ping-ep
24    mutate:
25      patchStrategicMerge:
26        data:
27          config: ‘{{- hcl }}’
28      targets:
29      - apiVersion: v1
30        kind: ConfigMap
31        name: ‘{{ request.object.metadata.name }}’
32        namespace: ‘{{ request.object.metadata.namespace }}’
33    name: vault-injector-config-blue-to-green-auth-backend

Improved ArgoCD Integration

Kyverno-managed webhook configurations are auto-cleaned up upon uninstallation. This behavior could be broken if Kyverno loses RBAC permissions to do so given the random resources deletion order. This release introduces a finalizer-based cleanup solution to ensure webhooks are removed successfully.

This feature is in beta stage and will be used as the default cleanup strategy in the future.

API Version Management

Kyverno 1.13 introduces new changes in the policy CRDs:

  • Both Policy Exceptions and Cleanup Policies have graduated to a stable version (v2).

  • Several policy settings are deprecated:

    • spec.validationFailureAction
    • spec.validationFailureActionOverrides
    • spec.mutateExistingOnPolicyUpdate
    • spec.generateExisting
  • These are replaced by more granular controls within the rule itself:

    • spec.rules[*].validate.failureAction
    • spec.rules[*].validate.failureActionOverrides
    • spec.rules[].verifyImages[].failureAction
    • spec.rules[*].mutate.mutateExisting
    • spec.rules[*].generate.generateExisting

Note that the deprecated fields will be removed in a future release, so migration to the new settings is recommended.

Conclusion

Kyverno 1.13 promises to be a great release, with many new features, enhancements, and fixes. To get started with Kyverno try the quick start guides or head to the installation section of the docs.

To get the most value out of Kyverno, and check out the available enterprise solutions!

Last modified November 04, 2024 at 7:04 PM PST: fix typo (#1424) (cfa9941)