Envoy is an extremely flexible reverse proxy, most known by its use in istio where it functions as an envelope in every job, routing the traffic and managing authorization.
That said, it’s totally fine to use envoy on its own; one case for such would be gRPC-Web. Despite gRPC being based on HTTP/2, the web browsers don’t expose enough of the HTTP insides to the JS runtime for the client code to talk gRPC directly, and thus there’s a need in proxying a web-safe gRPC-Web into the “native” gRPC. This is where envoy comes in.
Here’s a typical envoy configuration to serve as a gRPC-Web proxy:
|
|
For every outgoing connection, envoy needs an entry in clusters
, specifying the connection details. In the example above the cluster echo_service
will be reachable at http://node-server:9090
.
What if your backend talks HTTPS though? This is where the configuration gets interesting and somewhat cryptic.
|
|
First, notice how the hosts is now deprecated and you need to specify the load_assignment configuration. It’s straightforward; the logical_dns option tells envoy to resolve the socket address.
The cluster name is set to remote.example.com|443
. That bears no technical reason and I do that only to match the internal envoy’s reporting; i.e. it is customary but not required to name the clusters like that.
The transport_socket
part tells envoy to use HTTPS (or rather—TLS). The crucial parts are the sni
field which tells envoy which host to present for SNI validation (this should be your remote hostname in most of the cases) and the validation_context
. Hilariously, it’s 2020 and envoy doesn’t verify the remote certificates by default, which means you must explicitly tell it to do that or face a potential MITM attack.
Beware of match_subject_alt_names
being a string matcher. It means envoy won’t just behave like your browser; instead you need to include literally the expected SAN, e.g. if your remote has a wildcard certificate you must use that wildcard, not the actual domain.
Side note: if you’re using envoyproxy/envoy-alpine
from Dockerhub, it doesn’t include the ca-certificates by default. Inherit from it and do something like:
|
|
to make sure you have those certificates.
Final note. If your backend only talks HTTP/1.x but not HTTP/2, remove the http2_protocol_options
flag and envoy will fall back talking the old HTTP.