-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Initial support for upstream HTTP/1.1 tunneling #13293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
efcc5ed
40c2ac3
5ff338e
2e0857f
5d6d5de
0ddc44f
a1c9d98
eecf55c
3cfa1e9
3f7b4cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # This configuration takes incoming data on port 10000 and encapsulates it in a CONNECT | ||
| # request which is sent upstream port 10001. | ||
| # It can be used to test TCP tunneling as described in docs/root/intro/arch_overview/http/upgrades.rst | ||
| # and running `curl --x 127.0.0.1:10000 https://www.google.com` | ||
|
|
||
| admin: | ||
| access_log_path: /tmp/admin_access.log | ||
| address: | ||
| socket_address: | ||
| protocol: TCP | ||
| address: 127.0.0.1 | ||
| port_value: 9903 | ||
| static_resources: | ||
| listeners: | ||
| - name: listener_0 | ||
| address: | ||
| socket_address: | ||
| protocol: TCP | ||
| address: 127.0.0.1 | ||
| port_value: 10000 | ||
| filter_chains: | ||
| - filters: | ||
| - name: tcp | ||
| typed_config: | ||
| "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy | ||
| stat_prefix: tcp_stats | ||
| cluster: "cluster_0" | ||
| tunneling_config: | ||
| hostname: host.com:443 | ||
| clusters: | ||
| - name: cluster_0 | ||
| connect_timeout: 5s | ||
| # This ensures HTTP/1.1 CONNECT is used for establishing the tunnel. | ||
| http_protocol_options: | ||
| {} | ||
|
antoniovicente marked this conversation as resolved.
|
||
| load_assignment: | ||
| cluster_name: cluster_0 | ||
| endpoints: | ||
| - lb_endpoints: | ||
| - endpoint: | ||
| address: | ||
| socket_address: | ||
| address: 127.0.0.1 | ||
| port_value: 10001 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,10 +26,11 @@ static_resources: | |
| stat_prefix: tcp_stats | ||
| cluster: "cluster_0" | ||
| tunneling_config: | ||
| hostname: host.com | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, why 10002 when it's connecting to port 10001?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My idea was to show that the destination port can be different from the port used by the upstream proxy, but maybe using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sending CONNECT foo.com:1234 to foo.com:1235 seems odd to me, but if you think it's worth explicitly testing for that how about a comment so other folks don't think it's just an off by one error :-)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just to be sure we are on the same page, in this scenario, the CONNECT is sent to the upstream that is |
||
| hostname: host.com:443 | ||
| clusters: | ||
| - name: cluster_0 | ||
| connect_timeout: 5s | ||
| # This ensures HTTP/2 CONNECT is used for establishing the tunnel. | ||
| http2_protocol_options: | ||
| {} | ||
| load_assignment: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,17 +94,31 @@ will synthesize 200 response headers, and then forward the TCP data as the HTTP | |
| For an example of proxying connect, please see :repo:`configs/proxy_connect.yaml <configs/proxy_connect.yaml>` | ||
| For an example of terminating connect, please see :repo:`configs/terminate_connect.yaml <configs/terminate_connect.yaml>` | ||
|
|
||
| Tunneling TCP over HTTP/2 | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| Envoy also has support for transforming raw TCP into HTTP/2 CONNECT requests. This can be used to | ||
| proxy multiplexed TCP over pre-warmed secure connections and amortize the cost of any TLS handshake. | ||
| An example set up proxying SMTP would look something like this | ||
| Tunneling TCP over HTTP | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
| Envoy also has support for tunneling raw TCP over HTTP CONNECT requests. Find | ||
| below some usage scenarios. | ||
|
|
||
| HTTP/2 CONNECT can be used to proxy multiplexed TCP over pre-warmed secure connections and amortize the cost of any TLS | ||
| handshake. | ||
| An example set up proxying SMTP would look something like this: | ||
|
|
||
| [SMTP Upstream] --- raw SMTP --- [L2 Envoy] --- SMTP tunneled over HTTP/2 --- [L1 Envoy] --- raw SMTP --- [Client] | ||
|
|
||
| Examples of such a set up can be found in the Envoy example config :repo:`directory <configs/>` | ||
| If you run `bazel-bin/source/exe/envoy-static --config-path configs/encapsulate_in_connect.yaml --base-id 1` | ||
| If you run `bazel-bin/source/exe/envoy-static --config-path configs/encapsulate_in_http2_connect.yaml --base-id 1` | ||
| and `bazel-bin/source/exe/envoy-static --config-path configs/terminate_connect.yaml` | ||
| you will be running two Envoys, the first listening for TCP traffic on port 10000 and encapsulating it in an HTTP/2 | ||
| CONNECT request, and the second listening for HTTP/2 on 10001, stripping the CONNECT headers, and forwarding the | ||
| original TCP upstream, in this case to google.com. | ||
|
|
||
| HTTP/1.1 CONNECT can be used to have TCP client connecting to its own | ||
| destination passing through an HTTP proxy server (e.g. corporate proxy): | ||
|
|
||
| [HTTP Server] --- raw HTTP --- [Upstream HTTP Proxy] --- HTTP tunneled over HTTP/1.1 --- [Envoy] --- raw HTTP --- [HTTP Client] | ||
|
|
||
| Examples of such a set up can be found in the Envoy example config :repo:`directory <configs/>` | ||
| If you run `bazel-bin/source/exe/envoy-static --config-path configs/encapsulate_in_http1_connect.yaml --base-id 1` | ||
| you will be running Envoy listening for TCP traffic on port 10000 and encapsulating it in an HTTP/1.1 | ||
| CONNECT addressed to an HTTP proxy running on localhost and listenig on port | ||
| 10001, having as a final destination host.com on port 443. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a first time reader this seems a bit confusing: which proxy are we configuring with the provided config? Both? Just the one labeled 'Envoy'?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this scenario, I made the assumption that the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having re-read this a few times i realize my confusion stems from the fact that the flow is server -> client, not client -> server, and I was originally thinking of the encapsulation flow as originating from the client. I think I would still have this example make use of two Envoy instances (assuming we support this) and then mention that this can be used when the upstream is another proxy that does not support HTTP/2 (to justify why you would ever use HTTP/1.1). I think this would be clearer and would make the example complete, as its not relying on the reader knowing how to set up another local proxy.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, this makes sense. If it's not a problem for you I could address this with a follow-up PR as I still have some work to do on this feature.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did this already as I had to do another change. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the new HTTP1 example be included here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about this, WDYT @alyssawilk ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, might as well for completeness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done