A Kubernetes Gateway API implementation written in Rust:
kube-rs control plane, Cloudflare Pingora data plane, per-Gateway
proxy workloads, a GAMMA service-mesh sidecar for east-west routing,
and an AI Gateway for LLM traffic — routing
OpenAI, Anthropic, and Amazon Bedrock behind a unified
/v1/chat/completions API with JWT-based consumer
identity and weighted backend selection.
Conformance run 2026-04-26 · controller/proxy v0.3.0
· the upstream Go test harness reports PASS in
3 min 26 sec with 125 top-level
tests passed (471 sub-tests) and 0
failures across the three declared profiles
(GATEWAY-HTTP, GATEWAY-GRPC,
MESH-HTTP) plus the TLSRoute test set, which is
exercised through the TLSRoute,
TLSRouteModeTerminate, and
TLSRouteModeMixed features.
CitoRoute is a 100 % Rust implementation of the
Kubernetes Gateway API
(gateway.networking.k8s.io) — the official successor
to Ingress. It ships an opinionated stack: a control plane
built on kube-rs and an L7
data plane built on Cloudflare
Pingora, with tokio-rustls
and raw tokio sockets handling the TLSRoute Passthrough,
Terminate, and Mixed planes.
The entire codebase is written by AI coding agents working under human direction and review — an experiment in building production-grade infrastructure software through human–AI collaboration.
kube-rs + kube-runtime)Gateway, GatewayClass,
HTTPRoute, GRPCRoute, TLSRoute,
ListenerSet, ReferenceGrant,
BackendTLSPolicy, JWTValidationPolicy,
LLMBackend, LLMRoute,
Consumer,
Service, EndpointSlice,
Secret, ConfigMapConfigMap per Gateway)
consumed by the proxy via a mounted volumeDeployment per
Gateway, in the Gateway's own namespaceProxyHttptokio::io::copy_bidirectional shoveltokio-rustls::TlsAcceptor, hot-swappable
ServerConfig via ArcSwapArcSwap — no
proxy restarts on config changecitoroute-webhook) injects a Pingora sidecar +
iptables init container:15001 via
SO_ORIGINAL_DST, inbound passthrough on
:15006citoroute-mesh
ConfigMap indexes every
HTTPRoute with
parentRef.kind = Servicekube-rs
watch (falls back to a 500 ms file poll)BackendTLSPolicy (CA + SAN validation,
SPIFFE/URI, conflict resolution)JWTValidationPolicy
(citoroute.io/v1alpha1) — direct policy
attachment to Gateway per
GEP-713ListenerSet for additional listeners
attached to a GatewayReferenceGrant enforced for every
cross-namespace reference (Secrets, Services, CA
ConfigMaps)LLMBackend,
Consumer, LLMRoute
(citoroute.io/v1alpha1)/v1/chat/completions API —
clients speak OpenAI protocol, the proxy translates to
each provider nativelyConsumer identity with
claim matching & per-route authorizationLLMBackend resources
CitoRoute is run through the official upstream
Gateway
API conformance suite at version v1.5.1
(Experimental channel) in a single in-cluster run completed on
2026-04-26. This run includes the AI Gateway
code (LLMBackend, Consumer, LLMRoute CRDs and proxy logic).
The Go test harness reports PASS with no failures.
In Gateway API terminology, an implementation is "conformant" for a
profile when (a) every Core test passes and (b) every Extended
feature it declares in --supported-features
passes. Implementations are free not to declare individual
Extended features; undeclared features are auto-skipped and don't
affect conformance. CitoRoute exercises two architecturally
distinct stacks against this suite:
Gateway
Pingora proxy Deployment. Used for north-south
ingress (HTTP, gRPC, TLS Passthrough/Terminate/Mixed).The two are summarised separately below to avoid implying that a single number covers both stacks.
| Profile | Core | Standard Extended | Experimental | Total (top-level · sub-tests) | Failed | Skipped |
|---|---|---|---|---|---|---|
GATEWAY-HTTP |
34 / 34 | 45 / 45 | 10 / 10 | 89 passed · 342 sub-tests | 0 | 0 |
GATEWAY-GRPC |
4 / 4 | 1 / 1 | — | 5 passed · 25 sub-tests | 0 | 0 |
TLSRoute (Passthrough + Terminate + Mixed) |
8 / 8 | 2 / 2 | 1 / 1 | 13 passed · 29 sub-tests | 0 | 0 |
Across the three Gateway profiles every Core test passes, every
Extended feature published in v1.5 is declared, and every
declared feature passes. The 37 count is the
de-duplicated set of Extended features we declare across the
three route types: 25 HTTPRoute-specific
(3xx redirects, H2C / WebSocket, CORS, request mirroring,
timeouts, rewrites, header modifications, method / query / path
matching, BackendTLSPolicy + SAN validation, …)
+ 2 TLSRoute-specific
(TLSRouteModeTerminate,
TLSRouteModeMixed) + 1
GRPCRoute-specific (the GRPCRoute profile itself)
+ 9 Gateway-* features shared across all three
route types (address-empty, port 8080, listener isolation,
infrastructure propagation, static addresses, frontend client
certificate validation + insecure fallback, backend client
certificate, misdirected-request detection)
+ 1 ListenerSet shared across all
three. Per-route, that maps to the same
35 / 10 / 12 column counts shown on the
upstream
v1.5
comparison for HTTPRoute, GRPCRoute and TLSRoute respectively
(with shared features counted once per table). The
TLSRoute total above includes two early-returning
NotSupported tests
(TLSRouteListenerTerminateNotSupported and
TLSRouteListenerMixedTerminationNotSupported) that
the harness reports as PASS once the corresponding modes are
declared — the active TLSRoute test set is 8 + 2 + 1 = 11.
The harness also logs one auto-skip for a single
UDPRoute test
("suite does not support UDPRoute"). UDPRoute is an
Alpha L4 resource in
gateway.networking.k8s.io/v1alpha2 that is
not part of the v1.5 Standard / Experimental
channel and is not graded on the
v1.5
implementations comparison. CitoRoute does not implement it
and no v1.5 conformance profile depends on it.
--skip-tests)| Profile | Mesh Core | Mesh Extended (declared) | Total (top-level · sub-tests) | Failed | Skipped |
|---|---|---|---|---|---|
MESH-HTTP |
9 / 9 | 9 / 9 declared (7 mesh-specific + 2 gateway-shared) | 18 passed · 75 sub-tests | 0 | 4 opt-outs |
Mesh Core is fully covered. Two mesh-specific Extended
features are intentionally not declared —
MeshClusterIPMatching (sidecar implements it but
a separate Service-attribute validation is still pending) and
MeshConsumerRoute (cross-namespace
parentRef.kind=Service, not yet wired to
ReferenceGrant). Four upstream tests are listed in
--skip-tests for known sidecar limitations or a
broken upstream test:
MeshConsumerRoute, MeshFrontendHostname,
MeshGRPCRouteWeight, and
MeshHTTPRoute307Redirect (see
Mesh profile below).
The authoritative ranking lives on the official Gateway API v1.5 implementations comparison page, which aggregates the Extended-feature coverage from every submitted report and is updated as new submissions land. Rather than mirror that table here (and risk it going stale), this page only summarises CitoRoute's own position in it — and only for the three Gateway profiles, since the official Mesh table currently lists no v1.5 entries.
On a snapshot of that page taken on 2026-04-26, CitoRoute is one of only two v1.5 submissions to declare and pass every published Extended feature for the three Gateway profiles — HTTPRoute 35 / 35, GRPCRoute 10 / 10, and TLSRoute 12 / 12, with zero skipped tests in those profiles. The other project at that level is agentgateway; the next tier is envoy-gateway at 33–34, 8–9, and 10–11 respectively (with several tests skipped), followed by kgateway, nginx-gateway-fabric, traefik, microgateway, haproxy-ingress, and gke-gateway with progressively narrower feature sets.
CitoRoute additionally submits a MESH-HTTP profile
from a separate sidecar binary — not directly comparable
to the Gateway-profile numbers above, and with the caveats noted
in the Mesh section.
Comparison summary captured 2026-04-26 — the upstream page may have changed since. Always refer to the live comparison for the current state of the ecosystem.
Gateway proxy
The three cards below cover the north-south stack: a Pingora-based
proxy Deployment per Gateway resource,
sharing one HTTP/2 engine across HTTPRoute, GRPCRoute, and the
TLSRoute Passthrough / Terminate / Mixed planes. Every Extended
feature published for these three profiles in v1.5 is declared and
passing — the per-profile feature tables list them
individually.
Per-feature view using the same column layout as the
official
comparison table. CitoRoute declares and passes every one of
the 35 Extended features published for HTTPRoute in
v1.5.
✓ supported & passing
| Project | Extended features | Core | Backend TLS Policy | Backend TLS Policy SAN Validation | Gateway Address Empty | Gateway Backend Client Certificate | Gateway Frontend Client Certificate Validation | Gateway Frontend Client Certificate Validation Insecure Fallback | Gateway HTTP Listener Isolation | Gateway HTTPS Listener Detect Misdirected Requests | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | HTTPRoute 303R Status Code | HTTPRoute 307R Status Code | HTTPRoute 308R Status Code | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol WebSocket | HTTPRoute Backend Request Header Modification | HTTPRoute Backend Timeout | HTTPRoute CORS | HTTPRoute Destination Port Matching | HTTPRoute Host Rewrite | HTTPRoute Method Matching | HTTPRoute Named Route Rule | HTTPRoute Parent Ref Port | HTTPRoute Path Redirect | HTTPRoute Path Rewrite | HTTPRoute Port Redirect | HTTPRoute Query Param Matching | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Percentage Mirror | HTTPRoute Request Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | Listener Set |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| citoroute v0.3.0 | 35 / 35 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
CitoRoute translates gRPC service/method matching to HTTP/2 path
matching and reuses the same Pingora HTTP/2 stack. Every Extended
Gateway feature declared for HTTPRoute also runs against
GRPCRoute, plus GRPCRouteNamedRouteRule.
All 10 Extended features published for GRPCRoute in
v1.5 pass.
| Project | Extended features | Core | Gateway Address Empty | Gateway Backend Client Certificate | Gateway Frontend Client Certificate Validation | Gateway Frontend Client Certificate Validation Insecure Fallback | Gateway HTTP Listener Isolation | Gateway HTTPS Listener Detect Misdirected Requests | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | Listener Set |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| citoroute v0.3.0 | 10 / 10 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
CitoRoute implements all three TLSRoute modes defined by Gateway
API v1.5.1: Passthrough (Core),
Terminate (Standard Extended), and
Mixed (Experimental). The proxy uses
tokio SNI peeking for Passthrough,
tokio-rustls for Terminate, and a buffered-ClientHello
dispatcher for Mixed — all three behind the same dynamic-bind
machinery used by the HTTPS listener.
| Project | Extended features | Core | Gateway Address Empty | Gateway Backend Client Certificate | Gateway Frontend Client Certificate Validation | Gateway Frontend Client Certificate Validation Insecure Fallback | Gateway HTTP Listener Isolation | Gateway HTTPS Listener Detect Misdirected Requests | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | Listener Set | TLSRoute Mode Mixed | TLSRoute Mode Terminate |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| citoroute v0.3.0 | 12 / 12 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
The mesh profile is served by an entirely different
binary mode and codepath: a per-pod Pingora sidecar
injected by an admission webhook
(citoroute-webhook), with egress on
:15001 via SO_ORIGINAL_DST and inbound
passthrough on :15006. None of the per-Gateway proxy
results above carry over — mesh has its own feature
coverage, its own caveats, and its own list of
not-yet-implemented features.
CitoRoute submits a MESH-HTTP profile against the
same upstream conformance suite, run against the injected
sidecar. The official v1.5 implementations comparison currently
lists no projects under the
Mesh
HTTPRoute section, so there is no peer to compare against
here.
| Tier | Result | Notes |
|---|---|---|
Mesh Core (Mesh feature) |
9 / 9 tests, 29 sub-tests | Every mandatory east-west test passes |
| Mesh-specific Extended (declared) | 7 / 7 tests, 44 sub-tests | All declared mesh-specific Extended features pass |
| Gateway-shared Extended (303 / 308 redirects) | 2 / 2 tests, 2 sub-tests | Inherited from the same redirect plumbing |
| Total passing | 18 tests, 75 sub-tests, 0 failures | — |
The seven mesh-specific Extended features that are declared and pass:
MeshHTTPRouteQueryParamMatching — exact
query-parameter matchingMeshHTTPRouteNamedRouteRule —
name on HTTPRouteRuleMeshHTTPRouteBackendRequestHeaderModificationMeshHTTPRouteRedirectPath —
replacePrefixMatch & replaceFullPathMeshHTTPRouteRedirectPort — well-known
port omissionMeshHTTPRouteSchemeRedirect — HTTP ↔ HTTPSMeshHTTPRouteRewritePath — prefix and full-path
rewrite
Two published mesh-specific Extended features are
intentionally not declared in
--supported-features, and four upstream tests are
listed in --skip-tests. Conformance terminology
treats undeclared features as auto-skipped (they don't fail the
run), but they are still gaps a reader should know about.
| Item | Status | Reason |
|---|---|---|
MeshClusterIPMatching (Extended feature) |
not declared | Sidecar already matches by ClusterIP via
SO_ORIGINAL_DST, but the upstream test
asserts an additional Service attribute that needs a
separate validation pass before we declare the feature |
MeshConsumerRoute (Extended feature) |
not declared & opted out | Cross-namespace
HTTPRoute.parentRef.kind=Service not
implemented; sidecar rejects with
Accepted=False / NotAllowedByListeners until
ReferenceGrant support lands |
MeshFrontendHostname (test) |
opted out | Sidecar matches by ClusterIP, not by Host header |
MeshGRPCRouteWeight (test) |
opted out | Sidecar is HTTP-only today; no gRPC-mesh path yet |
MeshHTTPRoute307Redirect (test) |
opted out | 307 redirect itself works (gateway test
HTTPRoute307Redirect passes) — the
upstream mesh test is broken: it
references
the 303 manifest, so no implementation can satisfy
its 307 assertion in v1.5.1 |
Several other mesh tests
(MeshHTTPRouteRequestMirror,
MeshHTTPRouteRequestMultipleMirrors,
MeshHTTPRouteRequestPercentageMirror,
MeshHTTPRouteTimeoutRequest,
MeshHTTPRouteTimeoutBackendRequest,
MeshHTTPRouteCORS,
MeshBackendTLSPolicy,
MeshBackendTLSPolicySANValidation) are also listed
defensively in --skip-tests as not-yet-implemented
in the sidecar. They do not exist in the v1.5.1 suite yet, so
they don't appear in the run output, but they document scope
that the sidecar does not cover today.
The AI Gateway extends CitoRoute with three custom CRDs
(citoroute.io/v1alpha1) that let teams expose
LLM providers behind a unified OpenAI-compatible API.
Clients send standard /v1/chat/completions requests;
the proxy translates to each provider’s native protocol,
manages credentials, and enforces consumer-level access control.
x-api-key auth · automatic body translation from OpenAI format · streaming SSE
| CRD | Purpose | Key fields |
|---|---|---|
LLMBackend |
One provider + model + endpoint + credentials | provider, model, endpoint, credentialsRef, timeout, bedrock.region |
Consumer |
Map a JWT claim key/value to a named identity | jwtClaimMatch.key, jwtClaimMatch.value |
LLMRoute |
Bind Gateway parents, consumers, and backends | parentRefs[], consumerRefs[], path, backendRefs[] (with weight) |
LLMBackend
resources with configurable weightsPathPrefix or Exact match
(default: /v1/chat/completions)Consumer
resources; LLMRoute.consumerRefs controls
which consumers may use each routeconsumerRefs for public LLM endpoints (no
JWT required)Secret or the pod’s default
AWS credential chain (IRSA, instance profile)citoroute_llm_requests_total and
citoroute_llm_tokens_total Prometheus
metrics with consumer, backend, model, and provider
labels
Client
⟶ Gateway listener
⟶ JWT validation (if JWKS configured)
⟶ LLMRoute path match
⟶ Consumer identity check
⟶ weighted LLMBackend selection
⟶ protocol translation & credential injection
⟶ upstream provider (OpenAI / Anthropic / Bedrock)
⟶ response translation to OpenAI format
⟶ Client
A single LLMRoute can reference multiple
LLMBackend resources with different providers
and weights. Combined with Consumer resources,
teams can be isolated to specific routes while sharing the
same Gateway listener:
| Route path | Consumers | Backends | Behaviour |
|---|---|---|---|
/v1/chat/completions |
team-alpha, team-beta |
OpenAI (weight 3) + Anthropic (weight 1) | 75/25 weighted split, JWT required |
/llm/bedrock |
team-alpha |
Bedrock (weight 1) | Bedrock-only, SigV4 signed, single team |
/ai/chat (Exact) |
none (public) | OpenAI (weight 1) | Open route, no JWT needed |
Conformance is executed as an in-cluster Kubernetes
Job — the upstream
conformance-test Go binary running with cluster-admin
RBAC against a clean Minikube node.
| Cluster | Minikube v1.35.1, single-node |
| Architecture | aarch64 (Apple Silicon) |
| Resources | 4 vCPU · 6 GiB RAM |
| Gateway API CRDs | v1.5.1, Experimental channel |
| Conformance suite | kubernetes-sigs/gateway-api conformance v1.5.1 |
| Conformance image tag | 20260426092159 |
| Controller / proxy image tag | 20260426091613 (citoroute v0.3.0, includes AI Gateway) |
| Profiles | GATEWAY-HTTP,GATEWAY-GRPC,MESH-HTTP (TLSRoute is exercised through the declared TLSRoute, TLSRouteModeTerminate, and TLSRouteModeMixed features) |
| Test runner | In-cluster Job (-test.timeout=30m), single attempt, backoffLimit: 0 |
| Run date | 2026-04-26 (started 09:22 UTC) |
| Result | Go harness reports PASS · 0 failures · 125 top-level PASS · 471 sub-test PASS · 5 top-level SKIP (4 declared --skip-tests mesh opt-outs + 1 harness auto-skip for the undeclared UDPRoute alpha profile) |
| Wall-clock duration | 3 min 26 sec (206 s reported by the Go test harness; the -test.timeout=30m ceiling was never approached) |
| Container resources | requests: 100m CPU / 128Mi mem · limits: 500m CPU / 512Mi mem · per conformance pod |
k8s-openapi 0.27 / kube 3 /
gateway-api 0.21 (Rust)tokio-rustls for
the Terminate / Mixed planescitoroute field manager;
all generated resources are reconciled idempotently