This repository demonstrates how Cilium Service Mesh implements the Gateway API in a kind cluster. It provides a set of scenarios that exercise different configuration models so you can compare their behavior directly.
mise manages all other required tools (kind, helm, cilium-cli, hubble, kyverno) automatically.
Make sure to activate mise in your shell so the mise run ... tasks can load the right tools. Don’t skip this. Follow the official mise activate instructions for your shell:
After adding the activation line, restart your shell or open a new terminal.
When mise installs tools hosted on GitHub, unauthenticated requests can hit GitHub API rate limits. Create a personal access token (no scopes needed for public tools) and set it for this project with mise set --prompt. See the GitHub token creation guide or go directly to the token creation page:
- https://docs.github.com/articles/creating-an-oauth-token-for-command-line-use
- https://github.com/settings/tokens/new
Set the token interactively:
mise set --prompt GITHUB_TOKENAvoid setting the token using export GITHUB_TOKEN=token or mise set GITHUB_TOKEN as that stores the token the history of your shell.
mise run cluster:startThis creates a kind cluster and installs Cilium in kube-proxy-free mode with Hubble observability.
This is already done as part of mise run cluster:start. Instruction left here for reference.
mise run cluster:verifymise run scenario:01:start
mise run scenario:01:verifyThis deploys one gateway-system namespace with the Gateway, one client namespace with a netshoot-client pod, and two backend namespaces that both reuse the same backend-http app base:
| Pod | Namespace | Role |
|---|---|---|
netshoot-client |
client |
Interactive debug client |
api |
backend-a |
A httpbin container |
api |
backend-b |
A httpbin container |
Test the two HTTPRoutes from your machine:
curl -i -H 'Host: backend-a.example.test' http://localhost/headers
curl -i -H 'Host: backend-b.example.test' http://localhost/headersRead each scenario README for the scenario-specific test flow.
Scenarios use a numbered-tier system. The prefix tells you the category at a glance; the slug tells you the content.
| Range | Category | Rule |
|---|---|---|
01–09 |
Single protocol, single gateway | One route type, one gateway — vary the protocol or routing feature |
20–29 |
Multi-protocol, single gateway | Multiple route types on one gateway |
30–39 |
Multi-gateway | Topology is the variable — multiple gateways |
40–49 |
Policy & filters | Kyverno, rate limiting, auth — the protocol is incidental |
50+ |
Advanced topology | ClusterMesh, federation, cross-cluster |
Gap numbering leaves room for insertion without renaming existing scenarios.
| Scenario | Scope | Status |
|---|---|---|
01-http |
HTTPRoute, plaintext, one gateway, two backend namespaces | ✅ Done |
02-grpc |
GRPCRoute, TLS termination at gateway, two backend namespaces | ✅ Done |
03-https |
HTTPRoute over HTTPS, TLS termination at gateway, two backend namespaces | ✅ Done |
04-mtls |
TLSRoute passthrough, mTLS at backend, per-namespace PKI | ✅ Done |
05-tcp |
TCPRoute, no TLS | Planned |
06-http-header-routing |
HTTPRoute with header-based match rules | Planned |
07-http-canary |
HTTPRoute with weighted backendRefs for traffic splitting | Planned |
20-http-grpc |
HTTPS + gRPC on one gateway, separate ports, two namespaces | ✅ Done |
21-http-grpc-shared-port |
HTTPRoute + GRPCRoute on one HTTPS listener (same port, different hostnames) | ✅ Done |
22-http-grpc-allowed-routes |
HTTPS + gRPC on separate ports with per-listener allowedRoutes.kinds |
✅ Done |
23-http-grpc-shared-port-allowed-routes |
HTTPRoute + GRPCRoute on one HTTPS listener with multiple allowedRoutes.kinds (Cilium bug — only first kind honoured) |
|
24-http-grpc-same-hostname-split-ports |
HTTPRoute + GRPCRoute on same hostname, different ports (443 / 50051) — Cilium port-collision bug in route translation | |
30-multi-gateway-grpc |
Two gateways, each serving gRPC | Planned |
31-multi-gateway-multi-protocol |
Two gateways, mixed protocols | Planned |
40-kyverno-route-governance |
Mutating + validating policies for Gateway API route hygiene | Planned |
41-http-rate-limit |
HTTPRoute with Envoy rate-limit filter | Planned |
42-http-ext-auth |
HTTPRoute with OIDC / external authorization | Planned |
50-clustermesh-grpc |
Cross-cluster gRPC with Cilium ClusterMesh | Planned |
Demonstrates Kyverno mutating and validating policies that enforce Gateway API routing conventions across namespaces. Three policies work together:
-
Mutating policy — auto-inject
parentRefs: When a team creates an HTTPRoute or GRPCRoute with a label likegateway: shared(or a namespace label maps to a known gateway), amutatepolicy injects the correctparentRefsblock pointing to the shared Gateway ingateway-system. Teams never hard-code gateway names or namespaces in their route manifests. -
Validating policy — require hostname from namespace label: Each namespace carries a label like
routing.example.test/hostname: backend-a.example.test. Avalidatepolicy requires that every route'shostnameslist includes at least one hostname that matches the value derived from this namespace label. This prevents teams from accidentally routing under a hostname that belongs to another namespace. -
Validating policy — forbid wildcard hostnames: A
validatepolicy rejects any route whosehostnameslist contains a bare wildcard entry (*or*.example.test). This prevents a single namespace from accidentally capturing all traffic on the listener.
The verify task deploys conforming routes (pass), then attempts non-conforming routes (blocked by policy) to prove all three policies are enforced.
apps/contains reusable, namespace-agnostic app bases.scenarios/contains namespaces, app instances, and Gateway API resources.- App-base conventions live in
apps/README.md.
TLS-focused scenarios use cert-manager, but it is intentionally not part of mise run cluster:start.
Install it only when a scenario needs certificates:
mise run cert-manager:install
mise run cert-manager:verifyThe self-signed certificate pattern for this repo lives in docs/tls-selfsigned.md.
Gateway API CRDs are installed by the repo tasks before Cilium is installed. This repo now uses the Gateway API experimental CRD bundle at v1.5.0, because current Cilium Gateway behavior can log v1alpha2.TLSRouteList registration errors when only the standard bundle is installed.
For local TLS and gRPC checks in this repo, use insecure client flags against the self-signed certificates:
curl -k https://...
grpcurl -insecure ...Kyverno is also optional and is intentionally not part of mise run cluster:start because no current scenario depends on it yet.
Install it only when a scenario or experiment needs policy enforcement:
mise run kyverno:install
mise run kyverno:verify
mise run kyverno:deleteOpen the Hubble UI to watch network flows in real time as you run each scenario:
cilium hubble uiOr observe from the command line:
cilium hubble port-forward &
hubble observe --namespace client --follow
hubble observe --namespace backend-a --follow
hubble observe --namespace backend-b --followk9s is a terminal UI for browsing and managing Kubernetes resources. Start it with:
k9sBasic navigation:
- Use
:to open the command bar, then type a resource (for example,pods,ns,deploy) and press Enter. - Use
j/k(or arrow keys) to move,Enterto drill in, andEscto go back. - Press
/to filter the current list.
mise run scenario:01:delete
mise run cluster:delete