-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Kyverno Version
1.7.2
Description
A policy with preconditions that limits to operations UPDATE and CREATE, was still partially evaluated in a DELETE operation. Context Variables were evaluated by the policy during the DELETE admission, and returned null because request.object
is null in a DELETE, as per the Kyverno documentation. The context variable evaluating to null caused an error condition, and blocked deleting the resource. Weirdly enough, the policy still runs the preconditions and acknowledges that it should have skipped the resource because of the operation.
We tested this behavior in 1.7.2 and also in 1.8-dev-latest off main.
Suggestion - since some parts of the admission request
object can be null based on the operation, and because Preconditions aren't restricted from using either request.object or context variables, it seems that filtering admission by operation should be supported directly in the match
statement.
12:38:59 ❯ k delete ingress flaggertest-ing-canary
Error from server: admission webhook "validate.kyverno.svc-fail" denied the request:
resource Ingress/flaggertest-ml476k/flaggertest-ing-canary was blocked due to the following policies
ingress-unique-host:
unique-ingress-against-other-ingress-class: 'failed to load context: unable to add
context entry for variable requestIngressClass since it evaluated to nil'
unique-ingress-host-against-services: preconditions not met
In the policy below the evaluation of request.object
in the context variables was not strictly required and was mostly a way of making the final validation expression easier to read. I was able to work around this issue for now by rewriting the validation jmespath expression and cleaning up the context variables.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: ingress-unique-host
spec:
validationFailureAction: enforce
failurePolicy: Fail
rules:
- name: unique-ingress-against-other-ingress-class
match: # match any ingress resource
all:
- resources:
kinds:
- Ingress
context:
- name: requestIngressClass
variable:
jmesPath: request.object.metadata.annotations."kubernetes.io/ingress.class"
# Create a list of ingresses, excluding the ingress we are currently reviewing
- name: ingresses
apiCall:
urlPath: '/apis/networking.k8s.io/v1/ingresses'
jmesPath: items[?metadata.name != '{{ request.object.metadata.name }}']
preconditions:
all:
- key: "{{ request.operation }}"
operator: AnyIn
value:
- CREATE
- UPDATE
validate:
message: >
Ingress must have a unique hostname across different ingress classes
deny:
conditions:
any:
# select ingresses with ingress class that does NOT match the class of the request object
# compare the request object hosts against the selected set of hosts - if they match, deny
- key: '{{ request.object.spec.rules[].host }}'
operator: AnyIn
value: "{{ingresses[?metadata.annotations.\"kubernetes.io/ingress.class\" != '{{ request.object.metadata.annotations.\"kubernetes.io/ingress.class\" }}'].spec.rules[].host }}"
Slack discussion
https://kubernetes.slack.com/archives/CLGR9BJU9/p1661187029836889
Troubleshooting
- I have read and followed the documentation AND the troubleshooting guide.
- I have searched other issues in this repository and mine is not recorded.