gateway-demo — may still exist elsewhere on the cluster (noted per row)
Every "not here" / "not on cluster" row names its scope explicitly, because
that is exactly where this page went wrong before: it mixed up what exists
somewhere on wolf-test-k8s-api-gw-v2 with what this specific
demo (gateway-demo) actually uses. Gateway API bundle
v1.4.1, Envoy Gateway v1.7.0 (data plane
envoy:distroless-v1.37.0) — confirmed via
kubectl get crd gatewayclasses.gateway.networking.k8s.io -o jsonpath='{.metadata.annotations.gateway\.networking\.k8s\.io/bundle-version}'
and the envoy-gateway-system deployment images, 2026-08-26.
1. Core API resources
The three resources that form the backbone of every Gateway API
deployment, plus ReferenceGrant. spec statement
— all four are Standard-channel and GA since Gateway API v1.0; that fact
is about the spec, not this cluster.
| Resource | Channel | Notes | Status |
|---|---|---|---|
GatewayClass |
STANDARD | In use as eg, controller gateway.envoyproxy.io/gatewayclass-controller, Accepted=True. Its own parametersRef points to the cluster-wide default EnvoyProxy/cce-proxy-config in envoy-gateway-system — a different object from the one gateway-demo actually uses (see §4). Cmd: kubectl get gatewayclasses -o wide. |
✓ 2026-08-26 |
Gateway |
STANDARD | Live as gateway-demo/gateway-demo, external address 185.153.106.188, Programmed=True, 6 listeners (see §4). Cmd: kubectl -n gateway-demo get gateway gateway-demo -o yaml. |
✓ 2026-08-26 |
HTTPRoute |
STANDARD | Six routes in gateway-demo, all Accepted=True: echo, features, secret, gateway-demo-https-redirect, v1-features, v2-features. Cmd: kubectl -n gateway-demo get httproute. |
✓ 2026-08-26 |
ReferenceGrant |
STANDARD | None in gateway-demo — every backend Service (echo, echo-v2, hello, secret-page, slow, grpc-echo, tcp-echo) is local to the namespace, so none is needed. Cluster-wide, exactly one exists: ocis-app/platform-gateway-tls, unrelated to this demo. Cmd: kubectl get referencegrants -A. |
not here |
2. HTTPRoute features
These are typed spec fields on the live features,
v1-features and v2-features HTTPRoutes in
gateway-demo. Each replaces an annotation-based hack from
the old Ingress days. Verified by reading the routes' YAML directly
(kubectl -n gateway-demo get httproute <name> -o yaml)
and, where noted, by an actual HTTP request.
| Feature | Channel | Notes | Status |
|---|---|---|---|
| Path · PathPrefix | STANDARD | Every rule on features matches a PathPrefix like /features/header. | ✓ 2026-08-26 |
| Path · Exact | STANDARD | path.type: Exact, value: /features/exact — sets x-gw-matched: Path.type=Exact. | ✓ 2026-08-26 |
| Path · RegularExpression | EXPERIMENTAL | path.type: RegularExpression, value: ^/features/users/[0-9]+$. Experimental-channel field, live on this route. | ✓ 2026-08-26 |
| Hostname routing | STANDARD | v1-features and v2-features HTTPRoutes carry distinct hostnames: (v1.features.wolfslight.cc, v2.features.wolfslight.cc) and route to different backends. Live: curl https://v1.features.wolfslight.cc/ → header x-gw-backend: gateway-demo/echo; curl https://v2.features.wolfslight.cc/ → x-gw-backend: gateway-demo/echo-v2. | ✓ 2026-08-26 |
| Header matching | STANDARD | headers: [{name: x-canary, value: "yes"}] on /features/header routes to echo-v2. | ✓ 2026-08-26 |
| Method matching | STANDARD | method: POST on /features/post takes the POST-only rule; a fallback rule without the method match catches GET. | ✓ 2026-08-26 |
| Query-param matching | STANDARD | queryParams: [{name: canary, value: "true"}] on /features/query routes to echo-v2. | ✓ 2026-08-26 |
| Traffic splitting (weights) | STANDARD | /features/split has two backendRefs, weight: 80 / weight: 20 between echo and echo-v2. | ✓ 2026-08-26 |
| Filter · RequestHeaderModifier | STANDARD | /features/inject-header adds x-injected-by-gateway and x-trace-id before the request reaches echo. | ✓ 2026-08-26 |
| Filter · ResponseHeaderModifier | STANDARD | Used on every rule (sets x-gw-matched). /features/response-header also demonstrates add/set/remove together. | ✓ 2026-08-26 |
| Filter · URLRewrite | STANDARD | /features/rewrite is rewritten to /rewritten (ReplacePrefixMatch) before hitting echo. | ✓ 2026-08-26 |
| Filter · RequestRedirect | STANDARD | Two live uses: /features/redirect (302, ReplaceFullPath) and the whole-Gateway HTTP→HTTPS redirect on the http listener (301). Live: curl -I http://gateway.wolfslight.cc/ → 301. | ✓ 2026-08-26 |
| Filter · RequestMirror | STANDARD | /features/mirror: primary echo, mirror echo-v2. Mirror is fire-and-forget — the client only ever sees the primary's response. | ✓ 2026-08-26 |
| Filter · ExtensionRef | STANDARD | Hook for implementation-specific filters (EG plugins). No rule in gateway-demo uses it. | installed |
| Cross-namespace backendRef | STANDARD | The /features/cross-ns rule targets hello — but hello is a local Service in gateway-demo today, not a cross-namespace target. The route's own response header says so: x-gw-matched: "Cross-namespace backendRef demo to lb-demo (now local: see deviation note)". No ReferenceGrant is attached because none is needed. | not here |
| Backend timeouts | STANDARD | /features/timeout: timeouts.request: 2s in front of a slow backend rewritten to /delay/5. Gateway returns 504 in ~2s. | ✓ 2026-08-26 |
| Session persistence | EXPERIMENTAL | Cookie / header sticky sessions on backendRef. CRD field exists; no rule in gateway-demo sets it. | installed |
| BackendRef percentage mirror | EXPERIMENTAL | Mirror a fraction (e.g. 10%) of traffic instead of all of it. Not configured on any rule here. | installed |
3. Beyond HTTPRoute — other Route kinds
Gateway API can route more than HTTP. All four kinds below require the
Experimental channel CRDs, which are installed
cluster-wide (bundle v1.4.1).
| Route Kind | Channel | Notes | Status |
|---|---|---|---|
GRPCRoute | STANDARD | Live as grpc-echo, pinned to the grpc listener (grpc.wolfslight.cc:443). Live: grpcurl -d '{"name":"HUE"}' grpc.wolfslight.cc:443 helloworld.Greeter/SayHello → {"message":"Hello HUE, from grpc-echo-…"}. The only GRPCRoute instance anywhere on the cluster. | ✓ 2026-08-26 |
TCPRoute | EXPERIMENTAL | Live as tcp-echo, pinned to the tcp listener (port 9007). Live: curl http://gateway.wolfslight.cc:9007/ → 200, plain-text banner. The only TCPRoute instance anywhere on the cluster. | ✓ 2026-08-26 |
TLSRoute | EXPERIMENTAL | CRD installed; kubectl get tlsroutes -A returns zero instances anywhere on the cluster. Would need a passthrough listener on a port other than :443 (which is already in Terminate mode here). | installed |
UDPRoute | EXPERIMENTAL | Not built in gateway-demo — this Gateway has no UDP listener. But UDPRoute is not merely installed: it runs in production elsewhere on this cluster — gameforge-palworld/palworld-game and gameforge-palworld/palworld-query (Palworld game server, live >10 days). Cmd: kubectl get udproutes -A. | not here |
4. Gateway listener features
What's configured on the gateway-demo/gateway-demo Gateway
itself — listeners, TLS, infrastructure params. Source of truth:
kubectl -n gateway-demo get gateway gateway-demo -o yaml,
2026-08-26.
| Feature | Channel | Notes | Status |
|---|---|---|---|
| HTTP listener (port 80) | STANDARD | Listener http, hostname gateway.wolfslight.cc. Exactly one route attached — the HTTP→HTTPS redirect. | ✓ 2026-08-26 |
| HTTPS listeners (port 443) | STANDARD | Four listeners share port 443 with distinct hostnames via SNI: https (gateway.), grpc (grpc.), v1-features (v1.features.), v2-features (v2.features.) — not four separate certificates: all four reference the same Secret/gateway-wolfslight-tls. Gateway status flags this explicitly: "certificate SAN … overlaps … ALPN will default to HTTP/1.1 to prevent HTTP/2 connection coalescing" on three of the four listener pairs. | ✓ 2026-08-26 |
| TLS Passthrough listener | EXPERIMENTAL | Listener mode for TLSRoute. Would conflict with the existing Terminate-mode listeners on :443 — needs its own port. | installed |
| Multiple listeners | STANDARD | Six listeners total: http (HTTP:80), https (HTTPS:443), grpc (HTTPS:443), v1-features (HTTPS:443), v2-features (HTTPS:443), tcp (TCP:9007). | ✓ 2026-08-26 |
allowedRoutes.namespaces | STANDARD | Every listener sets from: Same — routes must live in gateway-demo itself. There is no from: All listener on this Gateway. | ✓ 2026-08-26 |
allowedRoutes.kinds | STANDARD | Gateway status reports supportedKinds per listener: HTTPRoute+GRPCRoute on the four HTTP(S) listeners, TCPRoute on tcp. Read from status.listeners[].supportedKinds, not from an explicit kinds: restriction (none is configured). | ✓ 2026-08-26 |
| Hostname on listener | STANDARD | Each of the four HTTPS-family listeners carries exactly one hostname: — gateway., grpc., v1.features., v2.features. — all resolving via DNS to the same Gateway address, dispatched by SNI onto the one shared certificate. | ✓ 2026-08-26 |
parametersRef (GatewayClass-level) | STANDARD | GatewayClass/eg references EnvoyProxy/cce-proxy-config in envoy-gateway-system — the cluster-wide default proxy config, used unless a Gateway overrides it (see next row). | ✓ 2026-08-26 |
Gateway.spec.infrastructure.parametersRef | STANDARD | gateway-demo overrides the class default with its own EnvoyProxy/gateway-demo-proxy-config — this is what actually carries the CCE elb.autocreate/elb.class annotations for this Gateway's ELB. | ✓ 2026-08-26 |
parentRef.sectionName | STANDARD | Every route pins a listener: echo/secret→https, gateway-demo-https-redirect→http, grpc-echo→grpc, tcp-echo→tcp, v1-features→v1-features, v2-features→v2-features. | ✓ 2026-08-26 |
tls.certificateRefs | STANDARD | One Secret (gateway-wolfslight-tls), referenced by all four HTTPS-family listeners — not four separate Secrets. | ✓ 2026-08-26 |
Gateway.spec.addresses | STANDARD | Request a specific IP. Not set — CCE allocates the address. | installed |
5. Envoy Gateway extensions (beyond the spec)
Envoy Gateway ships additional CRDs under gateway.envoyproxy.io
for features the Gateway API spec doesn't yet cover — but in a
Gateway-API-shaped way (typed, declarative, RBAC-able,
targetRefs).
| Resource | Channel | Notes | Status |
|---|---|---|---|
EnvoyProxy | EG-EXTENSION | Two relevant instances: cce-proxy-config (cluster-wide default, referenced by GatewayClass/eg) and gateway-demo-proxy-config (namespace-scoped, referenced by this Gateway's infrastructure.parametersRef, carries the ELB annotations — see §4). | ✓ 2026-08-26 |
BackendTrafficPolicy | EG-EXTENSION | One policy, gateway-demo-ratelimit: local rate limit, 60 requests/Minute, targetRefs: Gateway/gateway-demo. Corrected 2026-08-26: a Local rate limit that targets a Gateway is applied by Envoy Gateway per HTTPRoute — each of the four routes under this Gateway gets its own independent 60/min bucket, not one shared gateway-wide bucket. Still not per-client-IP; that needs rateLimit.global. | ✓ 2026-08-26 |
ClientTrafficPolicy | EG-EXTENSION | None attached to gateway-demo. Cluster-wide it exists twice — iagd-app/insel-client and secpol-demo/secpol-demo-xff — neither targets this Gateway. | not here |
SecurityPolicy | EG-EXTENSION | Two policies live: secret-basic-auth (Basic-Auth on /secret) and cors-features (CORS allowlist on features). Same CRD covers JWT, OIDC, ext-auth, API-key (not configured here). HTTP/gRPC layer only — does not attach to TCPRoute. | ✓ 2026-08-26 |
EnvoyExtensionPolicy | EG-EXTENSION | Live as gateway-demo-waf, targeting the features, v1-features and v2-features HTTPRoutes — Coraza WAF as a WASM filter (ghcr.io/corazawaf/coraza-proxy-wasm), OWASP CRS rules, failOpen: false. A second, unrelated instance exists cluster-wide: secpol-demo/secpol-demo-waf. | ✓ 2026-08-26 |
EnvoyPatchPolicy | EG-EXTENSION | None in gateway-demo. Cluster-wide, one instance exists: secpol-demo/secpol-demo-local-reply — an unrelated demo. | not here |
HTTPRouteFilter | EG-EXTENSION | EG-specific HTTPRoute filters (CredentialInjection, etc). CRD installed; kubectl get httproutefilter -A returns zero instances anywhere on the cluster. | installed |
Backend | EG-EXTENSION | Reference non-Service backends (IP, FQDN, Unix socket). CRD installed; kubectl get backend -A returns zero instances anywhere on the cluster. | installed |
5b. Hardening · OWASP-style protection
Defense-in-depth at the gateway layer — what's actually live in front
of every request to gateway.wolfslight.cc and its sibling
hostnames.
| Layer | Implemented as | Notes | Status |
|---|---|---|---|
| TLS hardening (min version, cipher allowlist) | ClientTrafficPolicy | No ClientTrafficPolicy targets gateway-demo. Whatever TLS floor Envoy applies here is its built-in default, not an explicit policy — the CRD exists and is used elsewhere on the cluster (§5), just not here. |
not here |
| Rate limiting (60 req/min, per route) | BackendTrafficPolicy | gateway-demo-ratelimit: local limit of 60 requests/minute, per Envoy replica (gateway-demo runs 1) and per route — each HTTPRoute under this Gateway gets its own independent bucket, not one bucket shared across the whole Gateway. Still not split per client IP; see the note below the table. |
✓ 2026-08-26 |
| CORS allowlist | SecurityPolicy | cors-features: single explicit origin https://gateway.wolfslight.cc, no *. Methods GET/POST/OPTIONS, header allowlist including x-canary. |
✓ 2026-08-26 |
| Security headers | HTTPRoute filter | Live: curl -I https://gateway.wolfslight.cc/ returns Strict-Transport-Security, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy, Content-Security-Policy — set via ResponseHeaderModifier. |
✓ 2026-08-26 |
| Basic-Auth gate | SecurityPolicy | Live: curl https://gateway.wolfslight.cc/secret → 401; with -u test:test → 200. |
✓ 2026-08-26 |
| WAF — OWASP-style rules | EnvoyExtensionPolicy (WASM) | Live: a SQLi-shaped query string against v1.features.wolfslight.cc returns 403; a harmless request to the same route returns 200. Applied on all three routes the policy targets (features, v1-features, v2-features). |
✓ 2026-08-26 |
| HTTP → HTTPS redirect | HTTPRoute filter | Live: curl -I http://gateway.wolfslight.cc/ → 301, Location: https://gateway.wolfslight.cc/. |
✓ 2026-08-26 |
| L4 backend self-auth / ELB ACL (TCPRoute) | n/a | SecurityPolicy cannot attach to TCPRoute — confirmed, it's an HTTP/gRPC-layer CRD. tcp-echo, the actual live TCPRoute backend, needs no auth by design (its own response: "no data stored, nothing to authenticate"). No backend-level auth or ELB listener ACL is configured for it today. |
not here |
| JWT / OIDC / ext-auth | SecurityPolicy | Same CRD as Basic-Auth, different sub-block. Supported by the installed CRD, not configured on any policy here. | installed |
| Global rate-limit (Redis-backed) | BackendTrafficPolicy.rateLimit.global | Cluster-wide consistent limits across many Envoy pods. Only the Local rate-limit type is configured here (see above). |
installed |
| mTLS to backends | BackendTLSPolicy | Encrypt the leg between Envoy and backend pods. CRD installed; kubectl get backendtlspolicy -A returns zero instances anywhere on the cluster. |
installed |
Why the original single-route burst test proved nothing
An earlier pass fired 80 parallel requests at one route
(/features/exact) and saw 60×200/20×429, then
concluded the bucket was shared across the whole Gateway. That
conclusion doesn't follow from that evidence: a per-route bucket
and a gateway-wide bucket produce the exact same result
when only one route is under test. A single-route burst can't
distinguish the two explanations — it needs a second route.
Re-run 2026-08-26: the same 80-request burst against
/features/exact still lands 60×200/20×429 (that
route's bucket is exhausted), but a request to /secret
fired immediately afterward returns 401 (not
429), and a request to / returns
200 (not 429). If the bucket were
gateway-wide, both would have been rate-limited too. They weren't
— the limit is per route, exactly as
apps/gateway-demo/policies.yaml (corrected there on
2026-07-15, commit 5025d9b) already said.
6. Swiss OTC / CCE-specific findings
These are behaviours of the underlying cloud + CCM, not of Gateway API itself — but they show up exactly because Gateway API needs them.
| Concern | Layer | Notes | Status |
|---|---|---|---|
| ELB auto-provisioning | CCE-CCM | kubernetes.io/elb.autocreate (set via EnvoyProxy/gateway-demo-proxy-config's envoyService.annotations) triggered ELB + EIP creation for gateway-demo. Eight ELBs run in parallel across the cluster right now — one per Gateway, not three. | ✓ 2026-08-26 |
| EIP automatic attachment | CCE-CCM | CCM created an EIP and wrote it back as kubernetes.io/elb.eip-id: 49aa6e66-… on the Envoy Service. | ✓ 2026-08-26 |
Strict bandwidth_name requirement | CCE-CCM | Documented CCE-CCM admission behaviour: autocreate JSON without bandwidth_name is rejected. The repo's manifest already sets it correctly; the rejection path itself was not re-triggered on this pass (no negative test performed). | installed |
| Source-IP preservation | CCE-CCM | Envoy Service has externalTrafficPolicy: Local (set by gateway-demo-proxy-config). | ✓ 2026-08-26 |
| TLS termination at Envoy (not the ELB) | CCE-CCM + EG | The L4 ELB passes TCP through; Envoy terminates TLS using the cert-manager-issued cert. One shared 4-SAN certificate serves all four HTTPS-family listeners via SNI — not four independent certs. | ✓ 2026-08-26 |
| DNS via external-dns | cluster-external | Live: dig +short gateway.wolfslight.cc grpc.wolfslight.cc v1.features.wolfslight.cc v2.features.wolfslight.cc all resolve to 185.153.106.188, the Gateway's address. | ✓ 2026-08-26 |
| cert-manager + Let's Encrypt | cluster-external | Certificate/gateway-wolfslight-tls: Ready=True, one certificate with four SANs (gateway., grpc., v1.features., v2.features.), valid until 2026-11-24 — not four separate certificates. | ✓ 2026-08-26 |
Shared-ELB pattern (elb.id reuse without autocreate) | CCE-CCM | No Service anywhere on the cluster uses elb.id to attach to an existing ELB without also setting autocreate. Every one of the eight LoadBalancer Services follows the same one-Gateway-one-ELB pattern; no whoami/fortune shared-ELB demo exists. | not on cluster |
| Multiple Gateways → multiple ELBs | CCE-CCM | Eight Gateways, eight independent ELBs and EIPs: gateclear, coder, platform, palworld, gameforge-auth, gateway-demo, insel, secpol-demo. | ✓ 2026-08-26 |
7. Upstream conformance suite
The authoritative "does X support Gateway API properly" answer comes from the upstream conformance suite — a Go test binary that exercises every spec'd feature against a real cluster + controller and emits a report. It was not run on this cluster. Every row below is a spec statement about the suite or the spec itself, not a claim this cluster's state can confirm or refute — they are excluded from the tallies above and in §8.
| Profile / suite | Channel | Notes | Status |
|---|---|---|---|
| Conformance Profile: Gateway-HTTP | STANDARD | Tests the GA HTTPRoute surface. Not run. | spec statement |
| Conformance Profile: Gateway-GRPC | STANDARD | Tests the GRPCRoute surface. Not run. | spec statement |
| Conformance Profile: Gateway-TLS | EXPERIMENTAL | Tests TLSRoute and TLS termination. Not run. | spec statement |
| Conformance Profile: Mesh | STANDARD | For service-mesh implementations — not this cluster's use case. | n/a |
How to run it (~30–60 min)
Clones the Gateway API repo at the tag matching what's actually
installed on this cluster (v1.4.1 — the run instructions
used to pin v1.2.1, two majors behind; that mismatch is
a stale instruction, not a claim about the cluster) and runs the
conformance test binary against the eg GatewayClass:
git clone --depth 1 --branch v1.4.1 \ https://github.com/kubernetes-sigs/gateway-api.git /tmp/gateway-api cd /tmp/gateway-api go test ./conformance \ -run TestConformance -v -timeout 60m \ -args --gateway-class=eg --report-output=$PWD/conformance-report.yaml
Output: conformance-report.yaml with a per-test pass/fail/skip matrix. Full instructions in tests/conformance/README.md.
8. Verdict
Everything above is a snapshot, dated 2026-08-26, against
wolf-test-k8s-api-gw-v2. It replaces a version of this
page that named a Gateway (default/eg, address
138.124.232.181) which does not and never did exist on
this cluster — a straight carry-over from the predecessor
wolf-apigw-external that was never re-verified.
| Category | What it means here | How to close it |
|---|---|---|
| TLSRoute, mTLS (BackendTLSPolicy), HTTPRouteFilter, Backend | CRDs are installed cluster-wide (Experimental + EG-extension channels are live), but zero live instances exist anywhere on this cluster to point at. | Each needs a concrete use case built and attached with targetRefs before it can move to "verified". |
| Session persistence, BackendRef percentage mirror, Filter · ExtensionRef | Experimental-channel HTTPRoute fields. CRDs present, no rule on features/v1-features/v2-features sets them yet. |
Add spec.rules[].sessionPersistence, a percentage-based RequestMirror, or an ExtensionRef filter to a rule. |
| ClientTrafficPolicy, EnvoyPatchPolicy | Both exist and are exercised elsewhere on the cluster (secpol-demo, iagd-app) — just not attached to gateway-demo. |
Write a policy with targetRefs: Gateway/gateway-demo the same way gateway-demo-ratelimit and gateway-demo-waf already do. |
| Conformance suite output | ~30–60 min run in a sandbox namespace. Authoritative pass/fail report, not yet generated. | Follow §7's runner instructions. Paste the resulting conformance-report.yaml summary into docs/compatibility-matrix.md. |
Net, as of 2026-08-26: 46 of 66 inventoried claims are live-verified
Of the 66 capability claims audited on this page, 46 are
live-verified against wolf-test-k8s-api-gw-v2 —
the full HTTPRoute matcher and filter surface on
gateway-demo, GRPCRoute and
TCPRoute both live for the first time on this cluster,
all six Gateway listeners with their real topology (one shared
4-SAN certificate, from: Same namespace scoping, both
levels of parametersRef), five EG-Extension policies
actually attached to gateway-demo (rate-limit, two
SecurityPolicy instances, the Coraza WAF), and the
real CCE-CCM behaviour (eight ELBs, not three; one shared cert, not
four).
12 claims describe features that are installed —
CRD present, cluster-wide or namespace-scoped — but not exercised
here. 8 describe something asserted absent: 7 are
scoped to gateway-demo specifically (several of those
— ClientTrafficPolicy, UDPRoute,
EnvoyPatchPolicy — do run elsewhere on this cluster;
the scope is the whole point), and 1 (the shared-ELB pattern) was
checked cluster-wide and found nowhere. Zero of the
46 live-verified claims failed their check on this pass.
This is a smaller, more specific number than the "43 of 52 live-verified" this page used to claim — because that number was never re-earned after the cluster underneath it changed. This one is dated, and it will need re-dating the next time this page is touched.