All Kyverno components, including validation, appear to ignore resources with a deletionTimestamp
. A ClusterPolicy or Policy with validationFailureAction: Enforce
may be bypassed by beginning deletion (finalization) of a resource before updating it. Deletion may last indefinitely if an unhandled finalizer is added to the resource before beginning deletion.
Many Kubernetes resources such as Pods are effectively "dead" as soon as they begin terminating. Even though the image:
field of a Pod is mutable, modifications to a Pod's spec:
are ignored during termination and the new image is not executed. Other resource kinds may not handle finalization however, or may handle it inconsistently. ConfigMaps are completely usable during finalization. It appears that during finalization, updates to LoadBalancer Services may be ignored and remain pending. However, NodePort Services updated during finalization will create a listening NodePort. CRD's behavior during finalization will vary with each custom controllers' implementation.
Because most policies and RBAC would not deny adding finalizers or deletion of resources, I believe this allows an attacker to bypass any Kyverno policy. Impact is limited if fields of the resource are immutable or updates to the resource are ignored during deletion. Policies on Pods appear to be safe because updates to the resource are ignored during termination.
I have not reviewed Kyverno's behavior for mutation, generation, image verification, etc. but it looks like Kyverno handles deletionTimestamp
similarly in each of them. I am less sure what users' security expectations are for these and if they should also be considered vulnerabilities. See the following areas of Kyverno's source code for various features' handling of deletionTimestamp
:
- https://github.com/kyverno/kyverno/blob/b2340785fc3cdf4244a5ef97e63bea3cd96b5a08/pkg/webhooks/resource/validation/validation.go#L89-L91
- https://github.com/kyverno/kyverno/blob/b2340785fc3cdf4244a5ef97e63bea3cd96b5a08/pkg/webhooks/resource/mutation/mutation.go#L87-L89
- https://github.com/kyverno/kyverno/blob/b2340785fc3cdf4244a5ef97e63bea3cd96b5a08/pkg/policy/generate.go#L124-L126
- https://github.com/kyverno/kyverno/blob/b2340785fc3cdf4244a5ef97e63bea3cd96b5a08/pkg/webhooks/resource/updaterequest.go#L37-L40
- https://github.com/kyverno/kyverno/blob/b2340785fc3cdf4244a5ef97e63bea3cd96b5a08/pkg/webhooks/resource/imageverification/handler.go#L104
- https://github.com/kyverno/kyverno/blob/b2340785fc3cdf4244a5ef97e63bea3cd96b5a08/pkg/background/common/resource.go#L35-L38
Please see the proof of concept exploit.sh
script below. Tested on Kyverno v1.9.2 on both k3s and vanilla Kubernetes v1.26.3. The hostname in the final curl
command may need to be edited depending on your environment. You may also need to run the commented out helm repo
commands.