Path · Exact
Matches the path exactly. Anything longer or shorter does not match.
- matches: - path: { type: Exact, value: /features/exact }
HTTP Method
First rule matches only POST; a fallback rule catches every other method on the same path.
- matches: - path: { type: PathPrefix, value: /features/post } method: POST
Header matching
When x-canary: yes is present, routes to echo-v2; otherwise to echo.
- matches: - path: { type: PathPrefix, value: /features/header } headers: - { name: x-canary, value: "yes" }
Query param matching
?canary=true routes to echo-v2; without it, default backend.
- matches: - path: { type: PathPrefix, value: /features/query } queryParams: - { name: canary, value: "true" }
Weighted traffic split
Splits 80% to echo, 20% to echo-v2. Click to fire 20 requests and see distribution.
- backendRefs: - { name: echo, port: 80, weight: 80 } - { name: echo-v2, port: 80, weight: 20 }
URLRewrite filter
Gateway strips /features/rewrite and forwards as /rewritten/... to the backend.
- filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: /rewritten
RequestHeaderModifier
Gateway injects two extra headers into the request before forwarding. The echo backend shows them in its JSON.
- filters: - type: RequestHeaderModifier requestHeaderModifier: add: - { name: x-injected-by-gateway, value: envoy-gateway-eg } - { name: x-trace-id, value: demo-trace-42 }
RequestRedirect filter
Gateway answers with 302 and a Location header — never even contacts a backend.
- filters: - type: RequestRedirect requestRedirect: path: type: ReplaceFullPath replaceFullPath: /features/exact statusCode: 302
Path · RegularExpression
Matches when the path matches the regex. Anything else falls through. Requires the experimental Gateway-API CRDs (installed on this cluster).
- matches: - path: type: RegularExpression value: "^/features/users/[0-9]+$"
Hostname matching
Two HTTPRoutes attach to the same Gateway with different hostnames:. We probe with an explicit Host: header — no DNS needed.
hostnames: [ "v1.features.wolfslight.cc" ] # second HTTPRoute hostnames: [ "v2.features.wolfslight.cc" ]
ResponseHeaderModifier
Adds x-added-header, sets content-language: en-CH, removes etag — all three sub-modes in one filter.
- filters: - type: ResponseHeaderModifier responseHeaderModifier: add: - { name: x-added-header, value: "I was added by the Gateway" } set: - { name: content-language, value: en-CH } remove: [ "etag" ]
RequestMirror filter
Primary backend echo answers; echo-v2 receives a fire-and-forget copy. The primary's response is what you see; the mirror runs in the background.
- filters: - type: RequestMirror requestMirror: backendRef: kind: Service name: echo-v2 port: 80
Cross-namespace backendRef
HTTPRoute in demo namespace points at a Service in lb-demo. Requires a ReferenceGrant in the backend namespace; without it the route is rejected.
- backendRefs: - name: hello namespace: lb-demo # cross-NS port: 80 # + ReferenceGrant in lb-demo allowing routes from demo
Backend timeouts
Slow backend (httpbin /delay/5) sleeps 5 s. HTTPRoute has timeouts.request: 2s. Gateway returns 504 after ~2 s without waiting for the backend.
- matches: - path: { type: PathPrefix, value: /features/timeout } timeouts: request: "2s" backendRequest: "2s" # backend would take 5s
BackendTrafficPolicy · Local Rate Limit (10 rps per IP)
Envoy Gateway's local rate-limit: each Envoy pod keeps a per-source-IP counter, no Redis needed. Burst more than 10 req/s from your IP and the surplus comes back as 429 Too Many Requests.
apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy metadata: name: ratelimit-features spec: targetRefs: - kind: HTTPRoute name: features rateLimit: type: Local local: rules: - clientSelectors: - sourceCIDR: { value: "0.0.0.0/0", type: Distinct } limit: requests: 10 unit: Second
Security Headers via ResponseHeaderModifier
Six browser-side hardening headers set globally on the UI + JSON + Secret routes: HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Content-Security-Policy.
filters: - type: ResponseHeaderModifier responseHeaderModifier: add: - Strict-Transport-Security: "max-age=63072000; includeSubDomains; preload" - X-Content-Type-Options: "nosniff" - X-Frame-Options: "DENY" - Referrer-Policy: "strict-origin-when-cross-origin" - Permissions-Policy: "geolocation=(), camera=(), microphone=()" - Content-Security-Policy: "default-src 'self'; …"
Coraza WAF · OWASP-style rules via EnvoyExtensionPolicy
Coraza is the OWASP-endorsed ModSecurity successor (Go-based, runs as a WASM filter inside Envoy). Six OWASP-CRS-flavoured rules block SQLi, XSS, path-traversal, command-injection, RFI, and known scanner User-Agents. Probes hit the SAME endpoint (/features/exact) with malicious payloads — the WAF returns 403 before the request reaches the backend.
apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyExtensionPolicy spec: targetRefs: - kind: HTTPRoute name: features wasm: - name: coraza code: type: Image image.url: ghcr.io/corazawaf/coraza-proxy-wasm:main config: directives_map: default: - "SecRuleEngine On" - "SecRule ARGS \"@detectSQLi\" id:1001,deny,status:403" - "SecRule ARGS \"@detectXSS\" id:1002,deny,status:403" - # ... + path-traversal, command-injection, RFI, scanner-UA
TCPRoute · raw L4 routing to a Redis backend
No HTTP, no hostname-matching — just port-based L4 forwarding. Gateway listener tcp-redis on port 6379, TCPRoute hands traffic to a Redis Pod (capped at 8 MB so demo-safe). Browser can't speak raw TCP; test from your laptop:
apiVersion: gateway.networking.k8s.io/v1alpha2 kind: TCPRoute metadata: name: redis namespace: demo spec: parentRefs: - name: eg sectionName: tcp-redis # Gateway listener :6379 rules: - backendRefs: - name: redis port: 6379 # TCPRoute has NO hostnames field — TCP carries no host identifier. # Routing is purely by listener-port.
GRPCRoute · gRPC routing through the Gateway
Separate Route kind for gRPC (HTTP/2 + protobuf). Attaches to a Gateway listener that has allowedRoutes.kinds: [GRPCRoute]. Live on grpc.wolfslight.cc with its own listener + cert. A SecurityPolicy.cors (cors-grpc) is attached to the GRPCRoute so the browser probe from gateway.wolfslight.cc passes the cross-origin preflight — same CRD as HTTPRoute CORS, kind-agnostic. Browser-side gRPC needs grpc-web; CLI test from your laptop:
apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: name: fortio namespace: demo spec: parentRefs: - name: eg sectionName: https-grpc hostnames: [ "grpc.wolfslight.cc" ] rules: - backendRefs: - name: fortio port: 8079 # fortio's gRPC port # Service port has appProtocol: kubernetes.io/h2c so Envoy uses HTTP/2 upstream
SecurityPolicy · Basic Auth gate to /secret
Envoy Gateway's SecurityPolicy CR attaches Basic Auth to an HTTPRoute. Demo credentials: test:test. Wrong/missing creds → 401; correct creds → a properly classified Resident-Evil-themed leak from inside the Raccoon Cluster.
apiVersion: gateway.envoyproxy.io/v1alpha1 kind: SecurityPolicy metadata: name: secret-basic-auth namespace: demo spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: secret # the route to protect basicAuth: users: name: secret-basic-auth # htpasswd Secret