Gateway api support (#890)

* Gateway api support

Signed-off-by: Kevin Fox <[email protected]>

* Update readme

Signed-off-by: Kevin Fox <[email protected]>

* Fix gateway name. a gateway doesnt need to be named gateway

Signed-off-by: Kevin Fox <[email protected]>

* Fix naming issue

Signed-off-by: Kevin Fox <[email protected]>

* Incorperate feedback

Signed-off-by: Kevin Fox <[email protected]>

* Incorperate feedback

Signed-off-by: Kevin Fox <[email protected]>

---------

Signed-off-by: Kevin Fox <[email protected]>
This commit is contained in:
kfox1111
2026-07-30 19:38:43 +00:00
committed by GitHub
parent 2d92b81ba4
commit 3cfefb72ba
39 changed files with 1015 additions and 5 deletions
+239
View File
@@ -366,3 +366,242 @@ Anything lower has an incompatible API.
{{- print "crt" }}
{{- end }}
{{- end }}
{{/* ---------------------------------------------------------------------------
* Gateway API helpers
*
* Gateway API support is entirely independent of Ingress. It is driven by a
* per-service `gatewayAPI:` values block (sibling of `ingress:`) with its own
* `enabled` flag, so a service can expose both an Ingress and Gateway API
* resources at the same time. The existing ingress helpers above are untouched.
*
* Only Standard-channel, v1 Gateway API resources are used
* (gateway.networking.k8s.io/v1): Gateway, HTTPRoute, TLSRoute, ListenerSet,
* BackendTLSPolicy. Requires Gateway API v1.5+ CRDs pre-installed.
* --------------------------------------------------------------------------- */}}
{{/* Shared Gateway object name (global reference). Input: dict {global} */}}
{{- define "spire-lib.gateway-name" -}}
{{- dig "spire" "gatewayAPI" "gateway" "name" "spire" .global -}}
{{- end }}
{{/* Shared Gateway namespace. Input: dict {global, root}. Defaults to the release namespace. */}}
{{- define "spire-lib.gateway-namespace" -}}
{{- $ns := dig "spire" "gatewayAPI" "gateway" "namespace" "" .global -}}
{{- if $ns -}}{{ $ns }}{{- else -}}{{ .root.Release.Namespace }}{{- end -}}
{{- end }}
{{/* Shared Gateway listener port (global reference, ListenerSets must match). Input: dict {global} */}}
{{- define "spire-lib.gateway-port" -}}
{{- dig "spire" "gatewayAPI" "gateway" "port" 443 .global -}}
{{- end }}
{{/* Resolve whether ListenerSet management is on for a service.
* Input: dict {gatewayAPI, global}. Per-service listenerSet.enabled (null=inherit)
* falls back to global.spire.gatewayAPI.manageListenerSets (default true).
* Returns the string "true" or "false".
*/}}
{{- define "spire-lib.gateway-manage-listenersets" -}}
{{- $ls := dig "listenerSet" "enabled" nil .gatewayAPI -}}
{{- if ne $ls nil -}}
{{- $ls -}}
{{- else -}}
{{- dig "spire" "gatewayAPI" "manageListenerSets" true .global -}}
{{- end -}}
{{- end }}
{{/* Default route kind from tlsSecret. Input: dict {gatewayAPI}. Empty tlsSecret => TLSRoute (passthrough). */}}
{{- define "spire-lib.gateway-route-kind" -}}
{{- if .gatewayAPI.tlsSecret -}}HTTPRoute{{- else -}}TLSRoute{{- end -}}
{{- end }}
{{/* parentRefs list items for a route.
* Input: dict {manageLS(bool), name, gatewayAPI, gwName, gwNS}
* - manageLS on: attach to the service's ListenerSet (kind ListenerSet, sectionName=name)
* - off + gatewayAPI.parentRefs set: use those verbatim
* - off + no override: attach directly to the shared Gateway
*/}}
{{- define "spire-lib.gateway-parentref" -}}
{{- if .manageLS }}
- group: gateway.networking.k8s.io
kind: ListenerSet
name: {{ .name | quote }}
sectionName: {{ .name | quote }}
{{- else if .gatewayAPI.parentRefs }}
{{ toYaml .gatewayAPI.parentRefs }}
{{- else }}
- group: gateway.networking.k8s.io
kind: Gateway
name: {{ .gwName | quote }}
namespace: {{ .gwNS | quote }}
{{- with .gatewayAPI.sectionName }}
sectionName: {{ . | quote }}
{{- end }}
{{- end }}
{{- end }}
{{/* Emit Gateway API resources for one service: a Route, plus (optionally) a
* ListenerSet and a BackendTLSPolicy. Direct analogue of spire-lib.ingress-spec.
* Input dict:
* root - chart root context (.)
* gatewayAPI - the per-service gatewayAPI values block
* name - base name for the emitted resources
* namespace - namespace for the emitted resources
* svcName - backend Service name
* port - backend Service port (number)
* labels - pre-rendered labels YAML (string)
* routeKind - "TLSRoute" or "HTTPRoute"
* backendTLS - bool; when true and HTTPRoute, emit a BackendTLSPolicy (reencrypt)
* path - HTTPRoute path prefix (default "/")
*/}}
{{- define "spire-lib.gateway-routes" -}}
{{- $g := .gatewayAPI -}}
{{- $global := .root.Values.global -}}
{{- $host := include "spire-lib.ingress-calculated-name" (dict "ingress" (dict "host" $g.host) "Values" .root.Values) | trim -}}
{{- $gwName := include "spire-lib.gateway-name" (dict "global" $global) -}}
{{- $gwNS := include "spire-lib.gateway-namespace" (dict "global" $global "root" .root) -}}
{{- $port := include "spire-lib.gateway-port" (dict "global" $global) -}}
{{- $manageLS := eq (include "spire-lib.gateway-manage-listenersets" (dict "gatewayAPI" $g "global" $global)) "true" -}}
{{- $terminate := eq .routeKind "HTTPRoute" -}}
{{- $path := default "/" .path -}}
{{- $parentRefs := include "spire-lib.gateway-parentref" (dict "manageLS" $manageLS "name" .name "gatewayAPI" $g "gwName" $gwName "gwNS" $gwNS) -}}
apiVersion: gateway.networking.k8s.io/v1
kind: {{ .routeKind }}
metadata:
name: {{ .name }}
namespace: {{ .namespace }}
labels:
{{- .labels | nindent 4 }}
{{- with $g.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- $parentRefs | trim | nindent 4 }}
hostnames:
- {{ $host | quote }}
rules:
{{- if $terminate }}
- matches:
- path:
type: PathPrefix
value: {{ $path | quote }}
backendRefs:
- name: {{ .svcName | quote }}
port: {{ .port }}
{{- else }}
- backendRefs:
- name: {{ .svcName | quote }}
port: {{ .port }}
{{- end }}
{{- if $manageLS }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: {{ .name }}
namespace: {{ .namespace }}
labels:
{{- .labels | nindent 4 }}
spec:
parentRef:
group: gateway.networking.k8s.io
kind: Gateway
name: {{ $gwName | quote }}
namespace: {{ $gwNS | quote }}
listeners:
- name: {{ .name }}
hostname: {{ $host | quote }}
port: {{ $port }}
{{- if $terminate }}
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- kind: Secret
group: ""
name: {{ $g.tlsSecret | quote }}
allowedRoutes:
namespaces:
from: Same
kinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
{{- else }}
protocol: TLS
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: Same
kinds:
- group: gateway.networking.k8s.io
kind: TLSRoute
{{- end }}
{{- end }}
{{- if and $terminate .backendTLS }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
name: {{ .name }}
namespace: {{ .namespace }}
labels:
{{- .labels | nindent 4 }}
spec:
targetRefs:
- group: ""
kind: Service
name: {{ .svcName | quote }}
validation:
hostname: {{ $host | quote }}
caCertificateRefs:
{{- if dig "backendTLS" "caCertificateRefs" (list) $g }}
{{- toYaml $g.backendTLS.caCertificateRefs | nindent 6 }}
{{- else }}
- group: ""
kind: ConfigMap
name: {{ include "spire-lib.bundle-configmap" .root | trim | quote }}
{{- end }}
{{- end }}
{{- end }}
{{/* The shared Gateway object. Rendered only by the umbrella chart.
* Input: dict {root, gatewayObject} where gatewayObject is the umbrella-local
* `gatewayAPI.gateway` values block. name/namespace/port come from the global
* reference; className and listener policy are local.
*/}}
{{- define "spire-lib.gateway-resource" -}}
{{- $global := .root.Values.global -}}
{{- $obj := .gatewayObject -}}
{{- $gwName := include "spire-lib.gateway-name" (dict "global" $global) -}}
{{- $gwNS := include "spire-lib.gateway-namespace" (dict "global" $global "root" .root) -}}
{{- $port := include "spire-lib.gateway-port" (dict "global" $global) -}}
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: {{ $gwName }}
namespace: {{ $gwNS }}
{{- with $obj.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
gatewayClassName: {{ required "gatewayAPI.gateway.className is required to render the shared Gateway" $obj.className | quote }}
allowedListeners:
namespaces:
from: {{ default "All" $obj.allowedListenersNamespaces }}
listeners:
- name: base
protocol: TLS
port: {{ $port }}
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: {{ default "All" $obj.allowedRoutesNamespaces }}
{{- with $obj.extraListeners }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}