Skip to main content

Gateway API

info

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.

Controller requirement

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 Gateway managed 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 Ingress resource 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 RegularExpression path match support — see the warning above for validated controllers.
  • A GatewayClass that the controller reconciles, ready to be referenced by your Gateway

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) or gateway-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:

FieldPurpose
ingress.enabledMaster switch for external exposure.
ingress.controllerData plane name. Drives autoscaling metric selection (HPA / KEDA). In Gateway API mode it does not influence routing.
ingress.tls.enabledEnables TLS on the public listeners and the HTTP → HTTPS redirect.
ingress.tls.existingSecretName of the Secret containing the TLS certificate.
hostname / domainPublic hostnames used by the chart (app, API, receiver).

Gateway API specific fields

These fields are only consumed when routingApi: gateway-api:

FieldPurpose
ingress.routingApiSet to gateway-api to enable this mode. Default is ingress.
ingress.gatewayApi.gatewayClassNameName 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.createtrue 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.nameName of the Gateway. The Gateway the chart creates if create=true, or the existing Gateway to attach to if create=false.
ingress.gatewayApi.gateway.namespaceNamespace of the existing Gateway. Required only when create=false and the Gateway lives in a different namespace than GitGuardian.
ingress.gatewayApi.gateway.httpListenerPortPort for the HTTP listener on the chart-managed Gateway. Default 80. Ignored when create=false.
ingress.gatewayApi.gateway.httpsListenerPortPort 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:

  1. The target Gateway's spec.listeners[].allowedRoutes.namespaces must allow routes coming from the GitGuardian namespace. Set it to From: All, or use From: Selector with a label that matches the GitGuardian namespace.
  2. If TLS is enabled and you reference a Secret from the chart, that Secret must be reachable by the Gateway (typically in the Gateway's namespace). When the certificate is fully managed at the Gateway level, leave ingress.tls.existingSecret empty.
  3. The Gateway must expose listeners with the names the chart's routes target via sectionName:
    • A listener named http is always required (used by the HTTP → HTTPS redirect route when TLS is enabled, or by all routes when TLS is disabled).
    • A listener named https is required when ingress.tls.enabled=true.

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 show Accepted=True reason=UnsupportedField). To restore them, apply a ProxySettingsPolicy (NGF ≥ 2.6) to the affected HTTPRoute — for example to keep the 3600 s ceiling on the billing-metrics export, target gim-app with proxyReadTimeout: 3600s.
  • In-app-agent SSE. The chart automatically skips the X-Accel-Buffering: no header 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 Gateway managed by your platform team. The Gateway and its load balancer already exist; GitGuardian only adds HTTPRoute resources to it. See Example: attaching to an existing Gateway.
  • B. Create a new Gateway from the chart. The chart provisions a dedicated Gateway, 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 Service of type LoadBalancer per Gateway (Istio in Gateway API mode, Envoy Gateway, Kong, Contour Gateway Provisioner). With these, the new Gateway gets a new address — plan a DNS cutover and a maintenance window.
  • Some controllers can reuse a single shared load balancer across multiple Gateway resources, or even share it with the legacy Ingress data 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:

  1. 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.
  2. Lower the TTL on your DNS records ahead of the cutover so rollback is quick.
  3. Switch the GitGuardian release to routingApi: gateway-api. The chart removes the Ingress resources and creates the routes against the Gateway.
  4. Update DNS to the new Gateway address (kubectl get gateway <name> -o jsonpath='{.status.addresses}').
  5. 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:

  1. Switch the GitGuardian release to routingApi: gateway-api. The chart swaps the Ingress resources for Gateway/HTTPRoute resources; traffic continues to flow through the same load balancer.
  2. Confirm with kubectl get httproute -n <namespace> and kubectl describe gateway <name> that all routes are Accepted=True and the Gateway is Programmed=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=False on HTTPRoute with a NotAllowedByListeners reason — the shared Gateway does not allow routes from the GitGuardian namespace. Update the Gateway's spec.listeners[].allowedRoutes.namespaces.
  • Programmed=False on Gateway — 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 Secret referenced by ingress.tls.existingSecret exists in a namespace reachable by the Gateway (usually the Gateway's namespace).