TLS passthrough

Available since MKE 3.7.0

TLS passthrough is the action of passing data through a load balancer to a server without decrypting it. Usually, the decryption or TLS termination happens at the load balancer and data is passed along to a web server as plain HTTP. TLS passthrough, however, keeps the data encrypted as it travels through the load balancer, with the web server performing the decryption upon receipt. With TLS passthrough enabled in NGINX Ingress Controller, the request will be forwarded to the backend service without being decrypted.

Note

Prior to setting up TLS termination, verify that you have correctly configured kubectl.

  1. Enable TLS passthrough using either the MKE web UI or the MKE configuration file.

    Note

    You must have MKE admin access to enable TLS passthrough.

    • To enable TLS passthrough with the MKE web UI, navigate to <username> > Admin Settings > Ingress, scroll down to Advanced Settings and toggle the Enable TLS-Passthrough control on.

    • To enable TLS passthrough using the MKE configuration file, set the ingress_extra_args.enable_ssl_passthrough file parameter under the cluster_config.ingress_controller option to true.

      [cluster_config.ingress_controller.ingress_extra_args]
           http_port = 80
           https_port = 443
           enable_ssl_passthrough = true
           default_ssl_certificate = ""
      
  2. Generate a self-signed certificate and a private key for the TLS connection.

    Note

    The Common Name (CN) in the certificate must match the host name of the server.

    mkdir -p example_certs
    
    openssl req \
      -new \
      -newkey rsa:2048 \
      -x509 \
      -sha256 \
      -days 365 \
      -nodes \
      -subj "/O=Example Inc./CN=nginx.example.com" \
      -keyout example_certs/nginx.example.com.key \
      -out example_certs/nginx.example.com.crt
    
  3. Create Kubernetes Secrets for the generated certificate:

    kubectl create secret tls nginx-server-certs \
      --key example_certs/nginx.example.com.key \
      --cert example_certs/nginx.example.com.crt
    
  4. Deploy a web server.

    1. Create a Kubernetes ConfigMap to retain the configuration of the NGINX server:

      cat <<EOF | kubectl apply -f -
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: nginx-conf
      data:
        nginx.conf: |
          events {
          }
          http {
            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
      
    2. Deploy the NGINX server:

      cat <<EOF | kubectl apply -f -
      apiVersion: v1
      kind: Service
      metadata:
        name: my-nginx
        labels:
          app: my-nginx
      spec:
        ports:
        - port: 443
          protocol: TCP
        selector:
          app: my-nginx
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: my-nginx
      spec:
        selector:
          matchLabels:
            app: my-nginx
        replicas: 1
        template:
          metadata:
            labels:
              app: 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 > nginx-conf
            - name: nginx-server-certs
              secret:
                secretName: nginx-server-certs
      EOF
      
  5. Configure Ingress.

    Create a Kubernetes Ingress with the annotation: nginx.ingress.kubernetes.io/ssl-passthrough: "true":

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/ssl-passthrough: "true"
      name: nginx-test
    spec:
      ingressClassName: nginx-default
      rules:
        - host: nginx.example.com
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: my-nginx
                    port:
                      number: 443
    EOF
    
  6. Test the TLS passthrough by connecting to the application using HTTPS.

    In the example below, the TLS connection is being negotiated using the certficate provided for host nginx.example.com. Thus, theTLS connection was passed to the deployed NGINX server.

    export MKE_HOST=<mke host>
    export NODE_PORT=33001
    
    curl -k -v \
    --resolve "nginx.example.com:$NODE_PORT:$MKE_HOST" \
    "https://nginx.example.com:$NODE_PORT"
    

    Example output:

    * Added nginx.example.com:33001:54.218.145.62 to DNS cache
    * Hostname nginx.example.com was found in DNS cache
    *   Trying 54.218.145.62:33001...
    * Connected to nginx.example.com (54.218.145.62) port 33001 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * successfully set certificate verify locations:
    *  CAfile: /etc/ssl/cert.pem
    *  CApath: none
    * (304) (OUT), TLS handshake, Client hello (1):
    * (304) (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-AES256-GCM-SHA384
    * ALPN, server accepted to use http/1.1
    * Server certificate:
    *  subject: O=Example Inc.; CN=nginx.example.com
    *  start date: Nov 29 18:52:39 2022 GMT
    *  expire date: Nov 26 18:52:39 2032 GMT
    *  issuer: O=Example Inc.; CN=nginx.example.com
    *  SSL certificate verify result: self signed certificate (18), continuing anyway.
    
    ...
    

    The output shows that the TLS connection is being negotiated with the certificate provided for host nginx.example.com, thus confirming that the TLS connection has passed to the deployed NGINX server.

  7. Clean up Kubernetes resources that are no longer needed:

    kubectl delete deploy my-nginx
    kubectl delete service my-nginx
    kubectl delete ingress nginx-test
    kubectl delete configmap nginx-conf
    kubectl delete secrets nginx-server-certs