Secure gateways

Configure transport layer security (TLS) certificates in your Gloo Mesh virtual gateway. Then, your Istio ingress gateways can serve HTTPS traffic.

Before you begin

  1. Complete the demo setup to install Gloo Mesh, Istio, and Bookinfo in your cluster. As part of this setup, keep in mind the following points.
    • License: Make sure to use your Gloo Mesh Gateway license key when you install Gloo Mesh Enterprise.
    • Namespaces: The setup example deploys the gateways into the istio-system namespace. If you use a different namespace, update the example configuration files.
  2. The default openssl version that is included in macOS is LibreSSL, which does not work with these instructions.

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

    1. Check the openssl version that is installed. 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. Set up environment variables for your certificates.
    • Update the DNS_NAME with the domain name that the certificate is for.
    • Update the GATEWAY_NAMESPACE and $REMOTE_CONTEXT values to match the cluster and namespace that the Istio ingress gateway is deployed to.
    ROOT_CERT_NAME=gateway-root
    DNS_NAME=www.example.com
    SERVER_CERT_NAME=north-south-gw-tls
    GATEWAY_NAMESPACE=istio-system
    GATEWAY_KUBE_CONTEXT=$REMOTE_CONTEXT
    

Create TLS certificate and key pair

In production scenarios, you might have a TLS certificate and key pair from a certificate management tool that you use. In this case, continue to the next section.

To create your own for a test environment, complete the following steps.

  1. Create the root certificate. The following command creates a root key for 10 years for the DNS hostname that you previously set as an environment variable. You can create a separate root key for each hostname. You might also use wildcards in the DNS hostname, such as to make a root key for multiple subdomains (*.example.com), or to create a test root key for any host (*). For more information, see the OpenSSL docs.
    # root cert
    openssl req -new -newkey rsa:4096 -x509 -sha256 \
        -days 3650 -nodes -out ${ROOT_CERT_NAME}.crt -keyout ${ROOT_CERT_NAME}.key \
        -subj "/CN=${DNS_NAME}/O=${ROOT_CERT_NAME}" \
        -addext "subjectAltName = DNS:${DNS_NAME}"
    
  2. Use the root certificate to create the server certificate.
    # server cert
    cat > "${SERVER_CERT_NAME}.conf" <<EOF
    [req]
    req_extensions = v3_req
    distinguished_name = req_distinguished_name
    [req_distinguished_name]
    [ v3_req ]
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth, serverAuth
    subjectAltName = @alt_names
    [alt_names]
    DNS = ${DNS_NAME}
    EOF
    
    openssl genrsa -out "${SERVER_CERT_NAME}.key" 2048
    openssl req -new -key "${SERVER_CERT_NAME}.key" -out ${SERVER_CERT_NAME}.csr -subj "/CN=${DNS_NAME}/O=${SERVER_CERT_NAME}" -config "${SERVER_CERT_NAME}.conf"
    openssl x509 -req \
      -days 3650 \
      -CA ${ROOT_CERT_NAME}.crt -CAkey ${ROOT_CERT_NAME}.key \
      -set_serial 0 \
      -in ${SERVER_CERT_NAME}.csr -out ${SERVER_CERT_NAME}.crt \
      -extensions v3_req -extfile "${SERVER_CERT_NAME}.conf"
    

Configure TLS for the virtual gateway

In your Gloo Mesh VirtualGateway custom resource to include add the TLS configuration details, including an HTTPS redirect. Then, Gloo Mesh applies the updates to each Istio ingress gateway that the virtual gateway selects so that the gateways handle HTTPS traffic for your hosts.

  1. Add your server certificate to the service mesh by using a Kubernetes Secret. You create the secret in the same cluster and namespace that the ingress gateway is deployed to.

    # create secret from server cert
    kubectl create secret generic ${SERVER_CERT_NAME}-secret \
    --from-file=tls.key=${SERVER_CERT_NAME}.key \
    --from-file=tls.crt=${SERVER_CERT_NAME}.crt \
    --dry-run=client -oyaml | kubectl apply -f- \
    --context ${GATEWAY_KUBE_CONTEXT} \
    --namespace ${GATEWAY_NAMESPACE}
    
  2. If you have ingress gateways in multiple clusters or namespaces, repeat the previous step for each namespace in each cluster that an ingress gateway is installed. The name of the secret must be the same in all clusters, although the secret can be in different namespaces as appropriate.

  3. Configure the VirtualGateway custom resource with the TLS details. Review the following example. For more information, see the API docs.

    kubectl --context ${REMOTE_CONTEXT} apply -f - <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: VirtualGateway
    metadata:
      name: ${SERVER_CERT_NAME}
      namespace: {GATEWAY_NAMESPACE}
    spec:
      workloads:
        - selector:
            labels:
              istio: ingressgateway
            cluster: ${REMOTE_CLUSTER}
      listeners: 
        - http: {}
          port:
            number: 443
          tls:
            mode: SIMPLE
            secretName: ${SERVER_CERT_NAME}-secret
          httpsRedirect: true
          allowedRouteTables:
            - host: '${DNS_NAME}'
    EOF
    
    Review the following table to understand this configuration.
    Setting Description
    metadata.namespace Create the virtual gateway in a namespace that is in the same workspace as your Istio ingress gateway, such as the same namespace.
    spec.workloads Select the Istio ingress gateways that you want to secure traffic to.
    spec.listeners.port Select the HTTPS port 443, or you could use the port.name to select HTTPS.
    spec.listeners.tls Configure the mode and secret to use to secure traffic. Remember that each cluster and namespace for each gateway must have the secret.
    spec.listeners.httpsRedirect Set to true so that any HTTP requests from port 80 are automatically redirected to HTTPS on port 443, with a 301 Moved Permanently response code.
    spec.listeners.allowedRouteTables You can specify the host name that the certificates are valid for, or select the route tables to use.

Verify the secure connection

Production setup: If you have your own domain, certificates, DNS, and load balancer exposed on port 443 set up, you can test the secure connection by curling the HTTPS address.

curl https://${DNS_NAME}/ratings/1

Test setup: If you do not have DNS and a load balancer or node port set up, you can still test the secure connection by tweaking a few settings.

  1. Enable port-forwarding for the istio-ingressgateway workload on port 443. Port-forwarding on 443 requires admin privileges, such as to run sudo on Linux or macOS. If you do not have admin privileges to listen locally on port 443, use a number greater than 1024 instead.

    
    # Note: You need sudo priviliges to listen on port 443 locally:
    sudo kubectl port-forward -n istio-system service/istio-ingressgateway 443
    
    
    # Listen on port 8443 locally:
    kubectl port-forward -n istio-system service/istio-ingressgateway 8443:443
    
  2. Send a curl request that uses the HTTPS protocol for your domain, such as www.example.com.

    
    # Note: Assumes you are listening on port 443 locally
    curl -k --resolve www.example.com:443:127.0.0.1 https://www.example.com/ratings/1
    
    
    # Note: Assumes you are listening on port 8443 locally
    curl -k --resolve www.example.com:8443:127.0.0.1 https://www.example.com:8443/ratings/1
    

    The ratings service returns a response, such as {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}.

  3. Print more verbose output by adding the -v option to the curl command.

    
    # Note: Assumes you are listening on port 443 locally
    curl -vik --resolve www.example.com:443:127.0.0.1 https://www.example.com/ratings/1
    
    
    # Note: Assumes you are listening on port 8443 locally
    curl -vik --resolve www.example.com:8443:127.0.0.1 https://www.example.com:8443/ratings/1
    

    Note the TLS information that is used for the request.

    * Added www.example.com:8443:127.0.0.1 to DNS cache
    * Hostname www.example.com was found in DNS cache
    *   Trying 127.0.0.1...
    * TCP_NODELAY set
    * Connected to www.example.com (127.0.0.1) port 8443 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * successfully set certificate verify locations:
    *   CAfile: /etc/ssl/cert.pem
      CApath: none
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (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-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: CN=www.example.com; O=gw-ssl
    *  start date: Aug  6 18:27:18 2021 GMT
    *  expire date: Aug  4 18:27:18 2031 GMT
    *  issuer: CN=www.example.com; O=gateway-root
    *  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
    * Using HTTP2, server supports multi-use
    * Connection state changed (HTTP/2 confirmed)
    * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
    * Using Stream ID: 1 (easy handle 0x7fb3c7010a00)
    > GET /ratings/1 HTTP/2
    > Host: www.example.com:8443
    > User-Agent: curl/7.64.1
    > Accept: */*
    >
    * Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
    < HTTP/2 200
    HTTP/2 200
    < content-type: application/json
    content-type: application/json
    < date: Fri, 06 Aug 2021 21:46:05 GMT
    date: Fri, 06 Aug 2021 21:46:05 GMT
    < x-envoy-upstream-service-time: 2
    x-envoy-upstream-service-time: 2
    < server: istio-envoy
    server: istio-envoy
       
    * Connection #0 to host www.example.com left intact
    {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}* Closing connection 0