Upstream TLS
Originate a TLS connection from the gateway proxy to your upstream service.
About this guide
In this guide, you learn how to set up an HTTPS Gateway that terminates incoming HTTPS connections and originates a new one-way or mutual TLS connection to the nginx upstream service. Nginx is configured to only accept incoming TLS connections.
Looking for instructions for how to pass through TLS connections to an upstream servicewithout terminating them at the Gateway? See the TLS passthrough guide for more information.
Before you begin
Follow the Get started guide to install Gloo Gateway and deploy the httpbin sample app.
Make sure that you have the OpenSSL version of openssl, not LibreSSL. The openssl version must be at least 1.1.
- Check your
openssl
version. 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,
- Check your
Deploy an nginx server that is configured for HTTPS traffic
Deploy a sample nginx server and configure the server for HTTPS traffic. To secure the nginx server, you use self-signed TLS certificates.
Self-signed certificates are used for demonstration purposes. Do not use self-signed certificates in production environments. Instead, use certificates that are issued from a trust Certificate Authority.
Create a root certificate for the
example.com
domain. You use this certificate to sign the certificate for your nginx service later.mkdir example_certs openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs/example.com.key -out example_certs/example.com.crt
Create a server certificate and private key for the
my-nginx.default.svc.cluster.local
domain.openssl req -out example_certs/my-nginx.default.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout example_certs/my-nginx.default.svc.cluster.local.key -subj "/CN=my-nginx.default.svc.cluster.local/O=some organization" openssl x509 -req -sha256 -days 365 -CA example_certs/example.com.crt -CAkey example_certs/example.com.key -set_serial 0 -in example_certs/my-nginx.default.svc.cluster.local.csr -out example_certs/my-nginx.default.svc.cluster.local.crt
Create a secret that stores the server and CA certificate that you created.
kubectl create -n default secret tls nginx-server-certs \ --key example_certs/my-nginx.default.svc.cluster.local.key \ --cert example_certs/my-nginx.default.svc.cluster.local.crt kubectl create -n default secret generic nginx-ca-certs \ --from-file=example_certs/example.com.crt
Prepare your nginx configuration. The following example configures nginx for HTTPS traffic with the certificate that you created earlier.
cat <<EOF > ./nginx.conf events { } http { log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log; server { listen 443 ssl; root /usr/share/nginx/html; index index.html; server_name my-nginx.nginx.svc.cluster.local; ssl_certificate /etc/nginx-server-certs/tls.crt; ssl_certificate_key /etc/nginx-server-certs/tls.key; ssl_client_certificate /etc/nginx-ca-certs/example.com.crt; ssl_verify_client on; } } EOF
Store the nginx configuration in a configmap.
kubectl create configmap nginx-configmap --from-file=nginx.conf=./nginx.conf
Deploy the nginx server.
kubectl apply -f- <<EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 443 protocol: TCP selector: run: my-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 443 volumeMounts: - name: nginx-config mountPath: /etc/nginx readOnly: true - name: nginx-server-certs mountPath: /etc/nginx-server-certs readOnly: true - name: nginx-ca-certs mountPath: /etc/nginx-ca-certs readOnly: true volumes: - name: nginx-config configMap: name: nginx-configmap - name: nginx-server-certs secret: secretName: nginx-server-certs - name: nginx-ca-certs secret: secretName: nginx-ca-certs EOF
Verify that the server is up and running.
kubectl get pods | grep nginx
Example output:
my-nginx-c4c49df8f-2bkws 1/1 Running 0 34s
Set up your gateway
Set up an HTTPS Gateway that terminates incoming TLS traffic on the gateway. To originate a new TLS connection to the nginx server backend, you later create an Upstream resource that is configured with the TLS credentials that you want to use during the connection.
Create a gateway certificate. You use this certificate to secure the HTTPS listener on the gateway and to terminate incoming TLS connections.
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/example.com.crt -CAkey example_certs/example.com.key -set_serial 0 -in example_certs/gateway.csr -out example_certs/gateway.crt
Create a Kubernetes secret to store your gateway TLS certificate. You create the secret in the same cluster and namespace that the gateway is deployed to.
kubectl create secret tls -n gloo-system https \ --key example_certs/gateway.key \ --cert example_certs/gateway.crt
Note that in this example, the secret does not include the root CA certificate. Adding a root CA certificate automatically instructs Gloo Gateway to establish a mutual TLS connection to the downstream application. If you want to set up an mTLS Gateway instead of an HTTPS Gateway, include the root CA certificate For an example, see the mTLS listenener guideCreate a Gateway resource and configure an HTTPS listener. In this example, the Gateway terminates incoming TLS traffic on the Gateway by using the TLS credentials that you just created.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: https namespace: gloo-system labels: gateway: https spec: gatewayClassName: gloo-gateway listeners: - name: https port: 443 protocol: HTTPS hostname: https.example.com tls: mode: Terminate certificateRefs: - name: https kind: Secret allowedRoutes: namespaces: from: All EOF
Get the external address of the gateway and save it in an environment variable. Note that it might take a few seconds for the gateway address to become available.
Set up Upstream TLS
Set up Upstream and HTTPRoute resources that are configured with the credentials that you want to use when originating a new TLS connection from the gateway to the nginx server backend.
Create a client certificate and private key. You use these credentials to originate a new TLS connection from the gateway to the nginx server.
openssl req -out example_certs/client.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs/client.example.com.key -subj "/CN=client.example.com/O=client organization" openssl x509 -req -sha256 -days 365 -CA example_certs/example.com.crt -CAkey example_certs/example.com.key -set_serial 1 -in example_certs/client.example.com.csr -out example_certs/client.example.com.crt
Create a Kubernetes secret for the client credentials. The steps vary depending on whether you want to use one-way or mutual TLS when connecting to your upstream service.
Create an Upstream for the nginx server. The Upstream is configured with the client credentials that you created in the previous step. Gloo Gateway uses these client credentials when originating a new TLS connection to the nginx upstream.
kubectl apply -f- <<EOF apiVersion: gloo.solo.io/v1 kind: Upstream metadata: name: nginx namespace: gloo-system spec: kube: serviceName: my-nginx serviceNamespace: default servicePort: 443 sslConfig: secretRef: name: client-credential namespace: gloo-system EOF
Create an HTTPRoute that routes incoming traffic to the nginx Upstream.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: nginx-https namespace: gloo-system spec: parentRefs: - name: https namespace: gloo-system rules: - backendRefs: - name: nginx kind: Upstream group: gloo.solo.io EOF
Send a request to the nginx upstream. Verify that traffic is terminated at the gateway and a new TLS connection is established to the nginx upstream. A 200 HTTP response code verifies that a TLS connection reached the nginx upstream service.
Example output:
* Added https.example.com:443:3.12.18.206 to DNS cache * Hostname https.example.com was found in DNS cache * Trying 3.12.18.206:443... * Connected to https.example.com (3.12.18.206) port 443 * ALPN: curl offers h2,http/1.1 * (304) (OUT), TLS handshake, Client hello (1): * (304) (IN), TLS handshake, Server hello (2): * (304) (IN), TLS handshake, Unknown (8): * (304) (IN), TLS handshake, Certificate (11): * (304) (IN), TLS handshake, CERT verify (15): * (304) (IN), TLS handshake, Finished (20): * (304) (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 / [blank] / UNDEF * ALPN: server accepted h2 * Server certificate: * subject: CN=*; O=any domain * start date: Apr 30 19:20:03 2025 GMT * expire date: Apr 30 19:20:03 2026 GMT * issuer: O=any domain; CN=* * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. * using HTTP/2 * [HTTP/2] [1] OPENED stream for https://https.example.com:443/ * [HTTP/2] [1] [:method: GET] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: https.example.com] * [HTTP/2] [1] [:path: /] * [HTTP/2] [1] [user-agent: curl/8.7.1] * [HTTP/2] [1] [accept: */*] > GET / HTTP/2 > Host: https.example.com > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/2 200 HTTP/2 200 < server: envoy ... <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Cleanup
You can optionally remove the resources that you set up as part of this guide.
kubectl delete upstream nginx -n gloo-system
kubectl delete httproute nginx-https -n gloo-system
kubectl delete secret client-credential -n gloo-system
kubectl delete gateway https -n gloo-system
kubectl delete secret https -n gloo-system
kubectl delete deployment my-nginx
kubectl delete service my-nginx
kubectl delete secret nginx-server-certs
kubectl delete secret nginx-ca-certs
kubectl delete configmap nginx-configmap
rm -rf example_certs