適切な HAProxy SNI ベースのルーティングには、なぜ「tcp-request content accept」フロントエンド命令が必要なのですか?

適切な HAProxy SNI ベースのルーティングには、なぜ「tcp-request content accept」フロントエンド命令が必要なのですか?

mongodb+srv最近、mongodbプロトコル接続用に HAProxy で SNI ベースのルーティングを設定しようとしました。

私はそれを動作させましたが、

tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }

フロントエンドの設定で正常に動作するようになった

これらがなければ(またはたった1つでこれらのうち、約 70% のリクエストで散発的に接続がリセットされ続けました。ただし、接続が確立されることもありました。

によるとhttp://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4-tcp-request%20content

コンテンツベースのルールは、宣言された順序どおりに評価されます。一致するルールがない場合、またはルールがない場合、デフォルトのアクションはコンテンツを受け入れることです。挿入できるルールの数に特定の制限はありません。

したがって、デフォルトで動作するはずでした。

基本的な TCP 概念か、Mongo の特定の接続の詳細が欠けているのかもしれません。しかし、SNI ベースのルーティングを選択する場合、ほぼすべての人が同じルールを定義していることに気付きました。そのため、ほとんどの人にとっては意味があるはずです。

動作する HAProxy 構成:

    frontend fe_mongo-nonprod
      bind :27017
      tcp-request inspect-delay 5s
      tcp-request content accept if { req_ssl_hello_type 1 }

      acl mongoAtlas-01 req_ssl_sni -i host1.mongodb.net
      acl mongoAtlas-02 req_ssl_sni -i host2.mongodb.net
      acl mongoAtlas-03 req_ssl_sni -i host3.mongodb.net
      use_backend be_mongo-nonprod if mongoAtlas-01 || mongoAtlas-02 || mongoAtlas-03

    backend be_mongo-nonprod
      mode tcp

      acl mongoAtlas-01 req_ssl_sni -i host1.mongodb.net
      acl mongoAtlas-02 req_ssl_sni -i host2.mongodb.net
      acl mongoAtlas-03 req_ssl_sni -i host3.mongodb.net

      use-server server-01 if mongoAtlas-01
      use-server server-02 if mongoAtlas-02
      use-server server-03 if mongoAtlas-03

      server server-01 host1.mongodb.net:27017
      server server-02 host2.mongodb.net:27017
      server server-03 host3.mongodb.net:27017

また、HAProxy は Kubernetes (GCP 内の Google 管理クラスタ) にデプロイされ、istio-sidecar を持ち、Internal LoadBalancer k8s サービスを介して公開されていることも言及する価値があります。

前述のとおり、上記の設定は完全に正常に動作します。私が興味を持っているのは、なぜtcp-request content acceptが絶対に必要なのか、そしてなぜここでは接続がデフォルトで [常に] 受け入れられないのかということです。

答え1

少し考えてから、自分自身の質問に答えてみようと思います。

したがって、HAProxy のドキュメントには次のような記述もあります。 http://cbonte.github.io/haproxy-dconv/2.0/configuration.html

コンテンツの切り替えが必要な場合は、以下の例のように、まず完全なクライアント ハロー (タイプ 1) を待機することをお勧めします。

さて、SNIデータはリクエストのClient Helloセクションにも含まれているので(https://www.rfc-editor.org/rfc/rfc6066#page-6) 私の仮定は次のとおりです。

Client Hello が複数の TCP パケットに分散していて、 がない場合tcp-request content accept is configured、最初のパケットを受信すると、HAProxy はそれをルーティングしようとし、次の 2 つのいずれかが発生します。

  1. デフォルトのバックエンドが設定されている場合、パケットはこのバックエンドに転送されます。
  2. デフォルトのバックエンドが設定されていない場合 (私の場合)、パケットはドロップされ、接続がリセットされます。

また、最初に説明したケースでも、バックエンド セクションで HAProxy が指すサーバーには SNI が必要な場合があることにも注意してください。そのため、SNI 表示のない不完全なリクエストを転送すると、接続がリセットされることになります。

関連情報