Kong Operator only reconciles
TLSRouteresources using thegateway.networking.k8s.io/v1API, which is available in Gateway API 1.5 or later (standard channel). If you installed the CRDs from an earlier release while following step 1 of this series, upgrade Kong Operator to the version that supportsTLSRoute. It will install or upgrade gateway API CRDs with the appropriate version. If you did not install gateway API CRDs by the Kong Operator helm release, install or upgrade them manually:kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml --server-sideCopied!
Proxy TLS traffic by SNI using TLSRoute
Prerequisites
Series Prerequisites
This page is part of the Get started with Kong Operator and Gateway API series.
Complete the previous page, Configure route and service before completing this page.
Generate a TLS certificate
-
Create a test certificate for the
tls9443.kong.examplehostname. This will be used to secure TLS traffic.Older OpenSSL versions, including the version provided with macOS Monterey, require using the alternative version of this command.
-
Create a Secret containing the certificate:
kubectl create secret -n kong tls tls9443.kong.example --cert=./server.crt --key=./server.keyCopied!
Attach the TLS certificate to the echo Service
The echo Service we deployed in a previous step doesn’t listen on the TLS port by default as it requires a certificate stored in a Kubernetes Secret. Patch the echo Deployment to mount the Secret in the pod and set the TLS_CERT_FILE and TLS_KEY_FILE environment variables to allow the echo Service to terminate TLS:
kubectl patch -n kong --type=json deployment echo -p='[
{
"op":"add",
"path":"/spec/template/spec/containers/0/env/-",
"value":{
"name": "TLS_PORT",
"value": "1030"
}
},
{
"op":"add",
"path":"/spec/template/spec/containers/0/env/-",
"value":{
"name": "TLS_CERT_FILE",
"value": "/var/run/certs/tls.crt"
}
},
{
"op":"add",
"path":"/spec/template/spec/containers/0/env/-",
"value":{
"name": "TLS_KEY_FILE",
"value": "/var/run/certs/tls.key"
}
},
{
"op":"add",
"path":"/spec/template/spec/containers/0/volumeMounts",
"value":[{
"mountPath": "/var/run/certs",
"name": "secret-test",
"readOnly": true
}]
},
{
"op":"add",
"path":"/spec/template/spec/volumes",
"value":[{
"name": "secret-test",
"secret": {
"defaultMode": 420,
"secretName": "tls9443.kong.example"
}
}]
}
]'Route TCP traffic with TLS
Re-apply the kong Gateway with the additional stream9443 TLS listener in Passthrough mode:
echo 'apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: kong
namespace: kong
spec:
gatewayClassName: kong
listeners:
- name: http
protocol: HTTP
port: 80
- name: stream9443
port: 9443
protocol: TLS
hostname: tls9443.kong.example
allowedRoutes:
namespaces:
from: All
tls:
mode: Passthrough' | kubectl apply -f -Next, create a TLSRoute:
echo "apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: echo-tls
namespace: kong
spec:
parentRefs:
- name: kong
sectionName: stream9443
hostnames:
- tls9443.kong.example
rules:
- backendRefs:
- name: echo
port: 1030
" | kubectl apply -f -This configuration instructs Kong Gateway to forward all traffic it receives on port 9443 to the echo Service on port 1030.
Validate your configuration
Export the Gateway’s external address:
export PROXY_IP=$(kubectl get gateway kong -n kong -o jsonpath='{.status.addresses[0].value}')You can now access the echo Service on port 9443 with SNI tls9443.kong.example.
In real-world usage, you would create a DNS record for tls9443.kong.example pointing to your proxy Service’s public IP address, which causes TLS clients to add an SNI automatically. For this demo, add it manually using the OpenSSL CLI:
echo "hello" | openssl s_client -connect $PROXY_IP:9443 -servername tls9443.kong.example -quiet 2>/dev/nullThe results should look like this:
Welcome, you are connected to node kind-control-plane.
Running on Pod echo-5f44d4c6f9-krnhk.
In namespace default.
With IP address 10.244.0.26.
helloTerminate TLS at the listener
The previous sections used tls.mode: Passthrough, which forwards encrypted TLS bytes through Kong Gateway so the backend completes the handshake. Kong Operator also supports tls.mode: Terminate: Kong Gateway terminates the client’s TLS connection at the listener using a certificate you provide, then forwards plain TCP to the backend. Use this mode when you want Kong to apply plugins, observe traffic, or enforce TLS policy on the connection. The tradeoff is that the connection is no longer end-to-end encrypted.
The following sections walk through a second TLSRoute on a new listener (port 9444) so it coexists with the Passthrough example above.
Generate a TLS certificate for the Terminate listener
-
Create a test certificate for the
tls9444.kong.examplehostname. This will be used to secure TLS traffic.Older OpenSSL versions, including the version provided with macOS Monterey, require using the alternative version of this command.
-
Create a Secret containing the certificate:
kubectl create secret -n kong tls tls9444.kong.example --cert=./server.crt --key=./server.keyCopied!
Label the certificate Secret
Kong Operator only watches certificate Secrets that carry the konghq.com/secret="true" label. Add the label so Operator picks up the Secret you just created:
kubectl label secret tls9444.kong.example -n kong konghq.com/secret="true"For more information about how Kong Operator handles secrets, see the Secrets reference.
Add a Terminate TLS listener to the Gateway
Reapply the kong Gateway with a stream9444 TLS listener in Terminate mode, referencing the labeled Secret:
Warning: Applying this Gateway replaces the listener list. If you completed the Passthrough walkthrough above, the
stream9443listener will be removed and theecho-tlsTLSRoutewill no longer attach to a parent. Runkubectl delete tlsroute echo-tls -n kongto remove the leftover route if you only want the Terminate demo running.
echo 'apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: kong
namespace: kong
spec:
gatewayClassName: kong
listeners:
- name: http
protocol: HTTP
port: 80
- name: stream9444
port: 9444
protocol: TLS
hostname: tls9444.kong.example
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: tls9444.kong.example' | kubectl apply -f -Create a TLSRoute for the Terminate listener
Because Kong is now terminating TLS, the backend can receive plain TCP. Point the TLSRoute at the unmodified echo Service on its default plain TCP port 1025:
echo "apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: echo-tls-terminate
namespace: kong
spec:
parentRefs:
- name: kong
sectionName: stream9444
hostnames:
- tls9444.kong.example
rules:
- backendRefs:
- name: echo
port: 1025
" | kubectl apply -f -Validate the Terminate listener
Reuse the $PROXY_IP you exported earlier and connect to the new listener:
echo "hello" | openssl s_client -connect $PROXY_IP:9444 -servername tls9444.kong.example -quiet 2>/dev/nullYou should see similar output as previously shown in the example using Passthrough TLS mode.
Unlike the Passthrough case, the TLS handshake terminates at Kong Gateway: the certificate presented to the client is the one stored in the labeled Secret, not a certificate served by the echo backend. You can confirm this by dropping the -quiet flag and inspecting the subject= line in the openssl output — it should match CN=tls9444.kong.example.