Transport layer security (TLS)

Requirements

Sandbox environment

Setup your sandbox environment with Docker and Docker Compose, and clone the Envoy repository with Git.

curl

Used to make HTTP requests.

jq

Parse json output from the upstream echo servers.

This example walks through some of the ways that Envoy can be configured to make use of encrypted connections using HTTP over TLS.

It demonstrates a number of commonly used proxying and TLS termination patterns:

  • https -> http

  • https -> https

  • http -> https

  • https passthrough

To better understand the provided examples, and for a description of how TLS is configured with Envoy, please see the securing Envoy quick start guide.

Warning

For the sake of simplicity, the examples provided here do not authenticate any client certificates, or validate any of the provided certificates.

When using TLS, you are strongly encouraged to validate all certificates wherever possible.

You should also authenticate clients where you control both sides of the connection, or relevant protocols are available.

Step 1: Build the sandbox

Change directory to examples/tls in the Envoy repository.

This starts four proxies listening on localhost ports 10000-10003.

It also starts two upstream services, one HTTP and one HTTPS, which echo back received headers in json format.

The upstream services listen on the internal Docker network on ports 80 and 443 respectively.

  1. $ pwd
  2. envoy/examples/tls
  3. $ docker-compose pull
  4. $ docker-compose up --build -d
  5. $ docker-compose ps
  6. Name Command State Ports
  7. -----------------------------------------------------------------------------------------------
  8. tls_proxy-https-to-http_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp
  9. tls_proxy-https-to-https_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10001->10000/tcp
  10. tls_proxy-http-to-https_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10002->10000/tcp
  11. tls_proxy-https-passthrough_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10003->10000/tcp
  12. tls_service-http_1 node ./index.js Up
  13. tls_service-https_1 node ./index.js Up

Step 2: Test proxying https -> http

The Envoy proxy listening on https://localhost:10000 terminates HTTPS and proxies to the upstream HTTP service.

The https -> http configuration adds a TLS transport_socket to the listener.

Querying the service at port 10000 you should see an x-forwarded-proto header of https has been added:

  1. $ curl -sk https://localhost:10000 | jq -r '.headers["x-forwarded-proto"]'
  2. https

The upstream service-http handles the request.

  1. $ curl -sk https://localhost:10000 | jq -r '.os.hostname'
  2. service-http

Step 3: Test proxying https -> https

The Envoy proxy listening on https://localhost:10001 terminates HTTPS and proxies to the upstream HTTPS service.

The https -> https configuration adds a TLS transport_socket to both the listener and the cluster.

Querying the service at port 10001 you should see an x-forwarded-proto header of https has been added:

  1. $ curl -sk https://localhost:10001 | jq -r '.headers["x-forwarded-proto"]'
  2. https

The upstream service-https handles the request.

  1. $ curl -sk https://localhost:10001 | jq -r '.os.hostname'
  2. service-https

Step 4: Test proxying http -> https

The Envoy proxy listening on http://localhost:10002 terminates HTTP and proxies to the upstream HTTPS service.

The http -> https configuration adds a TLS transport_socket to the cluster.

Querying the service at port 10002 you should see an x-forwarded-proto header of http has been added:

  1. $ curl -s http://localhost:10002 | jq -r '.headers["x-forwarded-proto"]'
  2. http

The upstream service-https handles the request.

  1. $ curl -s http://localhost:10002 | jq -r '.os.hostname'
  2. service-https

Step 5: Test proxying https passthrough

The Envoy proxy listening on https://localhost:10003 proxies directly to the upstream HTTPS service which does the TLS termination.

The https passthrough configuration requires no TLS or HTTP setup, and instead uses a simple tcp_proxy.

Querying the service at port 10003 you should see that no x-forwarded-proto header has been added:

  1. $ curl -sk https://localhost:10003 | jq -r '.headers["x-forwarded-proto"]'
  2. null

The upstream service-https handles the request.

  1. $ curl -sk https://localhost:10003 | jq -r '.os.hostname'
  2. service-https

See also

Securing Envoy quick start guide

Outline of key concepts for securing Envoy.

TLS SNI sandbox

Example of using Envoy to serve multiple domains protected by TLS and served from the same IP address.

Double proxy sandbox

An example of securing traffic between proxies with validation and mutual authentication using mTLS with non-HTTP traffic.