Gateway API
This page only concerns Helm-based installations on an existing cluster. See Ingress for the default routing model.
GitGuardian's Helm chart can route external traffic through the Kubernetes Gateway API instead of the legacy Ingress resource. This is opt-in: existing installations keep using Ingress by default.
Gateway API is the modern, future-proof, and standardized successor to Ingress for Kubernetes traffic routing: instead of relying on controller-specific annotations as the NGINX Ingress does, it expresses routing through portable, role-oriented resources. Adopting it also paves the way for upcoming capabilities such as latency-based autoscaling of the web application.
Every HTTPRoute emitted by the chart uses the RegularExpression path match type. Your Gateway API controller MUST support RegularExpression matchers, otherwise the resources are rejected and traffic does not flow. Validated controllers: Istio (≥ 1.25), NGINX Gateway Fabric, Traefik (≥ v3). Verify your controller's support before enabling Gateway API mode.
When should you use Gateway API?
Gateway API is the right choice when:
- Your platform team has standardized on Gateway API and wants GitGuardian to follow the same model as the rest of the cluster.
- You operate a multi-tenant cluster with a shared
Gatewaymanaged by a different team, and you want GitGuardian's routes to attach to it rather than provisioning a dedicated entry point. - Your data plane (Istio, Envoy Gateway, Kong, NGINX Gateway Fabric, …) is moving away from the
Ingressresource and Gateway API gives you cleaner role separation between platform and application teams.
If none of the above applies, the default Ingress mode is the simpler choice.
Prerequisites
To use Gateway API mode you need:
- Kubernetes ≥ 1.25
- Gateway API CRDs ≥ v1.0 (channel: standard) installed cluster-wide
- A Gateway API conformant controller with
RegularExpressionpath match support — see the warning above for validated controllers. - A
GatewayClassthat the controller reconciles, ready to be referenced by yourGateway
Verifying cluster compatibility
Run the following checks before switching to Gateway API mode.
Confirm the CRDs are installed:
kubectl get crd gateways.gateway.networking.k8s.io \
httproutes.gateway.networking.k8s.io \
gatewayclasses.gateway.networking.k8s.io
All three CRDs must exist. If they do not, install them following your controller's documentation (most controllers ship them or document the exact kubectl apply URL).
Confirm a GatewayClass is available and accepted:
kubectl get gatewayclass
NAME CONTROLLER ACCEPTED AGE
istio istio.io/gateway-controller True 28d
You should see at least one entry with ACCEPTED=True. Note the NAME column — this is the value you will set in ingress.gatewayApi.gatewayClassName.
Confirm the controller is healthy:
kubectl get pods -A -l 'app.kubernetes.io/component in (controller, gateway-api)'
The exact label depends on your controller; if in doubt, check that the namespace it runs in (istio-system, envoy-gateway-system, kong, projectcontour, …) has all pods in Running state.
Configuration
Two values control routing in your values.yaml file, and they are intentionally orthogonal:
ingress.routingApi:ingress(default) orgateway-api. Selects the routing API used to expose GitGuardian.ingress.controller: the data plane that fulfills the routes. Used in both modes for autoscaling metrics; in Ingress mode it also picks the routing manifest format.
Common fields
The following fields keep the same meaning in both modes:
| Field | Purpose |
|---|---|
ingress.enabled | Master switch for external exposure. |
ingress.controller | Data plane name. Drives autoscaling metric selection (HPA / KEDA). In Gateway API mode it does not influence routing. |
ingress.tls.enabled | Enables TLS on the public listeners and the HTTP → HTTPS redirect. |
ingress.tls.existingSecret | Name of the Secret containing the TLS certificate. |
hostname / domain | Public hostnames used by the chart (app, API, receiver). |
Gateway API specific fields
These fields are only consumed when routingApi: gateway-api:
| Field | Purpose |
|---|---|
ingress.routingApi | Set to gateway-api to enable this mode. Default is ingress. |
ingress.gatewayApi.gatewayClassName | Name of the GatewayClass the chart references. Required only when gateway.create=true. Run kubectl get gatewayclass to find available classes in your cluster. |
ingress.gatewayApi.gateway.create | true lets the chart create and own the Gateway alongside the Helm release. false makes the chart attach its HTTPRoute resources to a Gateway managed elsewhere (multi-tenant model). |
ingress.gatewayApi.gateway.name | Name of the Gateway. The Gateway the chart creates if create=true, or the existing Gateway to attach to if create=false. |
ingress.gatewayApi.gateway.namespace | Namespace of the existing Gateway. Required only when create=false and the Gateway lives in a different namespace than GitGuardian. |
ingress.gatewayApi.gateway.httpListenerPort | Port for the HTTP listener on the chart-managed Gateway. Default 80. Ignored when create=false. |
ingress.gatewayApi.gateway.httpsListenerPort | Port for the HTTPS listener on the chart-managed Gateway. Default 443. Ignored when create=false. |
Example: chart-managed Gateway
The simplest setup. The chart creates the Gateway in the GitGuardian namespace; the controller provisions a load balancer for it.
ingress:
enabled: true
routingApi: gateway-api
controller: istio
tls:
enabled: true
existingSecret: gitguardian-tls
gatewayApi:
gatewayClassName: istio
gateway:
create: true
name: gitguardian
httpListenerPort: 80
httpsListenerPort: 443
Example: attaching to an existing Gateway (multi-tenant)
The chart only emits HTTPRoute resources pointing at a Gateway that already exists in the cluster. Typical when a platform team operates one shared Gateway for many applications.
ingress:
enabled: true
routingApi: gateway-api
controller: istio
tls:
enabled: true
# Leave empty if the certificate is managed at the Gateway level
# by your platform team.
existingSecret: ''
gatewayApi:
gatewayClassName: istio
gateway:
create: false
name: shared-gateway
namespace: gateway-system
Three things must hold on the platform team's side for the attachment to succeed:
- The target
Gateway'sspec.listeners[].allowedRoutes.namespacesmust allow routes coming from the GitGuardian namespace. Set it toFrom: All, or useFrom: Selectorwith a label that matches the GitGuardian namespace. - If TLS is enabled and you reference a
Secretfrom the chart, thatSecretmust be reachable by theGateway(typically in theGateway's namespace). When the certificate is fully managed at theGatewaylevel, leaveingress.tls.existingSecretempty. - The
Gatewaymust expose listeners with the names the chart's routes target viasectionName:- A listener named
httpis always required (used by the HTTP → HTTPS redirect route when TLS is enabled, or by all routes when TLS is disabled). - A listener named
httpsis required wheningress.tls.enabled=true.
- A listener named
Limitations
Body size limits are not part of the Gateway API standard. The chart does not set one in Gateway API mode, so the effective cap is your controller's default (≈1 MB on NGF). To match the legacy mode, attach a controller-specific policy to the gim-exposed HTTPRoute with a 25 MB limit. Example on NGINX Gateway Fabric:
apiVersion: gateway.nginx.org/v1alpha1
kind: ClientSettingsPolicy
metadata:
name: gim-exposed-body-limit
namespace: <gitguardian-namespace>
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: gim-exposed
body:
maxSize: 25m
For Istio, Contour, Envoy Gateway or Traefik, use the equivalent native mechanism (e.g. EnvoyFilter, route-level setting, middleware) on the same HTTPRoute.
NGINX Gateway Fabric specifics
- Per-route timeouts. NGF ignores
spec.rules[].timeouts(routes showAccepted=True reason=UnsupportedField). To restore them, apply aProxySettingsPolicy(NGF ≥ 2.6) to the affected HTTPRoute — for example to keep the 3600 s ceiling on the billing-metrics export, targetgim-appwithproxyReadTimeout: 3600s. - In-app-agent SSE. The chart automatically skips the
X-Accel-Buffering: noheader on NGF (NGF rejects it from its allowlist). NGINX does not buffer streaming responses by default, so SSE flows correctly.
AWS Load Balancer Controller is not supported
The AWS Load Balancer Controller Gateway API mode (gateway.k8s.aws/alb) is not supported: the chart's HTTPRoutes use a ResponseHeaderModifier filter for security headers, which it rejects (only RequestRedirect is supported), so the Gateway never becomes Programmed. On Amazon EKS, use a validated controller such as Istio instead.
Upgrading from Ingress to Gateway API
Switching routingApi from ingress to gateway-api is potentially traffic-impacting: the chart stops creating Ingress resources and creates Gateway/HTTPRoute resources instead. Whether it requires a maintenance window or a DNS cutover depends on your cluster's setup.
Step 1 — Identify your scenario
Two possible paths:
- A. Attach to an existing shared
Gatewaymanaged by your platform team. TheGatewayand its load balancer already exist; GitGuardian only addsHTTPRouteresources to it. See Example: attaching to an existing Gateway. - B. Create a new
Gatewayfrom the chart. The chart provisions a dedicatedGateway, and your Gateway API controller provisions the underlying load balancer for it. See Example: chart-managed Gateway.
Scenario A is the model the Gateway API was designed for: the cluster admin owns the Gateway (entry point, listeners, certificates, load balancer) and application teams own their HTTPRoute resources. This separation of concerns is a core best practice — the cluster admin keeps full control over how traffic enters the cluster, while application teams remain free to manage their own routing without touching infrastructure. If your organization can support it, prefer scenario A.
Scenario B remains a valid choice when GitGuardian is the only application using Gateway API in the cluster, when you do not (yet) have a shared Gateway, or when GitGuardian must own its public entry point for organizational reasons. It is also a convenient stepping stone when migrating from Ingress before extracting the Gateway to the platform team's ownership later.
Step 2 — Determine the public-address impact
Whether the public IP / hostname of GitGuardian will change depends on your scenario.
Scenario A — Attach to an existing Gateway. The address is the one of the shared Gateway. Switching from your current Ingress to that Gateway will change the public address that GitGuardian is reachable at — unless the existing Ingress controller and the shared Gateway happen to be backed by the same load balancer, which is uncommon. Plan a DNS cutover and a maintenance window.
Scenario B — Chart-managed Gateway. Whether a new load balancer is provisioned depends on your Gateway API controller:
- Some controllers provision one
Serviceof typeLoadBalancerperGateway(Istio in Gateway API mode, Envoy Gateway, Kong, Contour Gateway Provisioner). With these, the newGatewaygets a new address — plan a DNS cutover and a maintenance window. - Some controllers can reuse a single shared load balancer across multiple
Gatewayresources, or even share it with the legacyIngressdata path (Traefik in Gateway API mode is a frequent example, depending on configuration). With these, the public address may be preserved and the cutover is closer to a regular Helm upgrade.
Check your controller's documentation before assuming the behavior — this is the single most important question to answer before scheduling the migration. Useful command once a Gateway is deployed:
kubectl get gateway <name> -n <namespace> -o jsonpath='{.status.addresses}'
If the address differs from the one your DNS currently points at, you are in the "new load balancer" situation.
Step 3 — Plan the cutover
If the address changes (most cases):
The goal is to rehearse the switch end-to-end in a non-production environment first — apply the same values.yaml change and confirm the routes work — so that production cutover is a known quantity rather than a discovery. Once that is done:
- Deploy the new Gateway API controller alongside the existing Ingress controller if possible (in staging, or as a parallel release in a separate namespace), so DNS records and certificates can be prepared against the future address.
- Lower the TTL on your DNS records ahead of the cutover so rollback is quick.
- Switch the GitGuardian release to
routingApi: gateway-api. The chart removes theIngressresources and creates the routes against theGateway. - Update DNS to the new
Gatewayaddress (kubectl get gateway <name> -o jsonpath='{.status.addresses}'). - If a corporate reverse proxy or CDN sits in front of GitGuardian, update its origin to the new address.
If the address is preserved (controller reuses the same load balancer):
The cutover is closer to a regular Helm upgrade, but the goal is still to rehearse it in a non-production environment first so the switch is a known quantity. Once that is done:
- Switch the GitGuardian release to
routingApi: gateway-api. The chart swaps theIngressresources forGateway/HTTPRouteresources; traffic continues to flow through the same load balancer. - Confirm with
kubectl get httproute -n <namespace>andkubectl describe gateway <name>that all routes areAccepted=Trueand theGatewayisProgrammed=True.
TLS certificate
The TLS Secret referenced by ingress.tls.existingSecret must live in a namespace reachable by the Gateway — usually the Gateway's own namespace. If you currently keep the certificate in the GitGuardian namespace and you switch to a Gateway in another namespace, replicate the Secret (or rely on a tool like cert-manager or reflector to copy it).
Autoscaling
Only controller: istio is currently supported for latency-based webapp autoscaling in Gateway API mode — the chart reuses the same istio_request_duration_milliseconds_bucket metrics as in Ingress mode, so no HPA/KEDA reconfiguration is needed when migrating. Other controllers (NGINX Gateway Fabric, Traefik, …) are not compatible: either disable webapp autoscaling or switch the trigger to a CPU / request-rate based one.
Rollback
To roll back, set routingApi back to ingress and re-apply. The chart will recreate the Ingress resources. The Gateway/HTTPRoute resources are removed by Helm; in scenario B the underlying cloud load balancer is released by the controller. DNS records have to be reverted manually if they were changed.
Troubleshooting
The Gateway API exposes status conditions on every resource. Most issues surface there.
# Gateway listeners and assigned address
kubectl get gateway -n <namespace>
kubectl describe gateway <name> -n <namespace>
# Routes and their attachment status
kubectl get httproute -n <gitguardian-namespace>
kubectl describe httproute -n <gitguardian-namespace>
Common cases:
Accepted=FalseonHTTPRoutewith aNotAllowedByListenersreason — the sharedGatewaydoes not allow routes from the GitGuardian namespace. Update theGateway'sspec.listeners[].allowedRoutes.namespaces.Programmed=FalseonGateway— the controller has not finished provisioning the underlying load balancer. Check the controller's logs.- No traffic reaches GitGuardian but routes are accepted — confirm DNS points at the new
Gateway's address, and that the cloud load balancer's security groups allow inbound traffic on the listener ports. - TLS handshake failures — confirm the
Secretreferenced byingress.tls.existingSecretexists in a namespace reachable by theGateway(usually theGateway's namespace).