TLS Server name indication (SNI
)
Requirements
Setup your sandbox environment with Docker and Docker Compose, and clone the Envoy repository with Git.
Used to make HTTP
requests.
Parse json
output from the upstream echo servers.
This example demonstrates an Envoy proxy that listens on three TLS
domains on the same IP
address.
The first two domains (domain1
and domain2
) terminate the TLS
and proxy to upstream HTTP
hosts.
The other domain (domain3
) is proxied unterminated, based on the SNI
headers.
It also demonstrates Envoy acting as a client proxy connecting to upstream SNI
services.
Step 1: Create keypairs for each of the domain endpoints
Change directory to examples/tls-sni
in the Envoy repository.
The example creates two Envoy TLS
endpoints and they will require their own keypairs.
Create self-signed certificates for these endpoints as follows:
$ pwd
envoy/examples/tls-sni
$ mkdir -p certs
$ openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
-subj "/C=US/ST=CA/O=MyExample, Inc./CN=domain1.example.com" \
-keyout certs/domain1.key.pem \
-out certs/domain1.crt.pem
Generating a RSA private key
.............+++++
...................+++++
writing new private key to 'certs/domain1.key.pem'
-----
$ openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
-subj "/C=US/ST=CA/O=MyExample, Inc./CN=domain2.example.com" \
-keyout certs/domain2.key.pem \
-out certs/domain2.crt.pem
Generating a RSA private key
.............+++++
...................+++++
writing new private key to 'certs/domain2.key.pem'
-----
Warning
SNI
does not validate that the certificates presented are correct for the domain, or that they were issued by a recognised certificate authority.
See the Securing Envoy quick start guide for more information about validating cerfificates.
Step 2: Start the containers
Build and start the containers.
This starts two upstream HTTP
containers listening on the internal Docker network on port 80
, and an upstream HTTPS
service listening on internal port 443
In front of these is an Envoy proxy that listens on https://localhost:10000 and serves three SNI
routed TLS
domains:
domain1.example.com
domain2.example.com
domain3.example.com
The first two domains use the keys and certificates you created in step 1 to terminate TLS
and proxy to the two upstream HTTP
servers.
The third domain proxies to the upstream TLS
server based on the requested SNI
address, but does no TLS
termination itself.
The composition also starts an Envoy proxy client which listens on http://localhost:20000.
The client proxy has no TLS
termination but instead proxies three routed paths - /domain1
, /domain2
and /domain3
- to the SNI
-enabled proxy.
$ pwd
envoy/examples/tls-sni
$ docker-compose build --pull
$ docker-compose up -d
$ docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------------------
tls-sni_http-upstream1_1 node ./index.js Up
tls-sni_http-upstream2_1 node ./index.js Up
tls-sni_http-upstream3_1 node ./index.js Up
tls-sni_proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp
tls-sni_proxy-client_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:20000->10000/tcp
Step 2: Query the SNI
endpoints directly with curl
You can use curl to query the SNI
-routed HTTPS
endpoints of the Envoy proxy directly.
To do this you must explicitly tell curl to resolve the DNS
for the endpoints correctly.
Each endpoint should proxy to the respective http-upstream
or https-upstream
service.
$ curl -sk --resolve domain1.example.com:10000:127.0.0.1 \
https://domain1.example.com:10000 \
| jq -r '.os.hostname'
http-upstream1
$ curl -sk --resolve domain2.example.com:10000:127.0.0.1 \
https://domain2.example.com:10000 \
| jq -r '.os.hostname'
http-upstream2
$ curl -sk --resolve domain3.example.com:10000:127.0.0.1 \
https://domain3.example.com:10000 \
| jq -r '.os.hostname'
https-upstream3
Step 3: Query the SNI
endpoints via an Envoy proxy client
Next, query the Envoy proxy client using the routed paths.
These route via the SNI
proxy endpoints to the respective http-upstream
or https-upstream
services.
$ curl -s http://localhost:20000/domain1 \
| jq '.os.hostname'
http-upstream1
$ curl -s http://localhost:20000/domain2 \
| jq '.os.hostname'
http-upstream2
$ curl -s http://localhost:20000/domain3 \
| jq '.os.hostname'
https-upstream3
See also
Securing Envoy quick start guide
Outline of key concepts for securing Envoy.
Sandbox featuring examples of how Envoy can be configured to make use of encrypted connections using HTTP
over TLS
.
An example of securing traffic between proxies with validation and mutual authentication using mTLS
with non-HTTP
traffic.