・はじめに
こんにちは。VMware グローバルサポート NSX チームの柴原です。
今回の Blog では NSX Advanced Load balancer (以下、NSX ALB) にて HTTP/2 を有効化する際の注意点ついて事例を含めてご案内します。NSX ALB にて HTTP/2 の利用を検討されている方や既に HTTP/2 を使用されている方の運用のお役に立てれば幸いです。
・HTTP/2 について
まずは事例の紹介に入る前に、HTTP/2 の概要について簡単に触れたいと思います。ご存じの方も多いかと思いますが、HTTP/2 は現在 Web サービスで一般的に利用されている HTTP/1.1 の後継にあたる通信プロトコルとなり、2015 年に RFC 7540 として規格化されて以降、徐々に普及が進んでいます。
HTTP/1.1 では原則として一つの TCP コネクションに対して一つの HTTP リクエスト/ レスポンスのやり取りしか許可されておらず、都度コネクションを切断するという設計となっておりましたが、この設計では リクエストの度に 3-Way-Handshake を実行し TCP コネクションを確立しなくてはならず、パフォーマンスの問題が指摘されておりました。
なお、HTTP Keep Alive などの仕組みを利用する事で、HTTP/1.1 においても一つの TCP コネクション上で複数の HTTP リクエストを実行する事も可能ですが、HTTP/1.1 では先に実行された HTTP リクエストに対するレスポンスを受信してからでないと、次の HTTP リクエストを実行する事は出来ないためレスポンスの遅延が発生した場合には、その後の全てのリクエストの処理に影響が及ぶ事になり、この点がボトルネックとなっておりました。
HTTP/2 では TCP コネクション上に「ストリーム」とよばれる仮想的なパイプを作成し「ストリーム」内で「フレーム」と呼ばれるメッセージのやり取りを行う事で、一つの TCP コネクション上で複数の HTTP リクエストを並列に処理(多重化)する事ができるようになりました。またフレームのやり取りについては非同期となっており、先に送信したリクエストに対するレスポンスが無い状態であっても次のリクエストの送信に移る事が可能です。これにより一つの TCP コネクション上で複数の HTTP リクエストを並列に実行する事が可能となっており Web アクセスの高速化を実現しています。
・ストリームによる HTTP リクエストの並列処理(イメージ)
HTTP/2 では、このようなストリームの多重化以外にもパフォ-マンスの向上につながる多くの新機能が実装されておりますので興味のある方は以下の資料をご参照いただければ幸いです。
<参考情報>
– HTTP/2 とは
https://www.nic.ad.jp/ja/newsletter/No68/0800.html
– Introduction to HTTP/2
https://web.dev/performance-http2/
・ NSX ALB の HTTP/2 サポート状況について
さて、これまでの説明で HTTP/2 の仕組みについて大まかなイメージを掴んでいただけたのではないかと思います。この章では NSX ALB における HTTP/2 のサポート状況について説明します。NSX ALB では Client – LB 間(フロントエンド)、LB – Server 間(バックエンド)のどちらの通信においても HTTP/2 をサポートしており、HTTP/2 の有効化の作業は GUI から簡単な操作で実施する事ができます。
・ HTTP/2 有効化方法
フロントエンド(Client -LB 間)側で HTTP/2 を有効化する場合には Virtual Service 上で HTTP/2 のチェックを有効化します。
CLI によるステータスの確認 (Virtual Service)
enable_http2 = true となっている事を確認します。
バックエンド(LB – Server 間)側で HTTP/2 を有効化する場合には、Pool の設定にて HTTP/2 を有効化します。
CLI によるステータス の確認(Pool)
enable_http2 = true となっている事を確認します。
このように、NSX ALB では非常に簡単な操作で HTTP/2 を有効化できる事をご理解いただけたのではないかと思います。なお、ALB を介さずに HTTP/2 を導入する際には Server 側でも HTTP/2 への対応が必須となりますが、NSX ALB では Client – LB 間(フロントエンド)でのみ HTTP/2 を使用するといった構成もサポートしておりますので、通信のボトルネックとなりやすい Client – LB 間(フロントエンド)の通信でのみ HTTP/2 を有効化し、LB – Server 間(バックエンド)はこれまで通り HTTP/1.1 を使用するといった運用も可能です。この構成をとる場合は Server 側が HTTP/2 に対応していなくても問題はありません。Server が HTTP/2 に対応しており、フロントエンド、バックエンドの両方で HTTP/2 を使用したいという場合には Virtual Service 側だけではなく Pool 側の設定でも HTTP/2 を有効化する必要がありますのでご注意ください。
・ NSX ALB で HTTP/2 を有効化する際の注意点について
HTTP/1.1 と比較するとメリットばかりあるように思える HTTP/2 ですが、その構造上の特性から DoS 攻撃をはじめとするいくつかの脆弱性が報告されており、2019 年には Netflix 社 により HTTP/2 で行われる通信に対する DoS 攻撃の可能性についてのアドバイザリが公開されております。これから HTTP/2 を導入する事を検討されている方はぜひ一度目を通していただければ幸いです。
– HTTP/2 Denial of Service Advisory
https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-002.md
また、Netflix 社から公開されたアドバイザリを受けて NSX ALB 側(旧 Avi Networks) からも以下のアドバイザリが公開されております。こちらも併せてご確認いただければ幸いです。
– HTTP/2 Denial of Service Advisory
https://avinetworks.com/docs/latest/netflix-http2-dos-advisory/
これらのアドバイザリにて注意喚起が行われている DoS 攻撃の手法は、HTTP/2 の特性である「一つ TCPコネクション上で複数のストリームを形成し並列でフレームのやり取りが行われる」という仕組みを逆手にとり、悪意ある攻撃者が複数のストリームを通じて、大量のリクエストやコントロールフレームを送信する事で通信相手のリソースの枯渇を引き起こすといった内容が含まれております。これらの攻撃は HTTP/1.1 とは異なり単一の TCP コネクション上で実行されるため、旧来の Syn フラッド攻撃 のような、通信相手に Syn パケットを大量に送信する事で Half Open のコネクションを大量に作成しリソースのオーバーフローを引き起こすといった DoS 攻撃に対する防御の仕組みでは対処が難しいという特徴があります。
一般的に Syn フラッド攻撃に対する検知のメカニズムは一定期間内に生成された TCP コネクションのうち、Half Open のコネクションが占める割合などの数値により異常の有無を判別するものが多いのですが、HTTP/2 においては既に確立された TCP コネクション内部でこれらのフラッド攻撃が実施されるため、このような検知のメカニズムでは検知をする事が出来ないのです。
このような背景があり、 NSX ALB では Default で実装されている HTTP/2 プロファイル上で、「一つの TCP コネクション内で実行可能なリクエストの数やコントロールフレームの数」に上限が設けられております。HTTP/2 のデータ通信中にこれらのカウンタの上限に達した場合には Virtual Service 上で 通信が遮断されるという挙動となりますので注意が必要となります。
以下に記載する HTTP/2 プロファイルの項目は、報告された脆弱性(CVE)に対応するために実行可能なフレーム数の上限が設定されておりますので、こちらもご確認ください。
・max_http2_control_frames_per_connection
クライアントが HTTP/2 接続を介して送信できるコントロールフレームの最大数となります。Ping Flood (CVE-2019-9512) 、Reset Flood (CVE-2019-9514)、Setting Flood (CVE-2019-9515)、リソースループ問題 (CVE-2019-9513) の検出に使用されます。 範囲は 0〜10,000 で、デフォルトは 1,000 です。 クライアント側の HTTP/2 接続でコントロールフレームの数が制限されないことを示すには 0 を使用します。
・max_http2_queued_frames_to_client_per_connection
クライアント側の HTTP/2 接続を介して送信を待機する(送信キューに並べる)ことができるフレームの最大数となります。 データのドリブル (CVE-2019-9511) と内部データバッファリング (CVE-2019-9517) の検出に使用されます。範囲は 0〜10,000 で、デフォルトは 1,000です。 キューに並べることができるフレーム数に制限がないことを示すには 0 を使用します。
・max_http2_empty_data_frames_per_connection
クライアント側の HTTP/2 接続上の空のデータフレームの最大数となります。 空のデータフレームがフラッディングされていることを検出するために使用されます (CVE-2019-9518)。注:空のヘッダーフレームの場合、現在の実装では接続が閉じられ、次のエラーが報告されます。HTTP2 フレームサイズエラー:クライアントが空のヘッダーブロックを含む HEADERS フレームを送信しました。範囲は 0〜10,000 で、デフォルトは 1,000 です。 空のフレームに制限がないことを示すには 0 を使用します。
これらの HTTP/2 プロファイルの設定値については ALB コントローラ上の Shell(Avi shell) から以下のコマンドにて確認する事ができます。
>shell
> show applicationprofile <applicationprofile-Name> ※<|grep http2>
実行例)
このような HTTP/2 に関する制限については、一般的な Web ブラウジングの範囲においてはカウンタの上限に達してしまう事は稀なのですが、通信の内容やアプリケーションの仕様によってはこれらのカウンタの上限を超えてしまう事があるため、通信が遮断される可能性があります。そのため HTTP/2 プロファイル 内に設定されている上限値については環境に合わせた値にチューニング(数値の拡張)が必要となりますのでご注意ください。
・事例紹介
さて、これまでに HTTP/2 の概要と、その脆弱性に関するアドバイザリの内容をもとに、NSX ALB の HTTP/2 プロファイル では「一つの TCP コネクション上で実行可能なフレームやリクエストの数に上限が設けられている事」を説明しました。この章では実際に HTTP/2 を使用した環境でデータ転送に問題が発生したというケースを紹介します。
<確認された事象>
Virtual Service 上で HTTP/2 を有効化している環境で、サイズの大きなファイル(4GB を超える ova ファイルなど)をダウンロードした際に、ファイルのダウンロードに失敗する事象が発生。クライアント端末のブラウザ上では 2.1 GB までデータのダウンロードが進んだタイミングで TCP セッションが切断されている状況が確認されていた。
この事例では、ALB の Virtual Service を経由した通信において、2.1 GB を超えるデータの転送に失敗するという事象が確認されておりました。ダウンロード中のファイルが特定のサイズに達したところでデータ転送が中断される事から、ALB 側で何らかのデータ転送サイズの制限が行われる可能性が疑われておりましたが、ALB 上では該当する設定が特定できず調査に行き詰っている状況となっておりました。
その後の切り分け作業において Virtual Service に紐づくアプリケーションプロファイルを 「Layer 7」から 「Layer 4 」に切り替えたところ事象が改善される事が判明し、Virtual Service に紐づけられている アプリケーションプロファイルに焦点を絞り調査を進めた結果、Virtual Service 上で HTTP/2 が有効化されている環境でのみこの事象が発生する事が分かりました。
なお、補足となりますが、このように初期の切り分け作業において、Virtual Service に紐づくアプリケーションプロファイルを 「L7 レベル」から「 L4 レベル」に切り替えるという作業は、「L7 レベル」のアプリケーションプロファイルの影響有無を判断するという意味で非常に有効な切り分け作業となります。この作業においては、 Virtual Service や Service Engine の再起動は不要となっており、変更後のアプリケーションプロファイルの内容は新規コネクションに対してのみ適用されるという動作となります。そのため既に確立されている TCP コネクションへの影響はないため、稼働中のサービスへの影響が少ない切り分け作業となりますので、トラブル発生時の切り分け作業としてぜひご活用いただければと思います。
NSX ALB のアプリケーションプロファイルの詳細については以下のドキュメントをご参照ください。
Application Profile
https://avinetworks.com/docs/latest/application-profile/
・事象発生原因の分析
HTTP/2 を無効化した環境では事象が解消された事から HTTP/2 プロファイル内 のパラメータの数値が影響している可能性が考えられたため各パラメータの値の変更(数値の拡張)を行いデータ転送のテストを繰り返したところ、サイズが 2.1 GB を超えるファイルのデータ転送においては、max_http2_control_frames_per_connection で定義されている「一つの TCP コネクション上で使用可能なコントロールフレームの数」の上限値に達している事が原因で Virtual Service 上でデータ転送が中断されている事が分かりました。
===
max_http2_control_frames_per_connection
クライアントが HTTP/2 接続を介して送信できるコントロールフレームの最大数。
Ping Flood (CVE-2019-9512) 、Reset Flood (CVE-2019-9514)、Setting Flood (CVE-2019-9515)、リソースループ問題 (CVE-2019-9513) の検出に使用されます。 範囲は 0〜10,000 で、デフォルトは 1,000 です。 クライアント側の HTTP/2 接続で制御フレームの数が制限されないことを示すには 0 を使用します。
===
このパラメータ は Default で上限が 1000 に設定されており、こちらは TCP コネクションにて PING_FRAME や RST_STREAM_FRAME 、 WINDOW_UPDATE FRAME 、 SETTINGS FRAME 等のコントロールフレームの実行回数の上限を定義したものとなり、通信相手にコントロールフレームを大量に送信し続ける事でリソースのオーバーフローを引き起こす Flood 攻撃に対処するための制限となっております。
一般的な Web ブラウジングなどであれば、この上限に達する事は稀なのですが、サイズの大きいファイル(2.1 GB 以上)の転送を実施した場合には、データ転送の継続に必要なコントロールフレームの数が上限値の 1000 を超えてしまう事があります。今回の事例では、 max_http2_control_frames_per_connection の値を Default の 1000 から 2000 に拡張する事で 4 GB のファイルの転送に成功する事が確認できました。
現在、こちらの Default 値については 1000 から 10000 に変更する事も検討されておりますが、現状では Default で 1000 が上限となっておりますので、HTTP/2 を使用する環境でサイズの大きいファイルの転送が頻繁に発生する事が想定される環境でしたら、この値を 2000~10000 に拡張する事をお勧めします。
・HTTP/2 パラメータの編集方法
HTTP/2 プロファイル の各パラメータの変更については、以下の方法で実施が可能です。
なお、このパラメータの変更後に Virtual Service や Service Engine などの再起動は不要となっております。また、パラメータの変更内容は新しく確立される TCP コネクションにのみ適用され、すでに確立されている TCP コネクションに対しては変更は適用されません。そのため既存の TCP コネクションへの影響はありませんが、パラメータの変更の効果が全てのコネクションに対して有効となるまでに時間がかかる事があります。
以下は、HTTP/2 のパラメータの値を Default から拡張する際の変更例となります。
max_http2_control_frames_per_connection、max_http2_queued_frames_per_connection、
max_http2_queued_frames_to_client_per_connection
などのパラメータの値を default の 1000 から 2000 に変更しています。
===
[admin:controller]: applicationprofile> http_profile <— http profile の編集モードに入る
[admin:controller]: applicationprofile:http_profile> http2_profile <— http2 profile の編集モードに入る
[admin:controller]: applicationprofile:http_profile:http2_profile> max_http2_control_frames_per_connection 2000
Overwriting the previously entered value for max_http2_control_frames_per_connection
[admin:controller]: applicationprofile:http_profile:http2_profile> max_http2_queued_frames_per_connection 2000
[admin:controller]: applicationprofile:http_profile:http2_profile> max_http2_queued_frames_to_client_per_connection 2000
Overwriting the previously entered value for max_http2_queued_frames_to_client_per_connection
[admin:controller]: applicationprofile:http_profile:http2_profile> max_http2_concurrent_streams_per_connection 256
Overwriting the previously entered value for max_http2_concurrent_streams_per_connection
[admin:controller]: applicationprofile:http_profile:http2_profile> max_http2_requests_per_connection 2500
Overwriting the previously entered value for max_http2_requests_per_connection
[admin:controller]: applicationprofile:http_profile:http2_profile> http2_initial_window_size 256
Overwriting the previously entered value for http2_initial_window_size
[admin:controller]: applicationprofile:http_profile:http2_profile> max_http2_header_field_size 8192
Overwriting the previously entered value for max_http2_header_field_size
[admin:controller]: applicationprofile:http_profile:http2_profile> save <–http2 profile の変更内容の保存
[admin:controller]: applicationprofile:http_profile> save <–http profile の変更内容の保存
[admin:controller]: applicationprofile> save <— application profile の変更内容の保存
Configure applicationprofile ap-1
・パラメータの変更
・パラメータ変更後のステータスの確認
Show applicationprofile ap-1
参照:
https://avinetworks.com/docs/latest/http-2-support/
・まとめ
今回の Blog では NSX ALB において HTTP/2 を有効化する際の注意点について説明しました。もし、HTTP/2 を有効化した環境で、Virtual Service を経由した通信に問題が発生するようでしたら、まずは HTTP/2 を無効化し事象が改善されるかをご確認ください。もし HTTP/2 の無効化で問題が改善される場合には、HTTP/2 プロファイル上の実行可能なリクエストやコントロールフレームの上限値などが影響している可能性が考えられますので、これらの値のチューニングをお試しいただけますでしょうか。
もちろん、その後も改善が見られない場合には弊社テクニカルサポートまでご相談ください。