feat(keycloak): Gateway-API as an alternative to the two Ingresses
Group 3 of the #114 sweep, first chart. keycloak has TWO Ingress objects - the public hostname and the admin hostname - so it gets TWO HTTPRoutes, with httpRoute.admin.parentRefs falling back to httpRoute.parentRefs exactly as ingress.admin.className falls back to ingress.className: "which data path" is a property of the Gateway in this API, not of the route, so an internal Gateway here is what an internal ingress class is in the other mode. The admin route stays gated on ingress.admin.enabled, because that value is not an Ingress switch - it also decides whether KC_HOSTNAME_ADMIN is set on the Deployment, i.e. whether the admin hostname exists at all. Switching to Gateway mode therefore must not require turning it off. FIXED ALONG THE WAY: the admin Ingress did not hang off ingress.enabled. Measured on origin/main, `helm template -f ci/keycloak/test-values.yaml --set ingress.enabled=false` emitted kc-keycloak-admin-ingress - so "ingress.enabled: false" did not mean "no Ingress", and ingress.clusterIssuer stayed required for an object nobody asked for. It also made Gateway mode impossible: the admin Ingress would have gone on claiming the admin host next to the admin HTTPRoute, one host over two data paths, which is the exact conflict the mutual exclusion exists to prevent. The default render is unchanged; what changed is a combination that could not be coherent. WHAT THIS MODE DROPS, MEASURED ON THE LIVE CLUSTER rather than inferred. On 2026-10-12 BOTH of this chart's Ingress objects in jk-cluster carried nginx.ingress.kubernetes.io/proxy-buffer-size: 16k nginx.ingress.kubernetes.io/proxy-buffers-number: 4 set by the OPERATOR through ingress.annotations and ingress.admin.annotations - the chart sets neither, which is why reading the chart alone does not reveal them. The Gateway API has no annotation channel and no counterpart for proxy buffer sizing; it is implementation policy, not routing. Per decision 1 of #114 the chart renders no policy object, so this is NAMED and not rebuilt, in values.yaml, in the schema and in the Gateway branch of NOTES.txt, with the consequence spelled out in Keycloak's own terms: large headers (JWTs, SAML assertions, long Set-Cookie chains on the login flow) make a too-small buffer answer 502 at the PROXY while Keycloak logs the request as successful. Named and deliberately not touched: four further Ingress objects in the same namespace (keycloak-realm-*-ingress, with app-root) belong to the Helm release jk-cluster-config-fleet-cd-keycloak-realm-ingress, i.e. to another repository. They point at this release's Service under four further hostnames. This chart renders exactly the two routes its own two Ingresses cover. Minor: additive, defaults unchanged. Empty helm template diff against origin/main with ci/keycloak/test-values.yaml. Part of #114
This commit is contained in:
1 parent
d36112aaf6
commit
d0f0d49a93
7 files changed
+470
-13
No files matched your search
@@ -642,6 +642,11 @@ ingress:
|
||||
|
||||
# Extra annotations for the public Ingress; merged with the cert-manager
|
||||
# annotation the chart always sets.
|
||||
#
|
||||
# INERT IN GATEWAY MODE (httpRoute.enabled) - the Gateway API has no
|
||||
# annotation channel for controller behaviour. That matters for THIS chart in
|
||||
# particular: see the httpRoute block below for the proxy-buffer annotations
|
||||
# this installation actually relies on and what their loss looks like.
|
||||
annotations: {}
|
||||
|
||||
admin:
|
||||
@@ -684,4 +689,84 @@ ingress:
|
||||
# annotation. This is where an IP allow-list would go
|
||||
# (nginx.ingress.kubernetes.io/whitelist-source-range) - with the caveat
|
||||
# above firmly in mind.
|
||||
#
|
||||
# INERT IN GATEWAY MODE, like ingress.annotations - see the httpRoute block
|
||||
# below for what this installation actually has in here today and what
|
||||
# losing it costs.
|
||||
annotations: {}
|
||||
|
||||
# THE GATEWAY-API ALTERNATIVE TO THE TWO INGRESSES (Gitea #114).
|
||||
#
|
||||
# Mutually exclusive with ingress.enabled - the render aborts when both are
|
||||
# true, and the message names both value paths. The chart renders ONLY
|
||||
# HTTPRoutes with parentRefs: no Gateway, no class, no Certificate, and no
|
||||
# implementation-specific policy object. Class and certificate sit on the
|
||||
# Gateway and its listeners and belong to the platform (cluster-config), which
|
||||
# is what makes the Gateway implementation replaceable without touching this
|
||||
# chart again.
|
||||
#
|
||||
# TWO ROUTES, mirroring the two Ingresses: the public hostname and the admin
|
||||
# hostname. ingress.admin.enabled keeps gating BOTH forms, because it is not an
|
||||
# Ingress switch - it decides whether KC_HOSTNAME_ADMIN is set on the
|
||||
# Deployment, i.e. whether the admin hostname exists at all.
|
||||
#
|
||||
# WHAT THIS MODE COSTS THIS CHART, MEASURED AND NOT HYPOTHETICAL. On
|
||||
# 2026-10-12 both of this chart's live Ingress objects carried
|
||||
#
|
||||
# nginx.ingress.kubernetes.io/proxy-buffer-size: 16k
|
||||
# nginx.ingress.kubernetes.io/proxy-buffers-number: 4
|
||||
#
|
||||
# set by the OPERATOR through the two annotations blocks above - this chart
|
||||
# sets neither, which is why reading the chart alone does not reveal them. The
|
||||
# Gateway API has no annotation channel and no counterpart for proxy buffer
|
||||
# sizing: it is implementation policy, not routing, so there is nothing here to
|
||||
# render and nothing this chart could promise. The consequence is specific:
|
||||
# Keycloak's responses carry large headers (JWTs, SAML assertions, long
|
||||
# Set-Cookie chains during the login flow), and a proxy whose buffer is too
|
||||
# small answers 502 ITSELF, while Keycloak logs a successful request. The
|
||||
# symptom therefore points at the application and the cause is at the proxy.
|
||||
# Set the equivalent next to the Gateway, in that implementation's own object,
|
||||
# BEFORE moving the host. NOTES.txt prints this in Gateway mode.
|
||||
#
|
||||
# THE GATEWAY-API CRDs MUST BE PRESENT. The chart cannot detect them
|
||||
# (.Capabilities.APIVersions is unreliable at template time) and an HTTPRoute
|
||||
# without them fails at install, so this is a value and not a guess.
|
||||
httpRoute:
|
||||
enabled: false
|
||||
|
||||
# The Gateway(s) the PUBLIC route attaches to - a platform object, usually in
|
||||
# another namespace, whose listener must allow this namespace in
|
||||
# allowedRoutes. Entries are the Gateway API's ParentReference (name, and
|
||||
# optionally namespace, sectionName, port, group, kind), passed through
|
||||
# unchanged:
|
||||
#
|
||||
# parentRefs:
|
||||
# - name: public
|
||||
# namespace: gateway
|
||||
# sectionName: https
|
||||
#
|
||||
# REQUIRED while httpRoute.enabled is true - the render aborts on an empty
|
||||
# list, because a route without a parent is created, is valid and routes
|
||||
# nothing, with no event to say so.
|
||||
parentRefs: []
|
||||
|
||||
# Empty means [ingress.domain], so the public hostname has one source of
|
||||
# truth. ingress.domain is required in every mode in this chart anyway (the
|
||||
# Deployment reads it as KC_HOSTNAME), so setting this list is only for
|
||||
# publishing under a different or an ADDITIONAL name - which is how a
|
||||
# migration from the Ingress runs: the HTTPRoute takes a second hostname
|
||||
# while the Ingress keeps ingress.domain.
|
||||
hostnames: []
|
||||
|
||||
admin:
|
||||
# The admin route's own parent. null/empty falls back to
|
||||
# httpRoute.parentRefs - the exact counterpart of ingress.admin.className
|
||||
# falling back to ingress.className. "Which data path" is a property of the
|
||||
# Gateway in this API rather than of the route, so an INTERNAL Gateway here
|
||||
# is what an internal ingress class is in the other mode. Still not the
|
||||
# access control the ingress.admin paragraph above is about.
|
||||
parentRefs: []
|
||||
|
||||
# Empty means [ingress.admin.domain]. Required (via that value) while
|
||||
# ingress.admin.enabled is true and httpRoute.enabled is true.
|
||||
hostnames: []
|
||||
Reference in new issue
Block a user