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
opensslversion. 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
opensslcommand.- For example,
opensslmight 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
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.yamlExample output:
deployment.apps/petstore created service/petstore createdVerify that the Petstore app is up and running.
kubectl get podsExample 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.crtGenerate a TLS certificate and key for the
httpbin.example.comdomain.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.crtGenerate a TLS certificate and key for the
petstore.example.comdomain.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.crtVerify 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.csrStore the credentials for the
httpbin.example.comdomain 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.crtIf 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.crtcommand. 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.comdomain 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.crtIf 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.crtcommand. 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.
kubectl apply -f- <<EOF kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: sni namespace: gloo-system spec: gatewayClassName: gloo-gateway listeners: - protocol: HTTPS port: 443 name: httpbin hostname: "httpbin.example.com" tls: mode: Terminate certificateRefs: - name: httpbin-credential kind: Secret allowedRoutes: namespaces: from: All - protocol: HTTPS port: 443 name: petstore hostname: "petstore.example.com" tls: mode: Terminate certificateRefs: - name: petstore-credential kind: Secret allowedRoutes: namespaces: from: All EOFCreate an HTTPRoute that routes incoming requests on the
httpbin.example.comdomain to the httpbin app.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-https namespace: httpbin labels: example: httpbin-route spec: parentRefs: - name: sni namespace: gloo-system hostnames: - "httpbin.example.com" rules: - backendRefs: - name: httpbin port: 8000 EOFCreate an HTTPRoute that routes incoming requests on the
petstore.example.comdomain to the petstore app.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: petstore-https namespace: default labels: example: petstore-route spec: parentRefs: - name: sni namespace: gloo-system hostnames: - "petstore.example.com" rules: - backendRefs: - name: petstore port: 8080 EOFGet 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.comdomain with the client certificate that you created earlier. Verify that the gateway presents the TLS certificate for thehttpbin.example.comdomain 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.comdomain with the client certificate that you created earlier. Verify that the gateway presents the TLS certificate for thepetstore.example.comdomain 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.
kubectl delete secret httpbin-credential -n gloo-system
kubectl delete secret petstore-credential -n gloo-system
kubectl delete gateway sni -n gloo-system
kubectl delete httproute httpbin-https -n httpbin
kubectl delete httproute petstore-https -n default
kubectl delete deployment petstore
kubectl delete service petstore
rm -r example_certs