# 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 namespace: ${NAMESPACE} 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 namespace: ${NAMESPACE} 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 namespace: ${NAMESPACE} 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 namespace: ${NAMESPACE} plugin: request-size-limiting config: allowed_payload_size: ${REQUEST_MAX_BODY_SIZE} --- apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: ${NAME}-correlation-id namespace: ${NAMESPACE} 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 namespace: ${NAMESPACE} 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 namespace: ${NAMESPACE} 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 namespace: ${NAMESPACE} plugin: opentelemetry config: endpoint: ${OTEL_ENDPOINT} resource_attributes: service.name: ${NAME}