Lesson 11 Gateway API
Theme:

Gateway API

The successor to Ingress — a role-oriented, expressive, and portable API for managing traffic into your Kubernetes cluster.

Introduction

For years, the Ingress resource was the standard way to expose HTTP services in Kubernetes. It worked, but its limitations became painfully clear as clusters grew in complexity: no standard support for TCP or gRPC traffic, header manipulation locked behind controller-specific annotations, no way to split traffic by weight, and a flat permission model where anyone who could create an Ingress could route traffic anywhere.

The Kubernetes Gateway API was designed from the ground up to solve these problems. Originally incubated in the SIG-Network community as the "Service APIs" project, it graduated to GA (v1.0) in October 2023 and continues to evolve with new route types and policy attachments. Unlike Ingress, Gateway API is not a single resource — it is a family of resources that model real organizational roles and enable fine-grained control over how traffic enters and traverses a cluster.

This lesson covers every core Gateway API resource, explains the role separation model, demonstrates how to template these resources in Helm charts, and surveys the major implementations available today.

Why Gateway API?

The Ingress specification was deliberately minimal. Its designers intended controller vendors to extend it via annotations. The result was a fragmented ecosystem: an Ingress manifest that worked perfectly with nginx-ingress-controller would fail silently or behave differently on Traefik, HAProxy, or AWS ALB. Teams moving between cloud providers or upgrading their ingress controller often had to rewrite manifests.

Gateway API takes a different approach. Core functionality — header-based routing, traffic splitting, redirects, URL rewrites — is part of the specification itself, not left to annotations. This means a valid HTTPRoute will work consistently across any conformant implementation.

FeatureIngressGateway API
API statusv1, frozenv1, actively evolving
Protocol supportHTTP/HTTPSHTTP, HTTPS, TLS passthrough, TCP, UDP, gRPC
Role separationSingle resource, single authorThree-tier: GatewayClass / Gateway / Route
Header manipulationAnnotation-dependentNative RequestHeaderModifier filter
Traffic splittingNot in specWeighted backendRefs
Cross-namespace routingNot supportedReferenceGrant
PortabilityLow (annotation lock-in)High (conformance test suite)

The Role Separation Model

Gateway API introduces a three-tier responsibility model that maps naturally to how most organizations operate:

Infrastructure Provider — GatewayClass

The infrastructure provider (a cloud vendor, a platform team, or a service mesh project) installs a controller and registers it via a GatewayClass. This resource is cluster-scoped and references the controller that will reconcile Gateways of this class. Think of it as the "driver" that backs a "car" (the Gateway).

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  parametersRef:
    group: gateway.envoyproxy.io
    kind: EnvoyProxy
    name: custom-proxy-config
    namespace: envoy-gateway-system

The controllerName field is a domain-prefixed string that uniquely identifies the controller implementation. The optional parametersRef points to an implementation-specific configuration resource (for example, proxy resource limits or access logging settings).

Cluster Operator — Gateway

The cluster operator creates Gateway resources that bind to a GatewayClass and configure the actual network endpoints: ports, protocols, TLS certificates, and which namespaces are allowed to attach routes.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main-gateway
  namespace: gateway-infra
spec:
  gatewayClassName: envoy
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      hostname: "*.example.com"
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: "true"
    - name: https
      port: 443
      protocol: HTTPS
      hostname: "*.example.com"
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-cert
      allowedRoutes:
        namespaces:
          from: All

Each listener declares a port, protocol, optional hostname, and an allowedRoutes policy. The namespaces.from field accepts three values: All (any namespace), Same (only the Gateway's namespace), or Selector (namespaces matching a label selector). The TLS section supports Terminate (decrypt at the gateway) and Passthrough (forward encrypted traffic to the backend).

Application Developer — Routes

Application developers create route resources that attach to a Gateway listener via parentRefs. The most common is HTTPRoute, but the specification also defines GRPCRoute, TLSRoute, and TCPRoute (the latter two are in the experimental channel).

HTTPRoute in Detail

The HTTPRoute is the workhorse of the Gateway API. It supports matching requests by path, headers, query parameters, and HTTP method, then applying filters and forwarding to one or more backends.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: store-route
  namespace: web
spec:
  parentRefs:
    - name: main-gateway
      namespace: gateway-infra
      sectionName: https
  hostnames:
    - store.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/v2
          headers:
            - name: x-canary
              value: "true"
      filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            set:
              - name: x-backend-version
                value: v2
      backendRefs:
        - name: store-api-v2
          port: 8080
          weight: 100
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: store-api-v1
          port: 8080
          weight: 90
        - name: store-api-v2
          port: 8080
          weight: 10

Key points about the structure:

Filters

Filters are what make the Gateway API dramatically more powerful than Ingress without resorting to annotations. The core specification defines these filter types:

Tip: You can chain multiple filters in a single rule. They execute in the order listed. A common pattern is to add a tracing header via RequestHeaderModifier, then rewrite the path via URLRewrite.

ReferenceGrant — Cross-Namespace Security

In multi-tenant clusters, an HTTPRoute in namespace web might need to forward traffic to a Service in namespace backend. By default, the Gateway API blocks this to prevent unauthorized cross-namespace routing. The ReferenceGrant resource (namespace-scoped, placed in the target namespace) explicitly permits the reference:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-web-to-backend
  namespace: backend
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: web
  to:
    - group: ""
      kind: Service

This grant says: "HTTPRoutes in the web namespace are allowed to reference Services in the backend namespace." Without it, the controller will reject the route attachment and set a ResolvedRefs condition to False.

Warning: ReferenceGrant is currently in v1beta1. It is expected to graduate to v1 soon, but the API version may change. Pin the version in your Helm templates and monitor upstream releases.

Templating Gateway API in Helm

Gateway API resources follow the same Kubernetes API conventions as any other resource, so your existing Helm templating patterns — include, toYaml, nindent, conditionals — all apply directly. A typical chart might optionally create a Gateway and one or more HTTPRoutes:

{{- if .Values.gatewayAPI.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: {{ include "mychart.fullname" . }}
  labels:
    {{- include "mychart.labels" . | nindent 4 }}
spec:
  parentRefs:
    - name: {{ .Values.gatewayAPI.gatewayName }}
      namespace: {{ .Values.gatewayAPI.gatewayNamespace }}
  hostnames:
    {{- range .Values.gatewayAPI.hostnames }}
    - {{ . | quote }}
    {{- end }}
  rules:
    {{- toYaml .Values.gatewayAPI.rules | nindent 4 }}
{{- end }}

For charts that need to support both Ingress and Gateway API, a common pattern is to provide both templates gated by separate boolean values: ingress.enabled and gatewayAPI.enabled. This gives consumers a smooth migration path.

Installing Gateway API CRDs

The Gateway API CRDs are not bundled with Kubernetes itself. You must install them separately before any Gateway, GatewayClass, or Route resource can be created:

# Standard channel (HTTPRoute, Gateway, GatewayClass, ReferenceGrant)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

# Experimental channel (adds TLSRoute, TCPRoute, UDPRoute, GRPCRoute)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml

The standard channel contains resources that have reached GA stability. The experimental channel includes additional route types that are still evolving. For production clusters, start with the standard channel and add experimental CRDs only when you need TCP, TLS passthrough, or gRPC routing.

Implementations

Unlike Ingress, where controller choice was a one-time decision that heavily influenced your manifest syntax, Gateway API implementations are interchangeable at the GatewayClass level. Here are the most widely used:

ImplementationController NameKey Characteristics
Envoy Gatewaygateway.envoyproxy.io/gatewayclass-controllerOfficial Envoy project; reference implementation for Gateway API. Dynamic xDS configuration.
Istioistio.io/gateway-controllerFull service mesh with mTLS, observability, and traffic management. Gateway API is its recommended ingress mode since Istio 1.18.
Ciliumio.cilium/gateway-controllereBPF-based data plane with extremely low latency. No sidecar proxies needed.
NGINX Gateway Fabricgateway.nginx.org/nginx-gateway-controllerNGINX-backed, maintained by F5. Familiar operational model for teams already using NGINX.

You can run multiple GatewayClasses in the same cluster — for example, Cilium for east-west traffic and Envoy Gateway for north-south. Each Gateway resource declares which class it uses, and controllers only reconcile Gateways that match their class.

Route Types Beyond HTTP

While HTTPRoute handles the vast majority of use cases, the Gateway API defines additional route types for other protocols:

Note: TLSRoute, TCPRoute, and UDPRoute require the experimental CRD channel. GRPCRoute graduated to the standard channel in Gateway API v1.2.0.

Summary

The Gateway API represents a fundamental shift in how Kubernetes handles ingress traffic. By separating concerns into GatewayClass, Gateway, and Route resources, it maps cleanly to real organizational roles. By moving features like header modification, traffic splitting, and URL rewriting into the core specification, it eliminates the annotation fragmentation that plagued Ingress. And by enforcing cross-namespace security through ReferenceGrant, it provides a safe multi-tenant model out of the box.

For Helm chart authors, the Gateway API is just another set of Kubernetes resources to template. The same patterns you use for Deployments and Services — conditionals, value-driven configuration, helper templates — apply directly. The key decision for chart consumers is whether to support only Gateway API, only Ingress, or both behind feature flags. As the ecosystem converges on Gateway API, building your charts with support for it today will pay dividends in portability and expressiveness.