apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: restrict-route-parentrefs annotations: policies.kyverno.io/title: Restrict route parent Gateway refs policies.kyverno.io/category: Gateway API policies.kyverno.io/severity: high policies.kyverno.io/description: >- HTTPRoutes may only parentRef public Gateways when the route namespace has allow-public, and gateway-internal when it has allow-internal. HTTPRoutes and TCPRoutes require allow-short for gateway-short. spec: validationFailureAction: Enforce background: true rules: - name: parentref-matches-namespace-labels match: any: - resources: kinds: - HTTPRoute context: - name: nslabels apiCall: urlPath: "/api/v1/namespaces/{{ request.namespace }}" jmesPath: "metadata.labels || `{}`" validate: message: >- HTTPRoute parentRefs must match namespace gateway attach labels (gateway.quorate.internal/allow-internal or allow-public). foreach: - list: "request.object.spec.parentRefs[]" deny: conditions: any: - key: >- {{ element.name == 'gateway-relay' && (nslabels."gateway.quorate.internal/allow-public" || '') != 'true' }} operator: Equals value: true - key: >- {{ element.name == 'gateway-internal' && (nslabels."gateway.quorate.internal/allow-internal" || '') != 'true' }} operator: Equals value: true - name: short-parent-label match: any: - resources: kinds: - HTTPRoute - TCPRoute context: - name: nslabels apiCall: urlPath: "/api/v1/namespaces/{{ request.namespace }}" jmesPath: "metadata.labels || `{}`" validate: message: >- Routes attached to gateway-short require the namespace label gateway.quorate.internal/allow-short=true. foreach: - list: "request.object.spec.parentRefs[]" deny: conditions: all: - key: "{{ element.name }}" operator: Equals value: gateway-short - key: "{{ nslabels.\"gateway.quorate.internal/allow-short\" || '' }}" operator: NotEquals value: "true"