From 3879f775b8a151af5f13c7712fa99af3befdbe8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Tailland?= Date: Thu, 20 Aug 2026 11:26:01 +0200 Subject: [PATCH] Globol Policies template --- .../global-policies-pluginbindings.yaml | 118 ++++++++++++++++++ .../global-policies-plugins.yaml | 117 +++++++++++++++++ .../kustomization.yaml | 5 + .../dataplane-template-defaults.yaml | 5 + 4 files changed, 245 insertions(+) create mode 100644 dataplane-globalpolicy-template/global-policies-pluginbindings.yaml create mode 100644 dataplane-globalpolicy-template/global-policies-plugins.yaml create mode 100644 dataplane-globalpolicy-template/kustomization.yaml diff --git a/dataplane-globalpolicy-template/global-policies-pluginbindings.yaml b/dataplane-globalpolicy-template/global-policies-pluginbindings.yaml new file mode 100644 index 0000000..d73d75d --- /dev/null +++ b/dataplane-globalpolicy-template/global-policies-pluginbindings.yaml @@ -0,0 +1,118 @@ +# scope: GlobalInControlPlane — applies each plugin to all traffic in this +# domain's Control Plane, no route/service target needed (verified real +# mechanism, see tasks-rate-limiting-global-binding in +# ~/dev/kong/kube/apis/tasks-api/pluginbindings.yaml). +# +# controlPlaneRef.konnectNamespacedRef.name is ${CONTROL_PLANE_REF_NAME}, +# NOT ${NAME} — the KonnectGatewayControlPlane object created by +# GatewayConfiguration's `mirror` is auto-named by the operator with a +# random suffix (e.g. catalog-dev-bkphl, not catalog-dev), so this value +# can't be derived from other vars. Currently looked up manually after the +# Gateway/GatewayConfiguration first reconcile and filled in per domain's +# kustomization.yaml — a two-phase step, same as the real reference +# implementation's kong-rc6s4. The self-service automation pipeline +# (terraform-konnect-control-plane / konnect-platform, still stubs) should +# populate this automatically once it exists — see STATUS.md. +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-openid-connect-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-openid-connect + scope: GlobalInControlPlane +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-rate-limiting-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-rate-limiting + scope: GlobalInControlPlane +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-cors-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-cors + scope: GlobalInControlPlane +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-request-size-limiting-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-request-size-limiting + scope: GlobalInControlPlane +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-correlation-id-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-correlation-id + scope: GlobalInControlPlane +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-hide-5xx-details-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-hide-5xx-details + scope: GlobalInControlPlane +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-prometheus-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-prometheus + scope: GlobalInControlPlane +--- +apiVersion: configuration.konghq.com/v1alpha1 +kind: KongPluginBinding +metadata: + name: ${NAME}-opentelemetry-binding +spec: + controlPlaneRef: + type: konnectNamespacedRef + konnectNamespacedRef: + name: ${CONTROL_PLANE_REF_NAME} + pluginRef: + name: ${NAME}-opentelemetry + scope: GlobalInControlPlane diff --git a/dataplane-globalpolicy-template/global-policies-plugins.yaml b/dataplane-globalpolicy-template/global-policies-plugins.yaml new file mode 100644 index 0000000..eeb9755 --- /dev/null +++ b/dataplane-globalpolicy-template/global-policies-plugins.yaml @@ -0,0 +1,117 @@ +# Global (per-domain-CP) baseline policies — security, API behavior +# consistency, observability. Bound via global-policies-pluginbindings.yaml +# with scope: GlobalInControlPlane (applies to all traffic in this domain's +# Control Plane, no per-route/service target needed — verified mechanism, +# see ~/dev/kong/kube/apis/tasks-api/pluginbindings.yaml's +# tasks-rate-limiting-global-binding). +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-openid-connect +plugin: openid-connect +config: + issuer: ${OIDC_ISSUER} + # Whitelist of every audience valid anywhere in this domain, not one + # audience — a domain can expose several APIs, each with its own audience. + # This global check only proves "this token belongs to *some* API of this + # domain, minted by our IdP" — narrowing to the *specific* API's own + # audience happens again at that API's own KongService/Route (defense in + # depth: two independent openid-connect instances, Kong runs both on every + # request, verified — see STATUS.md). JWT_AUDIENCE_WHITELIST is a single + # var holding the whole YAML flow-sequence as a string (e.g. + # '["catalog-api", "catalog-mcp"]') because postBuild.substitute does + # plain text substitution, not list generation — grows as the domain gains + # APIs, set in policies-kustomization.yaml, not here. + audience_required: ${JWT_AUDIENCE_WHITELIST} + auth_methods: + - bearer + display_errors: false # never leak IdP/token internals in error responses +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-rate-limiting +plugin: rate-limiting-advanced +config: + limit: + - ${RATE_LIMIT_MINUTE} + window_size: + - 60 + sync_rate: -1 + strategy: local +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-cors +plugin: cors +config: + origins: + - ${CORS_ORIGINS} + methods: + - GET + - POST + - PUT + - PATCH + - DELETE + - OPTIONS + credentials: true +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-request-size-limiting +plugin: request-size-limiting +config: + allowed_payload_size: ${REQUEST_MAX_BODY_SIZE} +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-correlation-id +plugin: correlation-id +config: + header_name: X-Correlation-ID + generator: uuid + echo_downstream: true +--- +# Hides whatever the backend actually returned on 5xx (stack traces, DB +# errors, etc.) behind a standard body. Only covers responses from a +# successfully-contacted backend ("service"-origin errors) — Kong's own +# generated errors (502/503/504 before reaching the backend, timeouts) are +# NOT covered by this plugin, that's the exit-transformer / Enterprise +# question still pending. +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-hide-5xx-details +plugin: response-transformer-advanced +config: + replace: + body: '{"error": "internal_server_error", "message": "An unexpected error occurred."}' + if_status: + - "500" + - "502" + - "503" + - "504" +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-prometheus +plugin: prometheus +config: + status_code_metrics: true + latency_metrics: true + bandwidth_metrics: true + upstream_health_metrics: true +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: ${NAME}-opentelemetry +plugin: opentelemetry +config: + endpoint: ${OTEL_ENDPOINT} + resource_attributes: + service.name: ${NAME} diff --git a/dataplane-globalpolicy-template/kustomization.yaml b/dataplane-globalpolicy-template/kustomization.yaml new file mode 100644 index 0000000..ff6a266 --- /dev/null +++ b/dataplane-globalpolicy-template/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - global-policies-plugins.yaml + - global-policies-pluginbindings.yaml diff --git a/kong-platform/dataplane-template-defaults.yaml b/kong-platform/dataplane-template-defaults.yaml index 5349a84..f90da9e 100644 --- a/kong-platform/dataplane-template-defaults.yaml +++ b/kong-platform/dataplane-template-defaults.yaml @@ -15,3 +15,8 @@ data: GATEWAY_IMAGE: kong/kong-gateway:3.15 REPLICAS: "1" TLS_ISSUER_KIND: ClusterIssuer + OIDC_ISSUER: https://keycloak.sttlab.eu/realms/sttlab # Keycloak today, but this template shouldn't assume it stays that way + CORS_ORIGINS: https://*.sttlab.local + RATE_LIMIT_MINUTE: "300" + REQUEST_MAX_BODY_SIZE: "10" # MB + OTEL_ENDPOINT: PLACEHOLDER # no OTel collector deployed on this cluster yet