Why Separating Control Plane from Data Plane Matters

▶ Watch (0:54)

When you expose a pod to user traffic, that pod should not also talk to the Kubernetes API server. Katz learned this the hard way maintaining ingress-nginx: CVEs followed directly from that conflation. His goal with this project was a reusable control plane that any proxy backend could consume, so the data plane never touches Kubernetes directly. That separation is the entire motivation for hooking into Agentic Gateway’s XDS server rather than writing a full controller.

How Kgateway Generates Proxy Configuration

▶ Watch (4:56)

Kgateway runs the full Gateway API reconciliation loop: it accepts or rejects Gateways, attaches HTTPRoutes, evaluates BackendTLSPolicy, and tracks status conditions. The output is an Aggregated Discovery Service (ADS) gRPC stream. The model it produces is intentionally simpler than raw Envoy xDS. A backend only needs to consume four things: a port binding, a listener, a route, and an IP definition. Messages for TCP and UDP routes are already in the schema, waiting for implementations to use them.

Discovering a CVE While Building the Client

▶ Watch (8:52)

Katz wrote a Go client that impersonates an Agentic Gateway proxy to read the ADS stream. While building it, he found that sending any pod name and namespace was enough to scrape the entire control plane. That is weak authentication by any measure. He reported it responsibly, the Kgateway maintainers patched it, and he kept building. He also shipped a terminal UI on top of the client so he could watch messages flow in real time as he edited HTTPRoutes and changed path prefixes.

The Nginx Backend: Vibe-Coded but Working

▶ Watch (13:19)

The nginx implementation consumes the two message types from the ADS stream: workload addresses (endpoints) and resources (listeners, routes, certificates). For every message it parses the payload and rewrites an nginx config file using the nginx-go-crossplane library instead of Go templates. Go templates are where ingress-nginx CVEs came from, so Katz skipped them. The proxy reloads nginx on each config change. A live demo showed a curl succeeding through the nginx gateway after an HTTPRoute edit, with ADS messages visible in the pod logs.

Conformance Gaps and the Pretending Problem

▶ Watch (18:24)

The nginx backend passes 19 of 30 Gateway API conformance tests. It registers itself by pointing a GatewayClass at a custom image and parameters, telling Agentic Gateway to deploy nginx instead of its own proxy. The impersonation is intentional but has one gap: if a user applies an unsupported route type, the proxy silently ignores it. Katz recommends adding a validating admission policy to reject unsupported resources before they reach the data plane, rather than letting them disappear without feedback.

Notable Quotes

I vibe coded that. So if you try using that in production please don’t right Ricardo Katz · ▶ 13:25

I found the CVE which was key gateway having weak authentication right. Ricardo Katz · ▶ 09:26

the majority of the cve they are because of uh go plating. So please don’t use go plates on your proxies Ricardo Katz · ▶ 14:23

I don’t care about the whole reconciliation loop adding status conditions to the gateway API, right? Ricardo Katz · ▶ 12:54

Key Takeaways

  • Kgateway’s ADS stream exposes four message types; backends only need to consume those four.
  • A CVE in Kgateway allowed full control-plane scraping with just a pod name and namespace.
  • Go templates in proxy config generation are a direct source of CVEs; use a structured library instead.

About the Speaker(s)

Ricardo Katz is a Software Engineer at Red Hat working on OpenShift Ingress, Gateway API, and DNS. He is a Kubernetes Gateway API maintainer and previously maintained ingress-nginx before it was deprecated. He builds infrastructure tooling and, apparently, nginx proxies backed by Rust-written AI gateways.