Multiple hosts on one listener (SNI)
Set up an HTTPS/ TLS listener on the gateway that serves multiple hosts.
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.
Before you begin
This guide assumes that you use the same names for components like clusters, workspaces, and namespaces as in the getting started. If you have different names, make sure to update the sample configuration files in this guide.
Set up SNI routing for multiple domains
The following steps show how you can set up a single HTTPS listener on your ingress gateway that serves multiple hosts. The steps in this guide show how to set up SNI routing for the httpbin.example.com
and bookinfo.example.com
domains.
When you apply the Gloo custom resources in this guide to your cluster, Gloo Mesh Gateway automatically checks the configuration against validation rules and value constraints. You can also run a pre-admission validation check by using the meshctl x validate resources
command. For more information, see the resource validation overview and the CLI command reference.
Create a root certificate and private key to sign the certificates for your services.
mkdir example_certs1 openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs1/example.com.key -out example_certs1/example.com.crt
Generate a TLS certificate and key for the
httpbin.example.com
domain.openssl req -out example_certs1/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization" openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 0 -in example_certs1/httpbin.example.com.csr -out example_certs1/httpbin.example.com.crt
Generate a TLS certificate and key for the
bookinfo.example.com
domain.openssl req -out example_certs1/bookinfo.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/bookinfo.example.com.key -subj "/CN=bookinfo.example.com/O=bookinfo organization" openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 1 -in example_certs1/bookinfo.example.com.csr -out example_certs1/bookinfo.example.com.crt
Generate a corresponding client certificate and private key that you later use to send requests to your gateway for both of your domains.
openssl req -out example_certs1/client.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/client.example.com.key -subj "/CN=client.example.com/O=client organization" openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 1 -in example_certs1/client.example.com.csr -out example_certs1/client.example.com.crt
Verify that you have the required certificates and keys.
ls example_cert*
Example output:
bookinfo.example.com.crt bookinfo.example.com.key client.example.com.csr example.com.crt httpbin.example.com.crt httpbin.example.com.key bookinfo.example.com.csr client.example.com.crt client.example.com.key example.com.key httpbin.example.com.csr
Store the credentials for the
httpbin.example.com
domain in a Kubernetes secret.kubectl create -n gloo-mesh-gateways secret tls httpbin-credential \ --key=example_certs1/httpbin.example.com.key \ --cert=example_certs1/httpbin.example.com.crt
Store the credentials for the
bookinfo.example.com
domain in a Kubernetes secret.kubectl create -n gloo-mesh-gateways secret tls bookinfo-credential \ --key=example_certs1/bookinfo.example.com.key \ --cert=example_certs1/bookinfo.example.com.crt
Create a virtual gateway and configure HTTPS listeners for both domains on the same port. Each HTTPS listener uses the domain-specific TLS credentials from the secret that you created earlier.
kubectl apply -f - <<EOF apiVersion: networking.gloo.solo.io/v2 kind: VirtualGateway metadata: name: mtls-vgateway namespace: gloo-mesh-gateways spec: listeners: - port: number: 443 http: {} tls: mode: SIMPLE secretName: httpbin-credential allowedRouteTables: - host: httpbin.example.com - port: number: 443 http: {} tls: mode: SIMPLE secretName: bookinfo-credential allowedRouteTables: - host: bookinfo.example.com workloads: - selector: labels: istio: ingressgateway EOF
Create a route table for the
httpbin.example.com
domain that routes incoming traffic to the httpbin app in your cluster.kubectl apply -f - <<EOF apiVersion: networking.gloo.solo.io/v2 kind: RouteTable metadata: name: httpbin namespace: gloo-mesh-gateways spec: virtualGateways: - name: mtls-vgateway namespace: gloo-mesh-gateways hosts: - 'httpbin.example.com' http: - matchers: - uri: prefix: / forwardTo: destinations: - ref: name: httpbin namespace: httpbin cluster: $CLUSTER_NAME port: number: 8000 EOF
Create a route table for the
bookinfo.example.com
domain that routes incoming traffic to the productpage app in your cluster.kubectl apply -f - <<EOF apiVersion: networking.gloo.solo.io/v2 kind: RouteTable metadata: name: bookinfo namespace: gloo-mesh-gateways spec: virtualGateways: - name: mtls-vgateway namespace: gloo-mesh-gateways hosts: - 'bookinfo.example.com' http: - matchers: - uri: prefix: / forwardTo: destinations: - ref: name: productpage namespace: bookinfo cluster: $CLUSTER_NAME port: number: 9080 EOF
Send a request to the
httpbin.example.com
domain with the client certificate that you created earlier. The gateway authorizes the request by using the TLS credentials that you stored in the TLS secret.curl -vik -HHost:httpbin.example.com --resolve "httpbin.example.com:443:${INGRESS_GW_IP}" \ --cacert example_certs1/example.com.crt "https://httpbin.example.com:443/status/200"
Example output:
... * Added httpbin.example.com:443:34.145.173.107 to DNS cache * Hostname httpbin.example.com was found in DNS cache * Trying 34.145.173.107:443... * Connected to httpbin.example.com (34.145.173.107) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: example_certs1/example.com.crt * 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=httpbin.example.com; O=httpbin organization * start date: Dec 29 17:10:18 2022 GMT * expire date: Dec 29 17:10:18 2023 GMT * issuer: O=example Inc.; CN=example.com * SSL certificate verify ok. * 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 0x150012400) > GET /status/200 HTTP/2 > Host:httpbin.example.com > user-agent: curl/7.77.0 > accept: */* > * Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)! < HTTP/2 200 HTTP/2 200 ...
Send a request to the
bookinfo.example.com
domain with the client certificate that you created earlier. The gateway authorizes the request by using the TLS credentials that you stored in the TLS secret.curl -vik -HHost:bookinfo.example.com --resolve "bookinfo.example.com:443:${INGRESS_GW_IP}" \ --cacert example_certs1/example.com.crt "https://bookinfo.example.com:443/productpage"
Example output:
... * Added bookinfo.example.com:443:34.145.173.107 to DNS cache * Hostname bookinfo.example.com was found in DNS cache * Trying 34.145.173.107:443... * Connected to bookinfo.example.com (34.145.173.107) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: example_certs1/example.com.crt * 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=bookinfo.example.com; O=bookinfo organization * start date: Dec 29 17:10:45 2022 GMT * expire date: Dec 29 17:10:45 2023 GMT * issuer: O=example Inc.; CN=example.com * SSL certificate verify ok. * 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 0x145017400) > GET /productpage HTTP/2 > Host:bookinfo.example.com > user-agent: curl/7.77.0 > accept: */* > * Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)! < HTTP/2 200 HTTP/2 200 ...
Next steps
Now that you have the virtual gateway configured, you can add other Gloo Mesh Gateway resources to control traffic that is routed through the gateway.
- Process and route traffic through the virtual gateway with route tables, such as by using header matching, redirects, or direct responses.
- Explore traffic management, security, and resiliency policies that you can apply to your routes and upstream services. For example, you might apply the proxy protocol policy to your API Gateway so that it preserves connection information such as the originating client IP address.
Cleanup
You can optionally remove the resources that you set up as part of this guide.
rm -r example_certs1
kubectl delete secret httpbin-credential -n gloo-mesh-gateways
kubectl delete secret bookinfo-credential -n gloo-mesh-gateways
kubectl delete virtualgateway mtls-vgateway -n gloo-mesh-gateways
kubectl delete routetable httpbin -n gloo-mesh-gateways
kubectl delete routetable bookinfo -n gloo-mesh-gateways