This episode covers how to store TLS certificates in a Kubernetes secret, configure HTTPS termination on the Gateway, and use TLS passthrough and SNI control for scenarios that require end-to-end encryption.

Plain HTTP traffic can be read by anyone on the network. In production, almost all inbound traffic must be encrypted. Episode 5 covers TLS & HTTPS termination in Multigress: storing certificates as a Kubernetes secret, using an HTTPS listener on the Gateway, and understanding when to use passthrough mode with SNI control.
There are two important modes you must understand: termination, where the gateway decrypts traffic and sends plaintext to the backend, and passthrough, where the gateway forwards the encrypted connection without opening it. Both are used in different scenarios.
For practice, create a self-signed certificate with openssl:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=api.example.com" \
-addext "subjectAltName=DNS:api.example.com"The command above produces tls.key and tls.crt for the domain api.example.com. In production, replace them with certificates from a trusted CA like Let's Encrypt.
The Gateway API only accepts secrets of type kubernetes.io/tls. Create and verify one:
kubectl create secret tls api-tls \
--key tls.key --cert tls.crt \
--namespace multigress-system
kubectl get secret api-tls -n multigress-systemThe api-tls secret stores tls.crt and tls.key as data keys. The kubectl get secret api-tls -n multigress-system command is best run with the -o yaml flag to confirm the data structure, even though the values are base64-encoded.
Warning
The Gateway and the TLS secret must be in the same namespace as the Gateway, not the application namespace. HTTPRoute lives in the application namespace, but the certificate belongs to the Gateway's listener.
Now declare an HTTPS listener that references the secret:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: main-gateway
namespace: multigress-system
spec:
gatewayClassName: multigress
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
certificateRefs:
- name: api-tls
kind: SecretNotice the tls.certificateRefs section: this connects the HTTPS listener to the secret. The hostname field is optional — if set, the listener only serves matching hostnames.
Apply and test:
kubectl apply -f gateway.yaml
curl -k https://localhost:8443/v1 -H "Host: api.example.com"Use the -k flag because the certificate is self-signed. If a response appears, the gateway has terminated TLS and forwarded the request to the backend. Also check the listener status:
kubectl describe gateway main-gateway -n multigress-systemIn the Status section, the Accepted: True and Ready: True conditions should appear for the HTTPS listener. Common errors like a missing secret will be recorded in the ResolvedRefs condition.
There are scenarios where the gateway must not open traffic: backends that handle their own certificates, such as legacy applications or regulations that require end-to-end encryption. This is where passthrough is used. Multigress only forwards the encrypted bytes and routes based on SNI (Server Name Indication) — the domain name the client sends during the handshake.
Passthrough is declared with a TLSRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: legacy-tls-route
spec:
parentRefs:
- name: main-gateway
namespace: multigress-system
hostnames:
- "legacy.example.com"
rules:
- backendRefs:
- name: legacy-app
port: 443TLSRoute has no concept of path because the connection isn't decrypted — routing decisions are purely based on SNI. The legacy-app backend must support TLS itself.
| Aspect | Termination | Passthrough |
|---|---|---|
| Certificate at the gateway | Yes | No |
| Path-based routing | Yes | No, SNI only |
| Encryption to backend | Can be plaintext | Always encrypted |
| Example use cases | Modern applications | Legacy apps, regulations |
Rule of thumb: use termination for almost all cases, and keep passthrough for scenarios that truly require it.
Episode 5 secured your inbound traffic path: storing certificates as secrets, configuring an HTTPS listener with certificateRefs, and choosing between termination or passthrough based on backend needs.
The key takeaways:
kubernetes.io/tls and lives in the Gateway namespace.tls.certificateRefs.Accepted for validity, ResolvedRefs for secret references.In the next episode 6 we'll manage traffic policy & load balancing — traffic splitting and weights, retries, timeouts, circuit breakers, request mirroring, and load balancing behavior between backend services. Your HTTPS gateway will become the laboratory for all these experiments.