Tunneling TCP traffic using the L4 proxy capabilities of Envoy works well, but due to the nature of TCP, very little metadata useful for routing can be propagated via the TCP protocol itself. Using the HTTP CONNECT verb however, it is possible to instruct a proxy to tunnel the subsequent data as raw TCP to some target without interpreting it as http or some other L7 protocol. The way it works is listed below:
- A caller A wants to send some TCP traffic to a service B.
- The caller A calls some proxy P by making an HTTP request with the following header: CONNECT http://<address_of_B>[:port] HTTP/1.1
- The proxy P opens a TCP connection to the address and the optional port, and keeps the connection from A open.
- The caller A then uses its connection to P to stream the TCP payload it needs to send to B. P relays this traffic to B.
static_resources: listeners: - name: listener_0 address: socket_address: { address: 127.0.0.1, port_value: 10000 } filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http codec_type: AUTO route_config: name: local_route virtual_hosts: - name: connect_tcp domains: ["fubar.xyz:1234"] routes: - match: { headers: [{name: ":authority", suffix_match: ":1234"}], connect_matcher: {} } route: { cluster: ssh, upgrade_configs: [{upgrade_type: "CONNECT", connect_config: {}}] } - match: { prefix: "/" } route: { cluster: ssh } - name: local_service domains: ["*"] routes: - match: { prefix: "/" } route: { cluster: ssh } http_filters: - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router upgrade_configs: - upgrade_type: CONNECT http2_protocol_options: allow_connect: true - name: listener_1 address: socket_address: { address: 127.0.0.1, port_value: 9000 } filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http codec_type: AUTO route_config: name: local_route1 virtual_hosts: - name: connect_fwd domains: ["fubar.xyz", "fubar.xyz:*"] routes: - match: { connect_matcher: {} } #### route: { cluster: conti, upgrade_configs: [{upgrade_type: "websocket"}]} route: { cluster: conti, timeout: "0s"} - match: { prefix: "/" } route: { cluster: conti1 } - name: local_service domains: ["*"] routes: - match: { prefix: "/" } route: { cluster: conti1 } http_filters: - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router upgrade_configs: - upgrade_type: CONNECT http2_protocol_options: allow_connect: true clusters: - name: ssh connect_timeout: 0.25s type: STATIC lb_policy: ROUND_ROBIN load_assignment: cluster_name: ssh endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 22 - name: conti connect_timeout: 0.25s type: STATIC lb_policy: ROUND_ROBIN load_assignment: cluster_name: conti endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 10000 - name: conti1 connect_timeout: 0.25s type: STATIC lb_policy: ROUND_ROBIN load_assignment: cluster_name: conti endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 8000
Read more!