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.

Before you begin

  1. Follow the Get started guide to install Gloo Gateway and deploy the httpbin sample app.

  2. Make sure that you have the OpenSSL version of openssl, not LibreSSL. The openssl version must be at least 1.1.

    1. Check your openssl version. If you see LibreSSL in the output, continue to the next step.
        openssl version
        
    2. Install the OpenSSL version (not LibreSSL). For example, you might use Homebrew.
        brew install openssl
        
    3. 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...

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.

  1. 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
      
  2. 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
      
  3. 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
      
  4. 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
      
  5. Store the nginx configuration in a configmap.

      kubectl create configmap nginx-configmap --from-file=nginx.conf=./nginx.conf
      
  6. 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
      
  7. 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.

  1. 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
      
  2. 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
      
  3. Create 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
      
  4. 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.

  1. 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
      
  2. 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.

  3. 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
      
  4. 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
      
  5. 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