From f7eab5490a4c0aa82b3f5ede8cfc78ce32906589 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Tue, 20 Oct 2026 18:23:12 +0200 Subject: [PATCH] test(kyverno): pin host access policy behavior --- ...est-validate-kyverno-fixture-evaluation.sh | 11 ++ .../kyverno-test.yaml | 65 +++++- .../validate-host-restrictions/resources.yaml | 186 ++++++++++++++++++ 3 files changed, 261 insertions(+), 1 deletion(-) diff --git a/scripts/tests/test-validate-kyverno-fixture-evaluation.sh b/scripts/tests/test-validate-kyverno-fixture-evaluation.sh index 20399975c9..a0eb9591ea 100755 --- a/scripts/tests/test-validate-kyverno-fixture-evaluation.sh +++ b/scripts/tests/test-validate-kyverno-fixture-evaluation.sh @@ -321,6 +321,17 @@ yq -i '(.spec.rules[] | select(.name == "teams-allow-listed") | .validate.deny.c "${root}/${policies}/restrict-github-team-management.yaml" expect_fail "an evaluated policy with the same edit" "${root}" 1 "Want pass, got fail" +# #5133: the host-access baseline must reject a permission broadening in each +# general rule. Keep the rule and scope intact so this proves that the denial +# resources are evaluated, rather than merely detecting a missing rule name. +for host_rule in disallow-host-path disallow-host-namespaces; do + root="$(copy "weaken-${host_rule}" validate-host-restrictions)" + HOST_RULE="${host_rule}" yq -i \ + '(.spec.rules[] | select(.name == strenv(HOST_RULE)) | .validate.pattern) = {"spec": {}}' \ + "${root}/${policies}/validate-host-restrictions.yaml" + expect_fail "weakened ${host_rule}" "${root}" 1 "kyverno test tests failed" +done + # A fixture whose expectation is wrong still fails through kyverno itself. root="$(copy wrong-expectation restrict-tenant-issuer-refs)" yq -i '(.results[] | select(.result == "fail") | .result) = "pass"' \ diff --git a/tests/validate-host-restrictions/kyverno-test.yaml b/tests/validate-host-restrictions/kyverno-test.yaml index a0ddfccc21..495d8ee9f2 100644 --- a/tests/validate-host-restrictions/kyverno-test.yaml +++ b/tests/validate-host-restrictions/kyverno-test.yaml @@ -2,7 +2,7 @@ apiVersion: cli.kyverno.io/v1alpha1 kind: Test metadata: - name: validate-host-restrictions-host-users + name: validate-host-restrictions policies: - >- ../../k8s/bases/infrastructure/cluster-policies/best-practices/validate-host-restrictions.yaml @@ -12,6 +12,69 @@ resources: # CLI reports every resource "Excluded" and the fixture passes vacuously. variables: values.yaml results: + - policy: validate-host-restrictions + rule: disallow-host-path + resources: + - userns-absent/ordinary-pod + - userns-absent/explicit-false + kind: Pod + result: pass + - policy: validate-host-restrictions + rule: disallow-host-path + resources: + - userns-absent/host-path + - userns-absent/helper-pod-create-pvc + - observability-app/namespace-lookalike + kind: Pod + result: fail + - policy: validate-host-restrictions + rule: disallow-host-path + resources: + - observability/infrastructure-pod + kind: Pod + result: skip + - policy: validate-host-restrictions + rule: disallow-host-namespaces + resources: + - userns-absent/ordinary-pod + - userns-absent/explicit-false + kind: Pod + result: pass + - policy: validate-host-restrictions + rule: disallow-host-namespaces + resources: + - userns-absent/host-network + - userns-absent/host-pid + - userns-absent/host-ipc + - userns-absent/helper-pod-create-pvc + - observability-app/namespace-lookalike + kind: Pod + result: fail + - policy: validate-host-restrictions + rule: disallow-host-namespaces + resources: + - observability/infrastructure-pod + kind: Pod + result: skip + # The cnpg label selector disables autogen for the entire current policy. + # These are genuine exclusions of the declared Pod rules, not invented + # autogen-* rows (which the CLI can misleadingly count as passing). + - policy: validate-host-restrictions + rule: disallow-host-path + resources: + - userns-absent/ordinary-deployment + - userns-absent/host-access-deployment + - observability/infrastructure-deployment + kind: Deployment + result: skip + - policy: validate-host-restrictions + rule: disallow-host-namespaces + resources: + - userns-absent/ordinary-deployment + - userns-absent/host-access-deployment + - observability/infrastructure-deployment + kind: Deployment + result: skip # The regression the mutate rule's conditional anchor cannot catch. - policy: validate-host-restrictions rule: disallow-host-users diff --git a/tests/validate-host-restrictions/resources.yaml b/tests/validate-host-restrictions/resources.yaml index 8283650aae..709f7734ca 100644 --- a/tests/validate-host-restrictions/resources.yaml +++ b/tests/validate-host-restrictions/resources.yaml @@ -75,3 +75,189 @@ spec: containers: - name: app image: registry.k8s.io/pause:3.10 +--- +apiVersion: v1 +kind: Pod +metadata: + name: ordinary-pod + namespace: userns-absent +spec: + containers: + - name: app + image: registry.k8s.io/pause:3.10 + volumes: + - name: scratch + emptyDir: {} +--- +apiVersion: v1 +kind: Pod +metadata: + name: explicit-false + namespace: userns-absent +spec: + hostNetwork: false + hostPID: false + hostIPC: false + containers: + - name: app + image: registry.k8s.io/pause:3.10 +--- +apiVersion: v1 +kind: Pod +metadata: + name: host-path + namespace: userns-absent +spec: + containers: + - name: app + image: registry.k8s.io/pause:3.10 + volumes: + - name: host + hostPath: + path: /fixture +--- +apiVersion: v1 +kind: Pod +metadata: + name: host-network + namespace: userns-absent +spec: + hostNetwork: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 +--- +apiVersion: v1 +kind: Pod +metadata: + name: host-pid + namespace: userns-absent +spec: + hostPID: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 +--- +apiVersion: v1 +kind: Pod +metadata: + name: host-ipc + namespace: userns-absent +spec: + hostIPC: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 +--- +# A familiar provisioner Pod name must not exempt another namespace. +apiVersion: v1 +kind: Pod +metadata: + name: helper-pod-create-pvc + namespace: userns-absent +spec: + hostNetwork: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 + volumes: + - name: host + hostPath: + path: /fixture +--- +# The infrastructure namespace exclusion is exact, not a prefix match. +apiVersion: v1 +kind: Pod +metadata: + name: namespace-lookalike + namespace: observability-app +spec: + hostNetwork: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 + volumes: + - name: host + hostPath: + path: /fixture +--- +apiVersion: v1 +kind: Pod +metadata: + name: infrastructure-pod + namespace: observability +spec: + hostNetwork: true + hostPID: true + hostIPC: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 + volumes: + - name: host + hostPath: + path: /fixture +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ordinary-deployment + namespace: userns-absent +spec: + selector: + matchLabels: + app: ordinary + template: + metadata: + labels: + app: ordinary + spec: + containers: + - name: app + image: registry.k8s.io/pause:3.10 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: host-access-deployment + namespace: userns-absent +spec: + selector: + matchLabels: + app: host-access + template: + metadata: + labels: + app: host-access + spec: + hostNetwork: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 + volumes: + - name: host + hostPath: + path: /fixture +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: infrastructure-deployment + namespace: observability +spec: + selector: + matchLabels: + app: infrastructure + template: + metadata: + labels: + app: infrastructure + spec: + hostNetwork: true + containers: + - name: app + image: registry.k8s.io/pause:3.10 + volumes: + - name: host + hostPath: + path: /fixture