Problem
server.route / adminConsole.route render an HTTPRoute whose only rule is a bare backendRefs. There is no way to express a matches[].path, a filters[] entry, or a raw rules override.
templates/_ingress.tpl:112-116:
rules:
- backendRefs:
- name: {{ .serviceName }}
port: {{ .servicePort }}
values.yaml:744-755 exposes only enabled / hostnames / parentRefs / annotations (identically for adminConsole.route, values.yaml:1045-1056), and values.schema.json sets additionalProperties: false on both route objects, so nothing extra can be passed through either.
The result is that route only works for a dedicated hostname serving authup at /. That is the one topology it supports, and it is not the topology the rest of the chart is built for.
It is not merely missing — it silently emits a wrong manifest
_ingress.tpl:99-104 derives the route hostname from the component's public URL via authup.urlOrigin, and _urls.tpl:58-65 returns scheme://host only — the path is discarded.
So an operator who follows the chart's own documented sub-path setup:
server:
publicUrl: "https://hub.example.com/auth"route:
enabled: trueparentRefs:
- name: my-gateway
gets:
spec:
parentRefs:
- name: my-gatewayhostnames:
- hub.example.comrules:
- backendRefs:
- name: release-authup-serverport: 3000
Per the Gateway API spec, an HTTPRouteRule with unspecified matchesdefaults to a PathPrefix / match, i.e. it matches every request. The chart consumed a /auth public URL, threw the path away, and attached authup as the catch-all backend for a hostname it is meant to share. On a shared-hostname gateway the more specific sibling routes still win their own prefixes, but every unmatched request on that host now lands on the IdP. There is no value that can correct this.
route.annotations cannot substitute
For Ingress, the chart documents the proxy-buffer workaround authup's large token responses need (values.yaml:729-730, README.md:367: "Token responses are large; with ingress-nginx consider proxy-buffer-size 16k+"). For Gateway API there is no annotation equivalent — NGINX Gateway Fabric requires an ExtensionRef filter to a gateway.nginx.org/v1alpha1 SnippetsFilter, which is a first-class spec field, not an annotation. So the route's single knob cannot address the one operational hazard the chart itself flags.
Parity gap against the chart's own design
The Ingress renderer ships four escape hatches — extraPaths, extraHosts, extraTls, extraRules (_ingress.tpl:42-60, values.yaml:736-743) — plus first-class path / pathType (values.yaml:721-723). The HTTPRoute renderer ships none of them, while DESIGN.md:304-307 states that "Sub-path single-host deployments are supported (authup rebases assets off publicUrl's pathname)". That topology is expressible through server.ingress and inexpressible through server.route.
Concrete use case: PrivateAIM/flame-hub
The FLAME Hub umbrella chart serves authup alongside client-ui, server-core, storage and telemetry on one shared hostname, with authup at PathPrefix /auth. It renders this itself (charts/flame-hub/templates/authup/httproute.yaml):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ .Release.Name }}-authup
spec:
parentRefs:
{{- include "flame-hub.gateway.parentRefs" . | nindent 8 }}
hostnames:
- {{ .Values.authup.gatewayApi.hostname | default .Values.global.flameHub.gatewayApi.hostname | quote }}
rules:
- matches:
- path:
type: PathPrefix
value: {{ .Values.authup.gatewayApi.path }} # "/auth"
{{- $rewrite := ne .Values.authup.gatewayApi.path "/" }}
{{- $ngfSnip := .Values.global.flameHub.gatewayApi.nginxGatewayFabric.snippets }}
{{- if or $rewrite $ngfSnip }}
filters:
{{- if $rewrite }}
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
{{- end }}
{{- if $ngfSnip }}
- type: ExtensionRef
extensionRef:
group: gateway.nginx.org
kind: SnippetsFilter
name: {{ .Release.Name }}-authup-ngf-snippets
{{- end }}
{{- end }}
backendRefs:
- name: {{ .Release.Name }}-authup-server-core
port: 3000
paired with (charts/flame-hub/templates/authup/snippetsfilter-timeouts.yaml):
apiVersion: gateway.nginx.org/v1alpha1kind: SnippetsFiltermetadata:
name: {{ .Release.Name }}-authup-ngf-snippetsspec:
snippets:
- context: http.server.locationvalue: | proxy_buffer_size 16k; proxy_buffers 4 16k; proxy_busy_buffers_size 16k;Three things are required and none is expressible: (a)matches[].path PathPrefix /auth, (b) a URLRewrite filter with ReplacePrefixMatch: /, (c) an ExtensionRef filter carrying the proxy buffers.
To be explicit about scope: this does not block flame-hub's migration to the upstream chart. flame-hub keeps its own HTTPRoute and leaves server.route.enabled=false. But it does mean an umbrella consumer of this chart can never use the chart's own routing feature — and that is the deployment shape the chart otherwise targets end to end.
Proposed minimal values API
Raw Gateway API passthrough, in exactly the style route.parentRefs already uses — no new abstraction, no re-modelling of the Gateway API:
server:
route:
enabled: falsehostnames: []parentRefs: []annotations: {}# -- HTTPRoute rule matches (tpl-rendered; [] = the Gateway API default, PathPrefix "/")matches: []# -- HTTPRoute rule filters (tpl-rendered; URLRewrite, RequestHeaderModifier, ExtensionRef, ...)filters: []# -- Full custom rules (tpl-rendered; replaces the generated rule entirely)extraRules: []Template change in templates/_ingress.tpl, replacing lines 112-116:
rules:
{{- if $route.extraRules }}
{{- include "authup.tplvalues.render" (dict "value" $route.extraRules "context" $ctx) | nindent 4 }}
{{- else }}
- {{- if $route.matches }}
matches: {{- include "authup.tplvalues.render" (dict "value" $route.matches "context" $ctx) | nindent 8 }}
{{- end }}
{{- if $route.filters }}
filters: {{- include "authup.tplvalues.render" (dict "value" $route.filters "context" $ctx) | nindent 8 }}
{{- end }}
backendRefs:
- name: {{ .serviceName }}
port: {{ .servicePort }}
{{- end }}
plus the matching values.schema.json entries (the objects are additionalProperties: false today, so the schema must be updated or the new keys are rejected). Applies identically to adminConsole.route.
Optionally, and separately: when matches is empty but the derived/derivable public URL carries a pathname, either default a PathPrefix match from it or fail — rather than silently widening it to /. At minimum the hostnames value comment ("[] = derived from server.publicUrl / ingress hostname", values.yaml:747) should say that the derivation drops the path.
Why the workaround is not acceptable as the answer
The workaround is server.route.enabled=false plus a hand-written HTTPRoute in root extraDeploy (values.yaml:32, rendered through tpl by templates/extra-list.yaml:1-4). It does work — helpers like {{ include "authup.server.fullname" . }} and {{ .Values.server.service.ports.http }} are in scope, so names and ports do not drift. But:
- It makes
route dead weight for its most likely consumer. Anyone deploying this chart as a subchart behind a shared gateway must not use server.route, which is exactly who a Gateway API feature is for. As shipped, the value is nearly ornamental. - The failure is silent, not loud. A user who tries the documented sub-path setup first does not get a render error or a no-op; they get a live catch-all route on a shared hostname.
extraDeploy is only a workaround for the user who already knows the feature is broken. - It forces duplication of everything the chart already renders — labels (
authup.labels), commonAnnotations, namespaceOverride handling, hostname derivation, service name and port — into user-maintained YAML that silently rots across chart upgrades. That is precisely the drift this chart's authup.tplvalues.render design exists to eliminate. - The chart already rejected this answer for Ingress.
ingress.extraRules exists so Ingress users do not have to escape to extraDeploy for a custom rule (values.yaml:742-743). The same rationale applies verbatim to HTTPRoute; the route side just never got it. - The fix is ~10 template lines and 3 values keys, all raw passthrough matching an existing convention in the same file. The cost of closing this is smaller than the cost of documenting the workaround properly.
Problem
server.route/adminConsole.routerender an HTTPRoute whose only rule is a barebackendRefs. There is no way to express amatches[].path, afilters[]entry, or a raw rules override.templates/_ingress.tpl:112-116:values.yaml:744-755exposes onlyenabled/hostnames/parentRefs/annotations(identically foradminConsole.route,values.yaml:1045-1056), andvalues.schema.jsonsetsadditionalProperties: falseon bothrouteobjects, so nothing extra can be passed through either.The result is that
routeonly works for a dedicated hostname serving authup at/. That is the one topology it supports, and it is not the topology the rest of the chart is built for.It is not merely missing — it silently emits a wrong manifest
_ingress.tpl:99-104derives the route hostname from the component's public URL viaauthup.urlOrigin, and_urls.tpl:58-65returnsscheme://hostonly — the path is discarded.So an operator who follows the chart's own documented sub-path setup:
gets:
Per the Gateway API spec, an
HTTPRouteRulewith unspecifiedmatchesdefaults to a PathPrefix/match, i.e. it matches every request. The chart consumed a/authpublic URL, threw the path away, and attached authup as the catch-all backend for a hostname it is meant to share. On a shared-hostname gateway the more specific sibling routes still win their own prefixes, but every unmatched request on that host now lands on the IdP. There is no value that can correct this.route.annotationscannot substituteFor Ingress, the chart documents the proxy-buffer workaround authup's large token responses need (
values.yaml:729-730,README.md:367: "Token responses are large; with ingress-nginx consider proxy-buffer-size 16k+"). For Gateway API there is no annotation equivalent — NGINX Gateway Fabric requires anExtensionReffilter to agateway.nginx.org/v1alpha1 SnippetsFilter, which is a first-classspecfield, not an annotation. So the route's single knob cannot address the one operational hazard the chart itself flags.Parity gap against the chart's own design
The Ingress renderer ships four escape hatches —
extraPaths,extraHosts,extraTls,extraRules(_ingress.tpl:42-60,values.yaml:736-743) — plus first-classpath/pathType(values.yaml:721-723). The HTTPRoute renderer ships none of them, whileDESIGN.md:304-307states that "Sub-path single-host deployments are supported (authup rebases assets offpublicUrl's pathname)". That topology is expressible throughserver.ingressand inexpressible throughserver.route.Concrete use case: PrivateAIM/flame-hub
The FLAME Hub umbrella chart serves authup alongside
client-ui,server-core,storageandtelemetryon one shared hostname, with authup at PathPrefix/auth. It renders this itself (charts/flame-hub/templates/authup/httproute.yaml):paired with (
charts/flame-hub/templates/authup/snippetsfilter-timeouts.yaml):Three things are required and none is expressible: (a)
matches[].pathPathPrefix/auth, (b) aURLRewritefilter withReplacePrefixMatch: /, (c) anExtensionReffilter carrying the proxy buffers.To be explicit about scope: this does not block flame-hub's migration to the upstream chart. flame-hub keeps its own HTTPRoute and leaves
server.route.enabled=false. But it does mean an umbrella consumer of this chart can never use the chart's own routing feature — and that is the deployment shape the chart otherwise targets end to end.Proposed minimal values API
Raw Gateway API passthrough, in exactly the style
route.parentRefsalready uses — no new abstraction, no re-modelling of the Gateway API:Template change in
templates/_ingress.tpl, replacing lines 112-116:plus the matching
values.schema.jsonentries (the objects areadditionalProperties: falsetoday, so the schema must be updated or the new keys are rejected). Applies identically toadminConsole.route.Optionally, and separately: when
matchesis empty but the derived/derivable public URL carries a pathname, either default a PathPrefix match from it orfail— rather than silently widening it to/. At minimum thehostnamesvalue comment ("[] = derived from server.publicUrl / ingress hostname",values.yaml:747) should say that the derivation drops the path.Why the workaround is not acceptable as the answer
The workaround is
server.route.enabled=falseplus a hand-written HTTPRoute in rootextraDeploy(values.yaml:32, rendered throughtplbytemplates/extra-list.yaml:1-4). It does work — helpers like{{ include "authup.server.fullname" . }}and{{ .Values.server.service.ports.http }}are in scope, so names and ports do not drift. But:routedead weight for its most likely consumer. Anyone deploying this chart as a subchart behind a shared gateway must not useserver.route, which is exactly who a Gateway API feature is for. As shipped, the value is nearly ornamental.extraDeployis only a workaround for the user who already knows the feature is broken.authup.labels),commonAnnotations,namespaceOverridehandling, hostname derivation, service name and port — into user-maintained YAML that silently rots across chart upgrades. That is precisely the drift this chart'sauthup.tplvalues.renderdesign exists to eliminate.ingress.extraRulesexists so Ingress users do not have to escape toextraDeployfor a custom rule (values.yaml:742-743). The same rationale applies verbatim to HTTPRoute; the route side just never got it.