Skip to content
If you are interested in trying out Gloo Gateway with the Kubernetes Gateway API, check out Solo Enterprise for kgateway. This version adds enterprise functionality on top of the kgateway open source project.

TLS passthrough

Page as Markdown

Set up a TLS listener on the Gateway that serves one or more hosts and passes TLS traffic through to a destination. Because TLS traffic is not terminated at the Gateway, the destination must be capable of handling incoming TLS traffic.

Before you begin

  1. Follow the Get started guide to install Gloo Gateway.

  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...
  3. Decide whether to set up an HTTP listener inline on the Gateway resource or as a separate ListenerSet resource. Note that ListenerSets are an experimental feature in the upstream Kubernetes Gateway API project, and subject to change. For more information, see the Listener overview.

Deploy an nginx server that is configured for HTTPS traffic

Deploy a sample nginx server and configure the server for HTTPS traffic.

  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 nginx.example.com domain.

    openssl req -out example_certs/nginx.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs/nginx.example.com.key -subj "/CN=nginx.example.com/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/nginx.example.com.csr -out example_certs/nginx.example.com.crt
  3. Create a secret that stores the certificate and key for the nginx server.

    kubectl create secret tls nginx-server-certs \
     --key example_certs/nginx.example.com.key \
     --cert example_certs/nginx.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 nginx.example.com;
        ssl_certificate /etc/nginx-server-certs/tls.crt;
        ssl_certificate_key /etc/nginx-server-certs/tls.key;
      }
    }
    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
          volumes:
          - name: nginx-config
            configMap:
              name: nginx-configmap
          - name: nginx-server-certs
            secret:
              secretName: nginx-server-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 TLS passthrough

To route TLS traffic to the nginx server directly without terminating the TLS connection at the Gateway, you create a Gateway and configure it for TLS passthrough. Then, you create a TLSRoute that represents the route to your nginx server and attach it to the Gateway.

  1. Install the experimental channel of the Kubernetes Gateway API so that you can use TLSRoutes.

    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml
  2. Create a Gateway that passes through incoming TLS requests for the nginx.example.com domain.

    kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: tls-passthrough
      namespace: gloo-system
      labels:
        gateway: tls-passthrough
    spec:
      gatewayClassName: gloo-gateway
      listeners:
      - name: tls
        protocol: TLS
        hostname: "nginx.example.com"
        tls:
          mode: Passthrough
        port: 8443
        allowedRoutes:
          namespaces:
            from: All
    EOF

    Review the following table to understand this configuration.

    SettingDescription
    spec.gatewayClassNameThe name of the Kubernetes gateway class that you want to use to configure the gateway. When you set up Gloo Gateway, a default gateway class is set up for you. To view the gateway class configuration, see Gateway classes and types.
    spec.listenersConfigure the listeners for this gateway. In this example, you configure a TLS listener in passthrough mode that listens for incoming traffic on port 8443.
    spec.listeners.tls.modeThe TLS mode that you want to use for incoming requests. In passthrough mode, the gateway forwards the encrypted TLS traffic directly to the backend service without terminating the TLS connection, allowing the backend service to handle decryption and certificate management.
    1. Create a Gateway that enables the attachment of ListenerSets.

      kubectl apply -f- <<EOF
      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
        name: tls-passthrough
        namespace: gloo-system
        labels:
          gateway: tls-passthrough
      spec:
        gatewayClassName: gloo-gateway
        allowedListeners:
          namespaces:
            from: All
        listeners:
        - protocol: HTTP
          port: 80
          name: http
          allowedRoutes:
            namespaces:
              from: All     
      EOF

      Review the following table to understand this configuration.

      SettingDescription
      spec.gatewayClassNameThe name of the Kubernetes gateway class that you want to use to configure the gateway. When you set up Gloo Gateway, a default gateway class is set up for you. To view the gateway class configuration, see Gateway classes and types.
      spec.allowedListenersEnable 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 to Selector.
      spec.listenersOptionally, 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 “dummy” listener. This dummy listener cannot conflict with the listener that you configure in the ListenerSet, such as using the same port or name. In this example, the dummy listener is configured on HTTP port 80, which differs from TLS port 8443 in the ListenerSet that you create later.
    2. Create a ListenerSet that configures a TLS listener for the Gateway.

      kubectl apply -f- <<EOF
      apiVersion: gateway.networking.x-k8s.io/v1alpha1
      kind: XListenerSet
      metadata:
        name: tls-listenerset
        namespace: gloo-system
        labels:
          gateway: tls-passthrough
      spec:
        parentRef:
          name: tls-passthrough
          namespace: gloo-system
          kind: Gateway
          group: gateway.networking.k8s.io
        listeners:
        - name: tls
          protocol: TLS
          hostname: "nginx.example.com"
          tls:
            mode: Passthrough
          port: 8443
          allowedRoutes:
            namespaces:
              from: All
      EOF

      Review the following table to understand this configuration.

      SettingDescription
      spec.parentRefThe name of the Gateway to attach the ListenerSet to.
      spec.listenersConfigure the listeners for this gateway. In this example, you configure a TLS listener in passthrough mode that listens for incoming traffic on port 8443.
      spec.listeners.tls.modeThe TLS mode that you want to use for incoming requests. In passthrough mode, the gateway forwards the encrypted TLS traffic directly to the backend service without terminating the TLS connection, allowing the backend service to handle decryption and certificate management.
  3. Create a TLSRoute resource that forwards incoming TLS traffic to the nginx server.

    kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1alpha2
    kind: TLSRoute
    metadata:
      name: tlsroute
      namespace: default
      labels:
        example: tlsroute
        gateway: tls-passthrough
    spec:
      parentRefs:
        - name: tls-passthrough
          namespace: gloo-system
      rules:
        - backendRefs:
            - group: ""
              kind: Service
              name: my-nginx
              port: 443
    EOF
    kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1alpha2
    kind: TLSRoute
    metadata:
      name: tlsroute
      namespace: default
      labels:
        example: tlsroute
        gateway: tls-passthrough
    spec:
      parentRefs:
        - name: tls-listenerset
          namespace: gloo-system
          kind: XListenerSet
          group: gateway.networking.x-k8s.io
      rules:
        - backendRefs:
            - group: ""
              kind: Service
              name: my-nginx
              port: 443
    EOF
  4. Verify TLS passthrough traffic for nginx.

    1. Get the external address of the gateway proxy and save it in an environment variable.external address of the gateway proxy and save it in an environment variable.

      export INGRESS_GW_ADDRESS=$(kubectl get svc -n gloo-system gloo-proxy-tls-passthrough -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
      echo $INGRESS_GW_ADDRESS  
    2. Send a request to the nginx.example.com domain and verify that you get back a 200 HTTP response code from your nginx server. Because nginx accepts incoming TLS traffic only, the 200 HTTP response code proves that TLS traffic was not terminated at the Gateway. In addition, you can verify that you get back the server certificate that you configured your nginx server with in the beginning.

      • Load balancer IP:

        curl -vik --resolve "nginx.example.com:8443:${INGRESS_GW_ADDRESS}" --cacert example_certs/example.com.crt https://nginx.example.com:8443/
      • Load balancer hostname:

        curl -vik --resolve "nginx.example.com:8443:$(dig +short $INGRESS_GW_ADDRESS | head -n1)" --cacert example_certs/example.com.crt https://nginx.example.com:8443/

      Example output:

      * Request completely sent off
      < HTTP/1.1 200 OK
      HTTP/1.1 200 OK
      < Server: nginx/1.27.4
      Server: nginx/1.27.4
      ...
      < 
      
      <!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>
      * Connection #0 to host nginx.example.com left intact
      
    1. Port-forward the tls-passthrough gateway proxy pod on port 8443.

      kubectl port-forward deployment/gloo-proxy-tls-passthrough -n gloo-system 8443:8443
    2. Send a request to the nginx.example.com domain and verify that you get back a 200 HTTP response code from your nginx server. Because nginx accepts incoming TLS traffic only, the 200 HTTP response code proves that TLS traffic was not terminated at the Gateway. In addition, you can verify that you get back the server certificate that you configured your nginx server with in the beginning.

      curl -vi --cacert example_certs/example.com.crt --resolve "nginx.example.com:8443:127.0.0.1" https://nginx.example.com:8443

      Example output:

      * Request completely sent off
      < HTTP/1.1 200 OK
      HTTP/1.1 200 OK
      < Server: nginx/1.27.4
      Server: nginx/1.27.4
      ...
      < 
      
      <!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>
      * Connection #0 to host nginx.example.com left intact
      

Cleanup

You can optionally remove the resources that you set up as part of this guide.
  1. Remove the routing resources for the TLS route.

    kubectl delete tlsroute,gateway -A -l gateway=tls-passthrough
    kubectl delete tlsroute,xlistenerset,gateway -A -l gateway=tls-passthrough
  2. Remove the example_certs directory that stores your TLS credentials.

    rm -rf example_certs
  3. Delete the nginx server.

    rm nginx.conf
    kubectl delete configmap nginx-configmap
    kubectl delete deployment my-nginx
    kubectl delete service my-nginx
    kubectl delete secret nginx-server-certs