EnvoyのCONNECTプロキシ機能

envoyの HTTPアップグレード機能は、WebSocketとHTTP CONNECTメソッドをサポートしています。
CONNECTを使うとTCP通信をトンネルできます。

また、SNIに対応したクライアントであれば、単一のenvoyで複数TCPサービスをホストするプロキシを構築できます。

設定

configサンプルの通り、HttpConnectionManagerの設定によりCONNECTメソッドを有効にできます。

     - 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
         route_config:
           name: local_route
           virtual_hosts:
           - name: local_service
             domains: ["*"]
             routes:
             - match:
                 connect_matcher: {}
               route:
                 cluster: backend_tcp
                 upgrade_configs:
                 - upgrade_type: CONNECT
                   connect_config: {}
         http_filters:
         - name: envoy.filters.http.router
           typed_config:
             "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
         http_protocol_options: {}
         http2_protocol_options:
           allow_connect: true
         upgrade_configs:
         - upgrade_type: CONNECT

upgrade_configsroute.upgrade_configsなどをセットで指定する必要があります。
http_protocol_options: {}などところどころで空のオブジェクトを指定していますが、これはデフォルト値が設定されるため効いています。

バックエンドクラスタの設定には、特殊な点はありません。
確認していませんが、 Basic認証なども追加できるでしょう。

Proxy Protocol

アップストリームにProxy Protocolを送りたい場合は、connect_configの設定を変更します。

                route:
                  upgrade_configs:
                  - upgrade_type: CONNECT
                    connect_config:
                      proxy_protocol_config:
                        version: V1

フロントエンドの対応も必要

HTTP CONNECTメソッドはGET/POSTのように一般的なメソッドではないため、フロントエンドのプロキシが対応していないケースがあるため注意が必要です。
GCPの例では、HTTPSロードバランサ(従来)はCONNECTに対してダイレクトにHTTP405エラーを返します。TCPロードバランサであればenvoyが直接受信するため動作します。

クライアントの例

CONNECTメソッドを用いてトンネルするクライアントはいくつか実装があります。
proxytunnelはSSLやSNIをサポートし、verboseオプションが比較的詳細にレポートします。

sshのconfig設定例は以下のようになります。

Host ssh.example.com
User someone
Port 443
ProxyCommand proxytunnel -E -p ssh.example.com:443 -d %h:%p

なお、envoyのconnect_matcherがポートをルーティングに用いているため、httpsのデフォルトポートであっても443は省略しない方が無難でしょう。

中馬崇尋
Chuma Takahiro