HTTPS
Create an HTTPS listener on your API gateway. Then, your API gateway listens for secured HTTPS traffic on the specified port and hostname that you configure.
Before you begin
-
Set up kgateway by following the Quick start or Installation guides.
-
Make sure that you have the OpenSSL version of
openssl
, not LibreSSL. Theopenssl
version must be at least 1.1.-
Check the
openssl
version that is installed. If you see LibreSSL in the output, continue to the next step.openssl version
-
Install the OpenSSL version (not LibreSSL). For example, you might use Homebrew.
brew install openssl
-
Review the output of the OpenSSL installation for the path of the binary file. You can choose to export the binary to your path, or call the entire path whenever the following steps use an openssl command.
- For example, openssl might be installed along the following path:
/usr/local/opt/openssl@3/bin/
- To run commands, you can append the path so that your terminal uses this installed version of OpenSSL, and not the default LibreSSL.
/usr/local/opt/openssl@3/bin/openssl req -new -newkey rsa:4096 -x509 -sha256 -days 3650...
- For example, openssl might be installed along the following path:
-
-
Decide whether to set up a listener inline on the Gateway resource or as a separate ListenerSet resource. For more information, see the Listener overview.
ListenerSets: This feature is available in kgateway version 2.1.x or later. Also, you must install the experimental channel of the Kubernetes Gateway API at version 1.3 or later.
Create a TLS certificate
-
Create a directory to store your TLS credentials in.
mkdir example_certs
-
Create a self-signed root certificate. The following command creates a root certificate that is valid for a year and can serve any hostname. You use this certificate to sign the server certificate for the gateway later. For other command options, see the OpenSSL docs.
# root cert openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=any domain/CN=*' -keyout example_certs/root.key -out example_certs/root.crt
-
Use the root certificate to sign the gateway certificate.
openssl req -out example_certs/gateway.csr -newkey rsa:2048 -nodes -keyout example_certs/gateway.key -subj "/CN=*/O=any domain" openssl x509 -req -sha256 -days 365 -CA example_certs/root.crt -CAkey example_certs/root.key -set_serial 0 -in example_certs/gateway.csr -out example_certs/gateway.crt
-
Create a Kubernetes secret to store your server TLS certificate. You create the secret in the same cluster and namespace that the gateway is deployed to.
kubectl create secret tls -n kgateway-system https \ --key example_certs/gateway.key \ --cert example_certs/gateway.crt kubectl label secret https gateway=https --namespace kgateway-system
Set up an HTTPS listener
Set up an HTTPS listener on your Gateway.
If you plan to set up your listener as part of a ListenerSet, keep the following considerations in mind. For more information, see ListenerSets (experimental).
- This feature is available in kgateway version 2.1.x or later.
- You must install the experimental channel of the Kubernetes Gateway API at version 1.3 or later.
-
Create a gateway resource with an HTTPS listener.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: https namespace: kgateway-system labels: example: httpbin-https spec: gatewayClassName: kgateway listeners: - protocol: HTTPS port: 443 hostname: https.example.com name: https tls: mode: Terminate certificateRefs: - name: https kind: Secret allowedRoutes: namespaces: from: All EOF
Review the following table to understand this configuration.
Setting Description spec.gatewayClassName
The name of the Kubernetes GatewayClass that you want to use to configure the Gateway. When you set up kgateway, a default GatewayClass is set up for you. spec.listeners
Configure the listeners for this Gateway. In this example, you configure an HTTPS Gateway that listens for incoming traffic for the https.example.com
domain on port 443. The Gateway can serve HTTP routes from any namespace.spec.listeners.tls.mode
The TLS mode that you want to use for incoming requests. In this example, HTTPS requests are terminated at the Gateway and the unencrypted request is forwarded to the service in the cluster. spec.listeners.tls.certificateRefs
The Kubernetes secret that holds the TLS certificate and key for the Gateway. The Gateway uses these credentials to establish the TLS connection with a client, and to decrypt incoming HTTPS requests. -
Create a Gateway that enables the attachment of ListenerSets.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: https namespace: kgateway-system labels: example: httpbin-https spec: gatewayClassName: kgateway allowedListeners: namespaces: from: All listeners: - protocol: HTTPS port: 80 name: https allowedRoutes: namespaces: from: All EOF
Review the following table to understand this configuration.
Setting Description spec.gatewayClassName
The name of the Kubernetes GatewayClass that you want to use to configure the Gateway. When you set up kgateway, a default GatewayClass is set up for you. spec.allowedListeners
Enable the attachment of ListenerSets to this Gateway. The example allows listeners from any namespace, which is helpful in multitenant environments. You can also limit the allowed listeners. To limit to listeners in the same namespace as the Gateway, set this value to Same
. To limit to listeners with a particular label, set this value toSelector
.spec.listeners
Optionally, you can configure a listener that is specific to the Gateway. Note that due to a Gateway API limitation, you must configure at least one listener on the Gateway resource, even if the listener is not used and is a generic, “dummy” listener. This generic listener cannot conflict with the listener that you configure in the ListenerSet, such as using the same port or name. In this example, the generic listener is configured on port 80, which differs from port 443 in the ListenerSet that you create later. -
Create a ListenerSet that configures an HTTPS listener for the Gateway.
kubectl apply -f- <<EOF apiVersion: gateway.networking.x-k8s.io/v1alpha1 kind: XListenerSet metadata: name: my-https-listenerset namespace: kgateway-system labels: example: httpbin-https spec: parentRef: name: https namespace: kgateway-system kind: Gateway group: gateway.networking.k8s.io listeners: - protocol: HTTPS port: 443 hostname: https.example.com name: https-listener-set tls: mode: Terminate certificateRefs: - name: https kind: Secret allowedRoutes: namespaces: from: All EOF
Review the following table to understand this configuration.
Setting Description spec.parentRef
The name of the Gateway to attach the ListenerSet to. spec.listeners
Configure the listeners for this ListenerSet. In this example, you configure an HTTPS gateway that listens for incoming traffic for the https.example.com
domain on port 443. The gateway can serve HTTP routes from any namespace.spec.listeners.tls.mode
The TLS mode that you want to use for incoming requests. In this example, HTTPS requests are terminated at the gateway and the unencrypted request is forwarded to the service in the cluster. spec.listeners.tls.certificateRefs
The Kubernetes secret that holds the TLS certificate and key for the gateway. The gateway uses these credentials to establish the TLS connection with a client, and to decrypt incoming HTTPS requests.
-
-
Check the status of the Gateway to make sure that your configuration is accepted. Note that in the output, a
NoConflicts
status ofFalse
indicates that the Gateway is accepted and does not conflict with other Gateway configuration.kubectl get gateway https -n kgateway-system -o yaml
-
Create an HTTPRoute resource for the httpbin app that is served by the gateway or ListenerSet that you created.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-https namespace: httpbin labels: example: httpbin-https spec: parentRefs: - name: https namespace: kgateway-system rules: - backendRefs: - name: httpbin port: 8000 EOF
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-https namespace: httpbin labels: example: httpbin-https spec: parentRefs: - name: my-https-listenerset namespace: kgateway-system kind: XListenerSet group: gateway.networking.x-k8s.io rules: - backendRefs: - name: httpbin port: 8000 EOF
-
Verify that the HTTPRoute is applied successfully.
kubectl get httproute/httpbin-https -n httpbin -o yaml
Example output: Notice in the
status
section that the parentRef is either the Gateway or the ListenerSet, depending on how you attached the HTTPRoute.... status: parents: - conditions: - lastTransitionTime: "2025-04-29T20:48:51Z" message: "" observedGeneration: 3 reason: Accepted status: "True" type: Accepted - lastTransitionTime: "2025-04-29T20:48:51Z" message: "" observedGeneration: 3 reason: ResolvedRefs status: "True" type: ResolvedRefs controllerName: kgateway.dev/kgateway parentRef: group: gateway.networking.k8s.io kind: Gateway name: https namespace: kgateway-system
-
Verify that the listener now has a route attached.
kubectl get gateway -n kgateway-system https -o yaml
Example output:
... listeners: - attachedRoutes: 1
kubectl get xlistenerset -n kgateway-system my-https-listenerset -o yaml
Example output:
... listeners: - attachedRoutes: 1
Note that because the HTTPRoute is attached to the ListenerSet, the Gateway does not show the route in its status.
kubectl get gateway -n kgateway-system https -o yaml
Example output:
... listeners: - attachedRoutes: 0
If you create another HTTPRoute that attaches to the Gateway and uses the same listener as the ListenerSet, then the route is reported in the status of both the Gateway (attachedRoutes: 1) and the ListenerSet (attachedRoutes: 2).
-
Get the external address of the gateway and save it in an environment variable.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system https -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESS
kubectl port-forward svc/https -n kgateway-system 8443:443
-
Send a request to the httpbin app and verify that you see the TLS handshake and you get back a 200 HTTP response code.
curl -vik --resolve "https.example.com:443:${INGRESS_GW_ADDRESS}" https://https.example.com:443/status/200
curl -vik --connect-to https.example.com:443:localhost:8443 https://https.example.com:443/status/200
Example output:
* ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem * CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 * Server certificate: * subject: CN=*; O=gateway * start date: Nov 5 01:54:04 2023 GMT * expire date: Nov 2 01:54:04 2033 GMT * issuer: CN=*; O=root * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x15200e800) > GET /status/200 HTTP/2 > Host: https.example.com > user-agent: curl/7.77.0 > accept: */* > * Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)! < HTTP/2 200 HTTP/2 200 ...
Cleanup
You can remove the resources that you created in this guide.kubectl delete -A gateways,httproutes,secret -l example=httpbin-https
rm -rf example_certs
kubectl delete -A gateways,httproutes,xlistenersets,secret -l example=httpbin-https
rm -rf example_certs