apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: audit-gateway-api-rbac annotations: policies.kyverno.io/title: Audit Gateway API mutating RBAC policies.kyverno.io/category: Gateway API policies.kyverno.io/severity: medium policies.kyverno.io/description: >- Report ClusterRoles and Roles that grant create/update/patch/delete on gateway.networking.k8s.io resources outside the approved controller set. spec: validationFailureAction: Audit background: true rules: - name: flag-unapproved-gateway-api-mutation match: any: - resources: kinds: - ClusterRole - Role exclude: any: - resources: names: - cluster-admin - admin - edit - system:* - cilium-* - cert-manager-* - grafana-operator* - victoriametrics-operator* - flux-* - cluster-reconciler-flux-system - crd-controller-flux-system - agentgateway-agentgateway-system # Kyverno * does not match '.' — use olm.og* not olm.og.* - olm.og* - aggregate-olm* # Count rules that explicitly mutate Gateway API kinds (no foreach — wildcard # AnyIn on * false-positived every Role). preconditions: all: - key: >- {{ (request.object.rules || `[]`)[? apiGroups != null && contains(apiGroups, 'gateway.networking.k8s.io') && ( contains(verbs, 'create') || contains(verbs, 'update') || contains(verbs, 'patch') || contains(verbs, 'delete') || contains(verbs, 'deletecollection') || contains(verbs, '*') ) && resources != null && ( contains(resources, 'gateways') || contains(resources, 'gateways/status') || contains(resources, 'httproutes') || contains(resources, 'httproutes/status') || contains(resources, 'httproutes/finalizers') || contains(resources, 'grpcroutes') || contains(resources, 'referencegrants') || contains(resources, 'tlsroutes') || contains(resources, 'tcproutes') || contains(resources, 'gatewayclasses') || contains(resources, 'gatewayclasses/status') ) ] | length(@) }} operator: GreaterThan value: 0 validate: message: >- Role grants mutating verbs on gateway.networking.k8s.io resources outside the approved controller set. Review and narrow or add to the policy allowlist. deny: conditions: any: - key: "{{ request.object.kind }}" operator: AnyIn value: - Role - ClusterRole