Skip to content

[BUG] Cannot compare precondition expression's value in `foreach`

Software version numbers State the version numbers of applications involved in the bug.

  • Kubernetes version: 1.23.3
  • Kubernetes platform (if applicable; ex., EKS, GKE, OpenShift): K3d
  • Kyverno version: 1.6 main

Describe the bug A validate.foreach loop using preconditions does not allow existence/non-existence expressions and throws an error like Failed to parse value type doesn't match key type.

To Reproduce Steps to reproduce the behavior:

  1. Apply this policy:
apiVersion : kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-limits-fraction
spec:
  validationFailureAction: enforce
  rules:
  - name: check-memory-requests-limits
    match:
      any:
      - resources:
          kinds:
          - Pod
    preconditions:
    - key: "{{ request.operation }}"
      operator: In
      value:
      - CREATE
      - UPDATE
    validate:
      message: Limits may not exceed 2.5x the requests.
      foreach:
      - list: "request.object.spec.containers"
        preconditions:
          all:
          - key: "{{ element.resources.limits.memory || '' }}"
            operator: NotEquals
            value: ""
          - key: "{{ element.resources.requests.memory || '' }}"
            operator: NotEquals
            value: ""
        deny:
          conditions:
            any:
            - key: "{{ divide('{{ element.resources.limits.memory }}', '{{ element.resources.requests.memory }}') }}"
              operator: GreaterThan
              value: 2.5
  1. Try to apply this resource, which should be blocked yet it is allowed.
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: 100Mi
      limits:
        memory: 300Mi
  1. See in the logs it was skipped because the existence check in the preconditions didn't execute:
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.120183       1 vars.go:378] EngineValidate "msg"="variable substituted" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "path"="/0/key" "value"="CREATE" "variable"="{{ request.operation }}"
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.122463       1 vars.go:378] EngineValidate "msg"="variable substituted" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "path"="/all/0/key" "value"="300Mi" "variable"="{{ element.resources.limits.memory || '' }}"
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.123042       1 vars.go:378] EngineValidate "msg"="variable substituted" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "path"="/all/1/key" "value"="100Mi" "variable"="{{ element.resources.requests.memory || '' }}"
kyverno-94798cfb-rx5w8 kyverno E0129 22:51:56.123775       1 notequal.go:84] EngineValidate "msg"="Failed to parse value type doesn't match key type" "error"="parse error: " "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" 
kyverno-94798cfb-rx5w8 kyverno I0129 22:51:56.123832       1 validation.go:277] EngineValidate "msg"="skip rule" "kind"="Pod" "name"="frontend" "namespace"="default" "policy"="enforce-limits-fraction" "rule"="check-memory-requests-limits" "reason"="preconditions not met"

Expected behavior A precondition(s) in foreach.validate should properly allow existence/non-existence checks like they work outside.

Additional context Observed when implementing https://github.com/kyverno/policies/issues/175