Client TLS

Configure your ingress gateway to perform TLS origination for traffic that is sent to services in or outside your cluster. When TLS origination is enabled, the ingress gateway encrypts incoming HTTP or HTTPS requests by using TLS certificates before forwarding the request to an HTTPS server or service in the cluster. Therefore, TLS origination is the opposite of TLS termination where incoming HTTPS requests are decrypted by the ingress gateway before they are forwarded to a service in the cluster.

For more information, see the following resources:

If you import or export resources across workspaces, your policies might not apply. For more information, see Import and export policies.

Before you begin

To follow the example that is outlined on this page, Gloo Gateway must be set up in a single cluster as described in the getting started guide. You do not need to deploy sample apps as you create an NGINX server and configure it for HTTPS traffic as part of this example.

Deploy an NGINX server that is configured for HTTPS traffic

The following steps show how to deploy a sample NGINX server and configure the server for HTTPS traffic. You use this server to try out the client TLS policy later.

  1. Create a namespaces for the NGINX server that you deploy as part of this example.

    kubectl create namespace nginx
    
  2. Create a root certificate for the example.com domain. You use this certificate to sign the certificate for your NGINX service later.

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
    
  3. Create a server certificate and private key for the my-nginx.nginx.svc.cluster.local service.

    openssl req -out my-nginx.nginx.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout my-nginx.nginx.svc.cluster.local.key -subj "/CN=my-nginx.nginx.svc.cluster.local/O=some organization"
    openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in my-nginx.nginx.svc.cluster.local.csr -out my-nginx.nginx.svc.cluster.local.crt
    
  4. Generate the client certificate and private key.

    openssl req -out client.example.com.csr -newkey rsa:2048 -nodes -keyout client.example.com.key -subj "/CN=client.example.com/O=client organization"
    openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in client.example.com.csr -out client.example.com.crt
    
  5. Create a secret that stores the server and CA certificate that you created.

    kubectl create -n nginx secret tls nginx-server-certs --key my-nginx.nginx.svc.cluster.local.key --cert my-nginx.nginx.svc.cluster.local.crt
    kubectl create -n nginx secret generic nginx-ca-certs --from-file=example.com.crt
    
  6. Prepare your NGINX configuration. The following example configures NGINX for HTTPS traffic with the server and client certificates 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
    
  7. Store the NGINX configuration in a configmap.

    kubectl create configmap nginx-configmap -n nginx --from-file=nginx.conf=./nginx.conf
    
  8. Deploy the NGINX server.

    kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/policy-demo/nginx.yaml
    
  9. Store the client certificate and key in another secret that the ingress gateway later uses to authenticate with the NGINX server.

    kubectl create secret -n gloo-mesh-gateways generic client-credential --from-file=tls.key=client.example.com.key \
    --from-file=tls.crt=client.example.com.crt --from-file=ca.crt=example.com.crt
    

Configure and verify client TLS policies

Now that you configured your NGINX server for HTTPS traffic, you must enable TLS origination for the ingress gateway.

  1. Configure an HTTP listener on your ingress gateway. This listener enables the ingress gateway to accept incoming HTTP requests.

    kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: VirtualGateway
    metadata:
      name: mtls-gateway
      namespace: gloo-mesh-gateways
    spec:
      listeners:
      - port:
          number: 80
        http: {}
      workloads:
      - selector:
          labels:
            istio: ingressgateway
    EOF
    
  2. Create a route table that routes incoming HTTP traffic to the NGINX server that is configured for HTTPS traffic.

    kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: mtls-routetable
      namespace: gloo-mesh-gateways
    spec:
      virtualGateways:
      - name: mtls-gateway
        namespace: gloo-mesh-gateways
      hosts:
      - '*'
      http:
      - matchers:
        - uri:
            prefix: /
        forwardTo:
          destinations:
          - ref:
              name: my-nginx
              namespace: nginx
              cluster: $CLUSTER_NAME
            port:
              number: 443
    EOF
    
  3. Verify that your NGINX server does not accept incoming HTTP requests.

    1. In a new terminal, port-forward the ingress gateway on your local machine.

      kubectl port-forward deploy/ingressgateway -n gloo-mesh-gateways 8080
      
    2. Send an HTTP request to your local host. Because the ingress gateway is not yet configured for TLS origination, the HTTP request is forwarded to the NGINX server without encryption. However, the NGINX server is configured to only accept HTTPS traffic so you see an error stating that you tried to send plain HTTP traffic to an HTTPS port.

      curl localhost:8080
      

      Example output:

      <html>
      <head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
      <body>
      <center><h1>400 Bad Request</h1></center>
      <center>The plain HTTP request was sent to HTTPS port</center>
      <hr><center>nginx/1.23.3</center>
      </body>
      </html>
      
  4. Create the client TLS policy. This policy configures the ingress gateway to encrypt all incoming HTTP traffic for the NGINX deployment by using the client certificates that are stored in the secret.

    kubectl apply -f- <<EOF
    apiVersion: security.policy.gloo.solo.io/v2
    kind: ClientTLSPolicy
    metadata:
      name: mtls
      namespace: gloo-mesh-gateways
    spec:
      applyToDestinations:
      - selector:
          namespace: nginx
          labels:
            run: my-nginx
      mutual:
        config:
          credentialName: client-credential
    EOF
    
  5. Send another HTTP request to your local host. Because the ingress gateway is now configured to encrypt HTTP requests before forwarding them to the NGINX server, the request now succeeds.

    curl localhost:8080
    

    Example output:

    <!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 namespace nginx
kubectl delete virtualgateway mtls-gateway -n gloo-mesh-gateways
kubectl delete routetable mtls-routetable -n gloo-mesh-gateways
kubectl delete clienttlspolicy mtls -n gloo-mesh-gateways