SNI
Serve multiple hosts on the same HTTPS listener.
About SNI
Each host comes with its own TLS certificates that the gateway uses to authenticate and authorize client requests.
Serving multiple hosts on a single listener is also referred to as Server Name Indication (SNI) routing. SNI is an extension to the TLS protocol and allows clients to indicate which hostname they want to connect to at the start of the TLS handshake. After the HTTPS/TLS traffic is accepted at the gateway, the TLS connection is terminated, and the unencrypted HTTP/TCP request is forwarded to the destination.
About this guide
In this guide, you learn how to set up an HTTPS Gateway that serves two different domains, httpbin.example.com
and petstore.example.com
on the same port 443. When sending a request to the Gateway, you indicate the hostname you want to connect to. Based on the selected hostname, the Gateway presents the hostname-specific certificate.
Before you begin
Follow the Get started guide to install Gloo Gateway and deploy the httpbin sample app.
Make sure that you have the OpenSSL version of openssl, not LibreSSL. The openssl version must be at least 1.1.
- Check your
openssl
version. If you see LibreSSL in the output, continue to the next step.openssl version
- Install the OpenSSL version (not LibreSSL). For example, you might use Homebrew.
brew install openssl
- 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...
- For example,
- Check your
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 sample apps
Deploy the Petstore sample app. This app is used alongside the httpbin app from the Get started guide to demonstrate the SNI routing capabilities.
Deploy the Petstore app.
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo/v1.16.x/example/petstore/petstore.yaml
Example output:
deployment.apps/petstore created service/petstore created
Verify that the Petstore app is up and running.
kubectl get pods
Example output:
NAME READY STATUS RESTARTS AGE petstore-66cddd5bb4-x7vdd 1/1 Running 0 26s
Set up TLS certificates for multiple domains
Create TLS certificates for the httpbin.example.com
and petstore.example.com
domains that are signed by a self-signed root CA.
Self-signed certificates are used for demonstration purposes. Do not use self-signed certificates in production environments. Instead, use certificates that are issued from a trust Certificate Authority.
Create a root certificate and private key to sign the certificates for your services.
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
Generate a TLS certificate and key for the
httpbin.example.com
domain.openssl req -out example_certs/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin 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/httpbin.example.com.csr -out example_certs/httpbin.example.com.crt
Generate a TLS certificate and key for the
petstore.example.com
domain.openssl req -out example_certs/petstore.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs/petstore.example.com.key -subj "/CN=petstore.example.com/O=petstore 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/petstore.example.com.csr -out example_certs/petstore.example.com.crt
Verify that you have the required certificates and keys.
ls example_cert*
Example output:
petstore.example.com.crt petstore.example.com.key example.com.crt httpbin.example.com.crt httpbin.example.com.key petstore.example.com.csr example.com.key httpbin.example.com.csr
Store the credentials for the
httpbin.example.com
domain in a Kubernetes secret.kubectl create -n gloo-system secret tls httpbin-credential \ --key=example_certs/httpbin.example.com.key \ --cert=example_certs/httpbin.example.com.crt
If you want to configure the Gateway to use an mTLS connection instead of one-way TLS between the downstream client and the Gateway, include the root CA certificate in your Kubernetes secret. Create the secret with theglooctl create secret tls --name httpbin-credential --certchain example_certs/httpbin.example.com.crt --privatekey example_certs/httpbin.example.com.key --rootca example_certs/example.com.crt
command. Note that you must have a client certificate and key that is signed by the same root CA. For more information, see the Mutual TLS guide.Store the credentials for the
petstore.example.com
domain in a Kubernetes secret.kubectl create -n gloo-system secret tls petstore-credential \ --key=example_certs/petstore.example.com.key \ --cert=example_certs/petstore.example.com.crt
If you want to configure the Gateway to use an mTLS connection instead of one-way TLS between the downstream client and the Gateway, include the root CA certificate in your Kubernetes secret. Create the secret with theglooctl create secret tls --name petstore-credential --certchain example_certs/petstore.example.com.crt --privatekey example_certs/petstore.example.com.key --rootca example_certs/example.com.crt
command. Note that you must have a client certificate and key that is signed by the same root CA. For more information, see the Mutual TLS guide
Set up SNI routing
Set up an SNI Gateway that serves multiple hosts on the same port.
Create an SNI Gateway. The Gateway defines two hosts on the same HTTPS listener. Each host is configured with the host-specific TLS certificate that you set up earlier.
Create an HTTPRoute that routes incoming requests on the
httpbin.example.com
domain to the httpbin app.Create an HTTPRoute that routes incoming requests on the
petstore.example.com
domain to the petstore app.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.
Send a request to the
httpbin.example.com
domain with the client certificate that you created earlier. Verify that the gateway presents the TLS certificate for thehttpbin.example.com
domain during the TLS handshake.Example output:
* Added httpbin.example.com:443:3.XXX.XXX.XX to DNS cache * Hostname httpbin.example.com was found in DNS cache * Trying 3.128.214.17:443... * Connected to httpbin.example.com (3.XXX.XXX.XX) 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=httpbin.example.com; O=httpbin organization * issuer: O=example Inc.; CN=example.com * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. * using HTTP/2 * [HTTP/2] [1] OPENED stream for https://httpbin.example.com:443/headers * [HTTP/2] [1] [:method: GET] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: httpbin.example.com] * [HTTP/2] [1] [:path: /headers] * [HTTP/2] [1] [user-agent: curl/8.7.1] * [HTTP/2] [1] [accept: */*] > GET /headers HTTP/2 > Host: httpbin.example.com > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/2 200 HTTP/2 200 ... "Accept": [ "*/*" ], "Host": [ "httpbin.example.com" ], "User-Agent": [ "curl/8.7.1" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Forwarded-Proto": [ "https" ], "X-Request-Id": [ "33654cba-7198-4b7c-a850-8629fd230145" ] } }
Send a request to the
petstore.example.com
domain with the client certificate that you created earlier. Verify that the gateway presents the TLS certificate for thepetstore.example.com
domain during the TLS handshake.Example output:
* Added petstore.example.com:443:3.XXX.XXX.XX to DNS cache * Hostname petstore.example.com was found in DNS cache * Trying 3.128.214.17:443... * Connected to petstore.example.com (3.XXX.XXX.XX) 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=petstore.example.com; O=petstore organization * issuer: O=example Inc.; CN=example.com * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. * using HTTP/2 * [HTTP/2] [1] OPENED stream for https://petstore.example.com:443/api/pets * [HTTP/2] [1] [:method: GET] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: petstore.example.com] * [HTTP/2] [1] [:path: /api/pets] * [HTTP/2] [1] [user-agent: curl/8.7.1] * [HTTP/2] [1] [accept: */*] > GET /api/pets HTTP/2 > Host: petstore.example.com > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/2 200 HTTP/2 200 ... [{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]
Cleanup
You can optionally remove the resources that you set up as part of this guide.
Remove the routing resources for the HTTPS route, including the Kubernetes secret that holds the TLS certificate and key.
Remove the
example_certs
directory that stores your TLS credentials.rm -rf example_certs