Extend Istio Ambient Mesh with Kgateway as Waypoints
Lin Sun
Apr 14, 2025
Ambient mesh is the new sidecarless data plane mode in the Istio service mesh. One of the key innovations of ambient mesh is that it splits Istio’s functionality into two distinct layers: a lightweight, secure overlay layer (implemented by a purpose-built node proxy called ztunnel) and a Layer 7 processing layer (implemented by L7 proxies called waypoints). As we designed ambient mesh with two distinct layers, we purposefully kept the secure overlay layer very lightweight with minimal function. The L7 layer was designed to be feature-rich and pluggable, enabling you to use your preferred L7 proxy as your waypoint.
But why choose kgateway as your waypoint? Kgateway is the first project that can be used as a pluggable waypoint for Istio. Built on the same Envoy engine that Istio’s waypoint implementation uses, there are nonetheless differentiators that make the use of kgateway as a waypoint a compelling alternative.
Why Choose Kgateway for Your Waypoint?
While Istio ambient provides a default waypoint proxy, there are several scenarios where kgateway can offer a more powerful alternative:
You are using or plan to use kgateway to control traffic in or out of your cluster
Most Istio users have two completely different gateway implementations: proxies for ingress (for “north-south” traffic) and proxies for internal service-to-service traffic (“east-west” traffic — in the traditional model, implemented by a mesh of sidecar proxies).
Kubernetes Gateway API is rapidly becoming the standard for networking in Kubernetes, with more than two dozen projects already supporting it. Kgateway is a feature-rich, fast and battle-tested gateway that integrates seamlessly with Kubernetes. It extends the Gateway API to provide advanced features like rate limiting, timeouts, header manipulation, and request transformations.
For applications that need to communicate with external services (like cloud APIs or LLM providers such as OpenAI), traffic control becomes even more critical. In such cases, using kgateway as an egress gateway can help manage costs, API key security, and caching, while ensuring sensitive data isn’t leaked.
Kgateway’s support for acting as a waypoint proxy offers users the chance to use a single system for both traffic directions. Even though the Gateway API lets you use the same terminology, there are differences in implementation, scalability, and performance even between projects using the same engine, like Kgateway and the default Istio waypoint. Many organizations already rely on kgateway to manage their north-south traffic, and it offers the same capabilities for east-west traffic in ambient mesh.
By using kgateway both for ingress/egress and internal service traffic, you create a unified architecture, making it easier to manage and troubleshoot your traffic. With consistent observability, debugging, and operational experiences, you’ll reduce the complexity of having multiple gateway solutions.
You need rich L7 features that Istio’s default waypoint doesn’t support
If you aren’t using kgateway for north-south traffic, you can still take advantage of its advanced Layer 7 capabilities for east-west traffic in Istio. Kgateway offers first-class APIs for rate limiting, header manipulation, request transformations, external auth and processing — without the headache of EnvoyFilters.
EnvoyFilters — snippets of raw Envoy configuration programmed into Istio — are a common workaround, but they are notoriously difficult to configure, and prone to breaking with new releases. Despite being around for five years, the EnvoyFilter API remains in Alpha status, largely due to their fragility, and are not supported in ambient mode at all. By using kgateway, you avoid this issue and gain access to powerful L7 functions via simple, Kubernetes-native APIs.
How Does it Work?
I previously wrote a blog about waypoint proxies, where I described how you can make sense of waypoints as gateways. Just as you can swap your gateway with other gateways that implement the same Kubernetes Gateway API, you can similarly bring in your preferred waypoint proxy.
A waypoint proxy is deployed using the Gateway resource, where you specify the gatewayClassName
to determine which proxy to use. The default class in an ambient mesh is istio-waypoint
. However, to use kgateway, you simply change the gatewayClassName
to kgateway-waypoint
, like so:

By default, Istio’s istio-waypoint listens on port 15008
, but kgateway-waypoint uses port 15088
and supports the PROXY protocol for passing connection information.
Once deployed, the kgateway-waypoint
controller automatically creates the necessary Kubernetes resources (Deployment and Service) for the waypoint. When Istio detects that this waypoint is being used as part of the data plane flow, it ensures that all client requests within the mesh pass through the waypoint before reaching their destination.

Seamlessly Integrating the Custom Waypoint into the Request Flow
Istio uses the status
field in the Gateway resource to manage the waypoint proxy’s integration into the request flow. Here’s an example of the status
section, which includes the waypoint’s service VIP (Virtual IP) address:
status:
addresses:
- type: IPAddress
value: 10.96.104.12
conditions:
- lastTransitionTime: "2025-04-09T20:51:02Z"
message: ""
observedGeneration: 1
reason: Accepted
status: "True"
type: Accepted
See It In Action
After you have Istio (v1.25 or newer) and kgateway (v2.0.0 or newer) installed in your Kubernetes cluster, you can deploy a kgateway-waypoint
in your namespace using a Kubernetes Gateway resource.
Let’s assume you already have a client app and an Ollama StatefulSet running in the same namespace. To integrate kgateway as the waypoint proxy, follow these steps:
First, create the Gateway resource to deploy kgateway-waypoint
within your namespace:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: kgateway-waypoint
spec:
gatewayClassName: kgateway-waypoint
listeners:
- name: proxy
port: 15088
protocol: istio.io/PROXY
Second, to ensure both the client app and ollama StatefulSet services are routed through the kgateway-waypoint
, label your namespace as follows, after making sure the namespace is enrolled in the ambient mesh:
$ kubectl label ns default istio.io/use-waypoint=kgateway-waypoint
This tells the ztunnel to route traffic through kgateway-waypoint
for all services in the namespace. You can verify this with the following command:
istioctl ztunnel-config service
NAMESPACE SERVICE NAME SERVICE VIP WAYPOINT ENDPOINTS
default client 10.96.143.111 kgateway-waypoint 1/1
default kgateway-waypoint 10.96.235.185 kgateway-waypoint 1/1
default ollama 10.96.238.187 kgateway-waypoint 1/1
Once configured, you can take full advantage of the L7 features offered by kgateway, such as rate limiting, header manipulation, and request transformation.
Example: Timeouts
Requests to LLMs may take longer than usual. You can easily modify the request timeout using an HTTPRoute
resource.
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ollama
spec:
parentRefs:
- name: ollama
kind: Service
group: ""
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: ollama
port: 80
timeouts:
request: "180s"
EOF
Example: Rate Limiting
To limit traffic, you can use TrafficPolicy to define a rate limit. Here’s an example that allows three requests per minute:
$ kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
name: ratelimit
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: ollama
rateLimit:
local:
tokenBucket:
maxTokens: 3
tokensPerFill: 3
fillInterval: 60s
EOF
After applying this, if you send more than three requests within a minute, you’ll receive a 429 Too Many Requests
response.
$ kubectl exec -it deploy/client -- curl http://ollama:80/ -v
* Host ollama:80 was resolved.
* IPv6: (none)
* IPv4: 10.96.238.187
* Trying 10.96.238.187:80...
* Connected to ollama (10.96.238.187) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: ollama
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 429 Too Many Requests
< content-length: 18
< content-type: text/plain
< date: Thu, 10 Apr 2025 18:12:29 GMT
< server: envoy
<
* Connection #0 to host ollama left intact
Example: Enable Access Logging
To enable access logging for the kgateway-waypoint, you can configure an HTTPListenerPolicy resource. This allows you to log traffic information such as request methods, response codes, bytes received/sent, and more. Here’s how to set it up:
Apply the access logging configuration
Create the HTTPListenerPolicy resource to enable access logs for the kgateway-waypoint:
$ kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: HTTPListenerPolicy
metadata:
name: access-logging
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: kgateway-waypoint
accessLog:
- fileSink:
path: /dev/stdout
jsonFormat:
start_time: "%START_TIME%"
method: "%REQ(X-ENVOY-ORIGINAL-METHOD?:METHOD)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
protocol: "%PROTOCOL%"
response_code: "%RESPONSE_CODE%"
response_flags: "%RESPONSE_FLAGS%"
bytes_received: "%BYTES_RECEIVED%"
bytes_sent: "%BYTES_SENT%"
request_id: "%REQ(X-REQUEST-ID)%"
authority: "%REQ(:AUTHORITY)%"
EOF
Verify the log output
After deploying this configuration, check the logs from the kgateway-waypoint pod to confirm that access logging is working as expected. Here’s an example of what the log entry might look like when the rate limit configuration is triggered for your ollama StatefulSet:
{"authority": "ollama",
"bytes_received": 0,
"bytes_sent": 18,
"method": "GET",
"path": "/",
"protocol": "HTTP/1.1",
"request_id": "88c6504b-d3e3-4921-92af-d06f0f0ce877",
"response_code": 429,
"response_flags": "RL",
"start_time": "2025-04-10T18:36:34.047Z"}
In this case, the log shows that the client attempted to make a request to the Ollama service but was rate-limited, as indicated by the response_code 429 Too Many Requests
and the response_flags RL
for rate limiting.
See a Demo
This video demonstrates the rate-limiting example in action:
Wrapping Up
I am super excited that the release of kgateway 2.0 brings a new level of extensibility to Istio’s ambient architecture. With the ability to seamlessly integrate kgateway as a waypoint proxy, you gain access to powerful Layer 7 functions while maintaining a unified traffic control experience across both north-south and east-west traffic.
By leveraging Kubernetes Gateway APIs, you can easily configure advanced traffic management features like rate limiting, request transformation, external processing (ExtProc), external Auth, and more — all without wrestling with complex Envoy filters.
Explore kgateway today, and reach out on the community Slack if you have any questions or need assistance!