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!