DoiT Cloud Intelligence™

GKE Gateway API and Service Extensions: Your New Toolkit for Tackling Complex Traffic Challenges in…

By Chimbu ChinnaduraiAug 12, 20258 min read
GKE Gateway API and Service Extensions: Your New Toolkit for Tackling Complex Traffic Challenges in…

Kubernetes has transformed container orchestration, and Google Kubernetes Engine (GKE) provides a powerful, managed platform for deploying and scaling containerised applications. While GKE offers strong capabilities for service discovery and load balancing, there are still limitations on applying custom processing logic to traffic before it reaches the workloads.

This is where Service Extensions come into play, providing a compelling solution to customise and enhance the Cloud Load Balancing with the GKE Gateway API (Note: This is a kubernetes feature and unrelated to Google Cloud API Gateway Service).

What are Service Extensions in GCP?

Service Extensions enables users to inject custom logic directly into the data path, enabling advanced modifications to traffic that flows through the load balancer. It's like a pipeline where you can insert your own code at various stages to manipulate the requests and responses without impacting the backends.

There are two primary types of Service Extensions:

  • Plugins: These allow for inline custom code insertion directly within the networking data path. Built using WebAssembly (Wasm) and the Proxy-Wasm ABI, plugins run as Wasm modules on a Google-managed sandbox infrastructure. They are designed for low-latency operations and are ideal for light-weight logic that needs to execute very close to the data plane.

  • Callouts: These enable Cloud Load Balancing to make gRPC calls to external services — either Google-managed services or user-managed services (including those running on GKE Pods). Callouts offer greater flexibility as they can reuse existing software and have fewer runtime restrictions, making them suitable for more complex logic that might require external data or state.

The GKE team recently announced preview support for Service Extensions in the Gateway API. This allows users to manipulate HTTP headers and payloads for requests and responses and even control traffic routing, all without impacting the existing backend service selections or security policies.

Types of GKE Gateway API Service Extensions

GKE Gateway controller currently supports two types of Callouts Service Extensions, each designed for specific functionalities:

  • GCPRoutingExtension: This extension type is focused on controlling traffic routing. It's ideal for scenarios where you need to direct traffic to different backend services or apply custom routing logic.

How GCPRoutingExtension works with Gateways

  • GCPTrafficExtension: This extension type allows you to change the headers and payloads of requests and responses. It operates without affecting backend service selection or security policies, making it perfect for data transformation and enrichment.

How GCPTrafficExtension works with Gateways

Configure Service Extensions in GKE Gateway API

To explore the service extension feature in GKE, you need a GKE cluster with version 1.33 or later and Gateway API enabled. Also, review the current Restrictions and limitations of Gateway Service Extensions in GKE before testing this feature.

Deploy a Gateway

To configure a Service extension, you must first deploy a Gateway resource or verify that the existing Gateway resource uses a supported GatewayClass. For details on supported load balancers, refer to Google Cloud Service Extension compatibility with GatewayClasses.

  • Apply the below manifest to deploy a simple regional application load balancer gateway.
---
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: gke-l7-regional-external-managed
spec:
  gatewayClassName: gke-l7-regional-external-managed
  listeners:
  - name: http
    protocol: HTTP
    port: 80

Deploy a sample store backend application

  • Apply the below manifest to deploy the sample backend application and HTTPRoute resources. The HTTPRoute specifies the routing behaviour of HTTP requests from a Gateway listener to the backend application.
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: store-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: store
      version: v1
  template:
    metadata:
      labels:
        app: store
        version: v1
    spec:
      containers:
      - name: whereami
        image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1.2.20
        ports:
          - containerPort: 8080
        env:
        - name: METADATA
          value: "store-v1"
---
apiVersion: v1
kind: Service
metadata:
  name: store-v1
spec:
  selector:
    app: store
    version: v1
  ports:
  - port: 8080
    targetPort: 8080
------
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: store
spec:
  parentRefs:
  - kind: Gateway
    name: gke-l7-regional-external-managed
  hostnames:
  - "store.example.com"
  rules:
  - backendRefs:
    - name: store-v1
      port: 8080
  • Send a sample request to the gateway API IP address to test the backend response.
curl http://store.example.com --resolve store.example.com:80:GATEWAY_IP_ADDRESS -v

The output is similar to the following:

{
  "cluster_name": "gateway-api-service-extensio-demo",
  "gce_instance_id": "2936941014208025864",
  "gce_service_account": "chimbuc-playground.svc.id.goog",
  "host_header": "store.example.com",
  "metadata": "store-v1",
  "pod_name": "store-v1-796c8ff75-mnssb",
  "pod_name_emoji": "🧑🏿‍⚖",
  "project_id": "chimbuc-playground",
  "timestamp": "2025-07-30T12:21:44",
  "zone": "us-central1-a"
}

Deploy a backend callout service

A callout service implements the custom logic for Gateway Service Extensions in GKE. The Load Balancer invokes the backend applications based on GCPTrafficExtension or GCPRoutingExtension configurations, to modify or route traffic.

If you are deploying a callout service in the GKE cluster, you must meet all the requirements mentioned in the limitations.

  • Generate a self-signed certificate for the callout service backend using mkcert or any other method. This is necessary because you must use HTTP2 as it'sappProtocol which requires end-to-end TLS.
mkcert internal
  • Create a K8S Secret with the self-signed cert.
kubectl create secret tls extension-service-app-secret \
  --cert=internal.pem \
  --key=internal-key.pem
  • Apply the manifest below to deploy the sample callout application. For more code samples, refer to the service-extensions GitHub repository.
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: extension-service-app
spec:
  selector:
    matchLabels:
      app: store
  replicas: 1
  template:
    metadata:
      labels:
        app: store
    spec:
      containers:
      - name: serviceextensions
        image: us-docker.pkg.dev/service-extensions-samples/callouts/python-example-basic:main
        ports:
        - containerPort: 8080
        - containerPort: 443
        volumeMounts:
        - name: certs
          mountPath: "/etc/certs/"
          readOnly: true
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: TLS_SERVER_CERT
          value: "/etc/certs/tls.crt"
        - name: TLS_SERVER_PRIVKEY
          value: "/etc/certs/tls.key"
        resources:
          requests:
            cpu: 10m
      volumes:
      - name: certs
        secret:
          secretName: "extension-service-app-secret"
          optional: false
---
apiVersion: v1
kind: Service
metadata:
  name: extension-service
spec:
  ports:
  - port: 443
    targetPort: 443
    appProtocol: HTTP2
  selector:
    app: store
  • The sample application performs a basic header modification for both the request and response. Refer to service_callout_example.py for further details, and you can develop your own application based on the business requirements.

Configure the Service Extensions

You can configure either a GCPRoutingExtension or a GCPTrafficExtension to customize your traffic flow.

  • Apply the manifest below to create a GCPRoutingExtension resource, and the load balancer will call the extension service app for the requests sent to the path routeextension and then forward it to the backend store application.
---
kind: GCPRoutingExtension
apiVersion: networking.gke.io/v1
metadata:
  name: my-gateway-extension
  namespace: default
spec:
  targetRefs:
  - group: "gateway.networking.k8s.io"
    kind: Gateway
    name: gke-l7-regional-external-managed
  extensionChains:
  - name: chain1
    matchCondition:
      celExpressions:
      - celMatcher: request.path.contains("routeextension")
    extensions:
    - name: routeextension
      authority: "store.example.com"
      timeout: 1s
      backendRef:
        group: ""
        kind: Service
        name: extension-service
        port: 443
  • Update the HTTPRoute resource with service-extensions.com host since the callout service performs a host header modification before forwarding the requests to the store app.
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: store
spec:
  parentRefs:
  - kind: Gateway
    name: gke-l7-regional-external-managed
  hostnames:
  - "store.example.com"
  - "service-extensions.com"
  rules:
  - backendRefs:
    - name: store-v1
      port: 8080
  • The Gateway API controller may take a few minutes to sync the changes. Use the command kubectl describe gateway GATEWAY_NAME to confirm that the GCPRoutingExtension is bound to the Gateway.
Name:         gke-l7-regional-external-managed
Namespace:    default
Labels:       <none>
Annotations:  networking.gke.io/addresses:
                /projects/269684357132/regions/us-central1/addresses/gkegw1-jorz-default-gke-l7-regional-external-manag-8wyhl317c00c
              networking.gke.io/backend-services:
                /projects/269684357132/regions/us-central1/backendServices/gkegw1-jorz-default-extension-service-443-e1aovl10z449, /projects/269684357132/...
              networking.gke.io/firewalls: /projects/269684357132/global/firewalls/gkegw1-jorz-l7-default-us-central1
              networking.gke.io/forwarding-rules:
                /projects/269684357132/regions/us-central1/forwardingRules/gkegw1-jorz-default-gke-l7-regional-external-manag-5s86aj5tzcoj
              networking.gke.io/health-checks:
                /projects/269684357132/regions/us-central1/healthChecks/gkegw1-jorz-default-extension-service-443-e1aovl10z449, /projects/269684357132/reg...
              networking.gke.io/last-reconcile-time: 2025-07-30T12:46:15Z
              networking.gke.io/lb-route-extensions:
                projects/269684357132/locations/us-central1/lbRouteExtensions/gkegw1-jorz-default-gke-l7-regional-external-manag-xivagz6clt0t
              networking.gke.io/lb-traffic-extensions:
                projects/269684357132/locations/us-central1/lbTrafficExtensions/gkegw1-jorz-default-gke-l7-regional-external-manag-lu8d7n5p4kbs
              networking.gke.io/ssl-certificates:
              networking.gke.io/target-http-proxies:
                /projects/269684357132/regions/us-central1/targetHttpProxies/gkegw1-jorz-default-gke-l7-regional-external-manag-kaecv0bs2nyx
              networking.gke.io/target-https-proxies:
              networking.gke.io/url-maps:
                /projects/269684357132/regions/us-central1/urlMaps/gkegw1-jorz-default-gke-l7-regional-external-manag-kaecv0bs2nyx
API Version:  gateway.networking.k8s.io/v1
Kind:         Gateway
Metadata:
  Creation Timestamp:  2025-07-30T07:45:42Z
  Finalizers:
    gateway.finalizer.networking.gke.io
  Generation:        1
  Resource Version:  1753879575407087021
...
  • The output shows the annotations, which GKE uses to store the links between the Gateway and the underlying Google Cloud resources. The networking.gke.io/lb-route-extensions annotation confirms the binding of the gateway to the GCPRoutingExtension.
  • Now test the traffic to the routeextension path by replacing GATEWAY_IP_ADDRESS.
curl -v http://store.example.com/routeextension --resolve store.example.com:GATEWAY_IP_ADDRESS
  • The output resembles the following, and you can notice the changes in the host_header within the response.
{
  "cluster_name": "gateway-api-service-extensio-demo",
  "gce_instance_id": "2936941014208025864",
  "gce_service_account": "chimbuc-playground.svc.id.goog",
  "host_header": "service-extensions.com",
  "metadata": "store-v1",
  "pod_name": "store-v1-796c8ff75-mnssb",
  "pod_name_emoji": "🧑🏿‍⚖",
  "project_id": "chimbuc-playground",
  "timestamp": "2025-07-30T12:51:06",
  "zone": "us-central1-a"
}

You can use GCPTrafficExtension to implement custom request and response logic, sophisticated routing, transformations, and security policies.

  • Apply the manifest below to create a GCPTrafficExtension resource, and the load balancer will call the extension service app for the requests sent to the path trafficetension. You can customize and control the load balancer invocation to the callout application by updating the supportedEvents .
---
kind: GCPTrafficExtension
apiVersion: networking.gke.io/v1
metadata:
  name: my-traffic-extension
  namespace: default
spec:
  targetRefs:
  - group: "gateway.networking.k8s.io"
    kind: Gateway
    name: gke-l7-regional-external-managed
  extensionChains:
  - name: chain1
    matchCondition:
      celExpressions:
      - celMatcher: request.path.contains("trafficeextension")
    extensions:
    - name: trafficeextension
      authority: "store.example.com"
      timeout: 1s
      supportedEvents: ["RequestHeaders", "RequestBody", "ResponseHeaders", "ResponseBody", "RequestTrailers", "ResponseTrailers"]
      backendRef:
        group: ""
        kind: Service
        name: extension-service
        port: 443
  • Now test the traffic to the trafficextension path by replacing GATEWAT_IP_ADDRESS.
curl -v http://store.example.com/trafficeextension --resolve store.example.com:GATEWAY_IP_ADDRESS
  • The output resembles the following, and you can notice the customer response header changes in hello and the response body is removed.
* Request completely sent off
< HTTP/1.1 200 OK
< server: Werkzeug/2.3.7 Python/3.11.3
< date: Wed, 30 Jul 2025 12:58:00 GMT
< content-type: application/json
< access-control-allow-origin: *
< hello: service-extensions
< via: 1.1 google
< transfer-encoding: chunked
<

Sample Pod logs:

GCP Service Extensions for GKE Gateway API represent a significant advance in how platform teams can manage, shape, and secure traffic at the ingress layer. Whether you need to enforce custom authentication, manipulate headers, perform traffic shaping, or integrate with external systems, Service Extensions enable you to do so declaratively and scalably.

Although it is still in preview, this presents an excellent opportunity to explore Service Extensions, test them in non-production environments, and develop reusable extension services tailored to your platform requirements.

If you are considering a PoC, you are not alone. DoiT is here to help you assess, plan and migrate with a strong focus on your business outcomes. With over 100 senior cloud experts specializing in crafting customized cloud solutions, our team is ready to help you navigate this process smoothly and optimize your infrastructure to ensure compliance and meet future demands efficiently.

Our experts are ready to provide you with strategic guidance and technical expertise every step of the way. Let’s discuss what makes the most sense for your company during this policy enforcement phase, ensuring your cloud infrastructure is robust, compliant, and optimized for success. Contact us today.