[Bug] Resolve context variables correctly if parameter isn't exist according to non-existence jmesPath check
Kyverno Version
1.12
Kubernetes Version
1.29
Kubernetes Platform
AKS
Description
We're using 1.13.4 Kyverno version in Argocd (couldn't find in dropdown). And we've configured Kyverno sidecar policy that injects container and initContainer to our Deployments. Additionally we've configured context variables to optionally overwrite default values from kyverno policy template like this - context: - name: tag variable: jmesPath: request.object.metadata.annotations."annotation1" || '{{ $.Values.image.tag }}'
My understanding is that if annotation(s) in application deployment template doesn't exist then Kyverno default values should be populated but it doesn't. Our current solution is to set annotations and add values.yaml with empty values in application Deployment helm template in such case it works.
I've read this documentation - https://kyverno.io/docs/writing-policies/jmespath/#non-existence-checks , where it's mentioned that "The resulting full expression which will correctly evaluate is {{request.object.metadata.labels.appns || ''}}. This expression reads, “take the value of the key request.object.metadata.labels.appns or, if it does not exist, set it to an empty string”.
So looks like if in our case annotation doesn't exists policy just stops working. I'd like to clarify is it some kind of bug or my query isn't properly formed?
Steps to reproduce
- Add argocd kyverno application -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: kyverno
namespace: argocd
annotations:
argocd.argoproj.io/compare-options: ServerSideDiff=true,IncludeMutationWebhook=true
argocd.argoproj.io/sync-wave: "-1"
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
name: in-cluster
namespace: kyverno
source:
path: charts/kyverno
repoURL: https://your_repo_URL
targetRevision: HEAD
helm:
valueFiles:
- values_dev.yaml
project: infrastructure
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
revisionHistoryLimit: 2
- Add Kyverno policy
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: sidecar
spec:
#for 1.12
#mutateExistingOnPolicyUpdate: true
validationFailureAction: {{ .Values.mode | default "Audit" }}
background: true
webhookTimeoutSeconds: 30
failurePolicy: Fail
rules:
- name: sidecar-rule
skipBackgroundRequests: true
match:
any:
- resources:
kinds:
- Deployment
selector:
matchLabels:
label1: "true"
context:
- name: tag
variable:
jmesPath: request.object.metadata.annotations."annotation1" || '{{ $.Values.image.tag }}'
mutate:
# Specify the mutate targets explicitly
#For 1.13+
mutateExistingOnPolicyUpdate: true # Ensures existing resources are mutated
targets:
- apiVersion: apps/v1
kind: Deployment
name: {{`"{{request.object.metadata.name}}"`}}
namespace: {{`"{{request.object.metadata.namespace}}"`}}
patchStrategicMerge:
metadata:
labels:
label1: "true"
spec:
template:
spec:
{{- with .Values.test }}
initContainers:
- name: init-container
image: "{{ .image.registry }}/{{ .image.repository }}:{{`{{ tag }}`}}"
imagePullPolicy: {{ .image.pullPolicy }}
env:
- name: tag
value: "{{`{{ tag }}`}}"
{{- if .resources }}
resources:
{{- toYaml .resources | nindent 18 }}
{{- end }}
volumeMounts:
- mountPath: /data
name: test-volume
containers:
- name: sidecar
image: "{{ .image.registry }}/{{ .image.repository }}:{{`{{ tag }}`}}"
imagePullPolicy: {{ .image.pullPolicy }}
{{- if .resources }}
resources:
{{- toYaml .resources | nindent 18 }}
{{- end }}
livenessProbe:
{{- .livenessProbe | toYaml | nindent 18 }}
volumeMounts:
- mountPath: /data
name test-volume
volumes:
- emptyDir: {}
name: test-volume
{{- end }}
-
Set some values in kyverno chart values.yaml.
-
On application deployment don't set annotations and set only this label -
apiVersion: apps/v1 kind: Deployment metadata: name: {{ .fullnameOverride }} labels: label1: "true" ...
- Deploy kyverno and application in Argocd and you should observe that Kyverno policy isn't applied on application because it can't find annotations that are set in jmesPath queries. If annotations are set on application deployment helm template then policy works as expected
Expected behavior
When I'm using non-existence jmesPath check I'm expecting that if value in first condition part isn't exist, then second condition executes and populates with Kyverno default template values - context: - name: tag variable: jmesPath: request.object.metadata.annotations."annotation1" || '{{ $.Values.image.tag }}'
According to documentation it should but for some reason doesn't - https://kyverno.io/docs/writing-policies/jmespath/#non-existence-checks
Screenshots
No response
Kyverno logs
Actually I didn't find any errors in Kyverno admission and background controller logs
Slack discussion
No response
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.