標準機能
このセクションでは、HAProxyで非常によく使われるものの、ほかのロードバランサーに必ずしも備わっているとは限らない機能を紹介します。
3.4.1. 標準機能:情報の取得と変換
HAProxyは、多数の「サンプル取得関数」による情報の取得をサポートします。サンプルと呼ばれる個々の情報を取り出し、その場で利用する仕組みです。スティッキネス、条件の構築、ログ情報の生成、HTTPヘッダーへの情報追加などに使われます。
サンプルは、さまざまな情報源から取得できます。
-
定数:整数、文字列、IPアドレス、バイナリブロック。
-
プロセス:日付、環境変数、サーバー・フロントエンド・バックエンド・プロセスの状態、バイト数・接続数とそのレート、キューの長さ、乱数生成器など。
-
変数:セッションごと、リクエストごと、レスポンスごとの変数。
-
クライアント接続:送信元・宛先のアドレスとポート、および関連するすべての統計カウンター。
-
SSLクライアントセッション:プロトコル、バージョン、アルゴリズム、暗号方式、鍵の長さ、セッションID、クライアント・サーバー証明書のすべてのフィールド、証明書のシリアル番号、SNI、ALPN、NPN、特定の拡張に対するクライアントの対応状況。
-
リクエスト・レスポンスバッファーの内容:オフセットと長さで指定した任意のペイロード、データ長、RDP Cookie、SSL helloの種類のデコード、TLS SNIのデコード。
-
HTTP(リクエストとレスポンス):メソッド、URI、パス、クエリー文字列の引数、ステータスコード、ヘッダーの値、位置を指定したヘッダーの値、Cookie、取得値、認証、ボディーの要素。
取得したサンプルは、「コンバーター」と呼ばれる一連の演算子を通して変換できます。コンバーターはサンプルを受け取り、新しいサンプルを返します。型がまったく異なることもあります。たとえば、入力文字列の長さだけを整数として返したり、文字列を大文字に変換したりできます。最終的に使う前に、任意の数のコンバーターを順に適用できます。利用可能なサンプルコンバーターのうち、よく使われるものは次のとおりです。
-
算術・論理演算子:比率や百分率の計算、単位変換など、入力データに対する高度な計算ができます。
-
IPアドレスマスク:アドレスをより大きなネットワーク単位でまとめたい場合に便利です。
-
データ表現:URLデコード、base64、16進数、JSON文字列、ハッシュ。
-
文字列変換:固定位置・固定長の部分文字列の抽出、特定の区切り文字で分けられたフィールドの抽出、特定の単語の抽出、大文字・小文字の変換、正規表現による置換。
-
日付変換:HTTP日付形式への変換、ローカル時刻とUTCの相互変換、オフセットの加減算。
-
スティックテーブルのエントリーを検索し、統計や割り当てられたサーバーを取得する。
-
ファイルを使った、マップによるキーから値への変換(主に位置情報の判定に使われます)。
3.4.2. 標準機能:マップ
マップは強力なコンバーターの一種です。起動時に二列のファイルをメモリへ読み込み、入力サンプルを一列目で検索し、見つかれば二列目の対応するパターンを、見つからなければデフォルト値を返します。出力もサンプルなので、さらに別のマップ検索を含む変換を適用できます。マップはネットワークアドレスの最長一致をサポートするため、クライアントのIPアドレスをAS番号や国コードへ変換する用途が最も一般的ですが、ほかにもさまざまな用途に使えます。
強みの一つは、CLIや、ほかのサンプルを使う特定のアクションから、稼働中に更新できることです。これにより、アクセス間で情報を保存・取得できます。もう一つは、二分木による索引で、数十万件のエントリーがあっても極めて高速に検索できることです。位置情報の判定を低コストで簡単に導入できます。
3.4.3. 標準機能:ACLと条件
HAProxyのほとんどの操作には、条件を付けられます。条件は、複数のACLを論理演算子(AND、OR、NOT)で組み合わせて構築します。各ACLは、次の要素に基づく一連のテストです。
-
テスト対象の要素を取得するサンプル取得メソッド。
-
要素を変換する、任意の一連のコンバーター。
-
照合するパターンのリスト。
-
パターンとサンプルの比較方法を指定する照合メソッド。
たとえば、HTTPの"Host"ヘッダーからサンプルを取得し、小文字に変換してから、正規表現による照合メソッドで複数の正規表現パターンと比較できます。
技術的には、ACLはマップと同じ基盤で構築されており、内部構造、パターン照合メソッド、性能はまったく同じです。実質的な違いは、サンプルを返す代わりに、「見つかった」か「見つからなかった」だけを返すことです。使い方の面では、ACLパターンは設定ファイル内に直接記述でき、専用のファイルは不要です。使いやすさや設定の分かりやすさのために、ACLに名前を付けることもできます。名前付きACLは複数回定義でき、どれかに一致するまで、すべての定義を順に評価します。
IPアドレスマスク、整数範囲、部分文字列、正規表現など、約13種類のパターン照合メソッドがあります。関数のように動作し、プログラミング言語と同様に、必要なものだけを評価します。そのため、ORを含む条件がすでに真なら後続は評価せず、ANDを含む条件がすでに偽なら残りの条件を評価しません。
定義できるACLの数に実用上の制限はなく、よく使うものがいくつかあらかじめ用意されています。ただし経験上、名前付きACLを多用する構成はトラブルシューティングがかなり難しく、場合によっては、匿名ACLをその場に記述したほうが簡単です。調べている範囲の外を参照する回数を減らせるためです。
3.4.4. 標準機能:内容に基づく振り分け
HAProxyは、内容に基づく振り分けの仕組みを実装しています。接続やリクエストがフロントエンドへ届くと、それに含まれる情報を処理します。その情報を使うACL条件を記述して、リクエストを処理するバックエンドを決められます。つまり、リクエストの内容に応じて、いずれかのバックエンドへトラフィックを送ります。最も一般的な例は、Hostヘッダーやパスの要素(サブディレクトリやファイル拡張子)から、HTTPリクエストの対象が静的オブジェクトかアプリケーションかを判断するものです。静的オブジェクトへのトラフィックは高速で軽量なサーバー群のバックエンドへ、それ以外はより複雑なアプリケーションサーバーへ送り、きめ細かな仮想ホスティングを実現します。複数の技術を全体的なソリューションとして共存させるのに便利です。
別の用途は、さまざまな条件に応じて異なる負荷分散アルゴリズムを使うことです。キャッシュにはURIハッシュを使い、アプリケーションにはラウンドロビンを使う、といった構成が可能です。
また、バックエンドごと、つまり顧客ごとに接続数を制限することで、複数の顧客が共通のリソースを少しずつ利用できるようにします。
内容に基づく振り分けルールは非常によく拡張できますが、性能は使用するACLの数や複雑さに左右される場合があります。ACLを一切使わず、サンプル値を直接バックエンド名に変換する動的な振り分けルールも記述できます。このような構成は、本番環境で少なくとも300000のバックエンドを扱い、正常に動作したと報告されています。
3.4.5. 標準機能:スティックテーブル
スティックテーブルは、通常、スティッキネス情報の保存に使われます。つまり、特定の訪問者が送られたサーバーへの参照を保持します。キーは訪問者に関連する識別子(送信元アドレス、接続のSSL ID、HTTPまたはRDP Cookie、URLやペイロードから抽出した顧客番号など)で、保存する値はサーバーの識別子です。
スティックテーブルのキーには、整数、文字列、アドレスの3種類のサンプルを使えます。一つのプロキシで参照できるスティックテーブルは一つだけで、どこでもプロキシ名で指定します。最大8個のキーを並行して追跡できます。キーとサーバーの両方が判明した時点で、リクエストまたはレスポンスの処理中にサーバー識別子を確定します。
スティックテーブルの内容は、“peers"と呼ばれるほかのHAProxyノードへアクティブ・アクティブ方式で複製でき、リロード時の新しいプロセスにも引き継げます。これにより、すべての負荷分散ノードで同じ情報を共有し、クライアントのリクエストが複数ノードに分散しても、同じルーティング判断ができます。
スティックテーブルは、クライアントを識別できる情報をキーにするため、クライアントごとの統計など、追加情報の保存にもよく使われます。追加の統計には余分な領域が必要で、明示的に宣言しなければなりません。保存できる統計には、入出力帯域幅、同時接続数、一定期間の接続レートと件数、エラーの数と頻度、特定のタグやカウンターなどがあります。特定のサーバーへ固定せずにこれらの情報を保持できるよう、特別な「追跡」機能を実装しています。スティッキー処理ルールに関係なく、異なるテーブルの最大3個のキーを同時に追跡できます。保存した各統計は、CLIから検索、ダンプ、クリアでき、稼働中のトラブルシューティングに役立ちます。
この仕組みは、再訪問者を優遇したり、利用者の行動の良し悪しに応じてサービス品質を調整したりするためにも使えますが、主な用途はサービスの不正利用や、より広くDDoSへの対策です。特定の不正な行動を高速に検出する複雑なモデルを構築できます。
3.4.6. 標準機能:書式付き文字列
HAProxyでは、ログ、リダイレクト、ヘッダーの追加など、さまざまな箇所で文字列を操作します。柔軟性を最大限に高めるため、書式付き文字列という概念を導入しました。当初はログ用に導入されたため、今でも"log-format"と呼ばれています。これらの文字列にはエスケープ文字が含まれ、変数やサンプル取得式など、さまざまな動的データを埋め込めます。また、結果を文字列に変換する際に、引用符を付けるなど、エンコード方法を調整することもできます。ヘッダーの内容、レスポンスデータ、レスポンステンプレートの構築や、ログ行のカスタマイズに使える強力な仕組みです。さらに、よく使う文字列を簡単に組み立てられるよう、ログで頻繁に使う情報の省略表現として、約50個の特別なタグを提供しています。
3.4.7. 標準機能:HTTPの書き換えとリダイレクト
ロードバランサーを前提に設計されていないアプリケーションの前段へロードバランサーを配置することは、適切なツールがなければ難しい作業です。この場合によく求められるのは、リクエストとレスポンスのヘッダーを調整し、ロードバランサーをオリジンサーバーとして見せ、固定された情報を修正することです。これには、リクエストのパスの変更(強く非推奨)、Hostヘッダーフィールドの変更、リダイレクト用のLocationレスポンスヘッダーフィールドの変更、Cookieのpath属性・domain属性の変更などが含まれます。また、サーバーによってはレスポンスで過剰な情報を公開し、標的型の攻撃に対して脆弱になることがあります。理論的には、これを取り除くのはロードバランサーの役割ではありませんが、実際には、すべてを確実に取り除くのに最も適した位置にあります。
同様に、ロードバランサーが一部のリクエストを捕捉し、新しい宛先URLへのリダイレクトで応答する必要がある場合もあります。リダイレクトと書き換えは混同されがちですが、まったく異なる概念です。書き換えではクライアントとサーバーが異なるものを見ることになり、訪問中のページの場所について認識が食い違います。一方、リダイレクトではクライアントに新しいURLへのアクセスを求めるため、サーバーと同じ場所を見ることになります。
このために、HAProxyはさまざまな書き換え・リダイレクト機能をサポートします。
-
正規表現による、リクエスト・レスポンス内のURLとヘッダーの書き換え。正規表現は扱いやすく、よく理解されているため、ヘッダー値の変更に最もよく使われる手段です。
-
書式付き文字列に基づくヘッダーの追加、削除、置換。たとえば、クライアント側のTLSアルゴリズムや暗号方式などの情報をヘッダーで渡せます。
-
任意の3xxコードを使った、相対URI、絶対URI、完全に動的なURI(書式付き文字列)へのHTTPリダイレクト。
-
特定のCookieの設定・削除、クエリー文字列の除去、末尾にスラッシュがない場合の追加など、HTTPリダイレクトの追加オプション。
-
強力な"return"ディレクティブ。動的な内容やテンプレートファイルを使い、ステータス、ヘッダー、ボディーなど、レスポンスのすべての部分をカスタマイズできます。
-
すべての操作で、ACLによる条件をサポートします。
3.4.8. 標準機能:サーバー保護
HAProxyは、サービスの可用性を最大化するため、サーバーを過負荷や攻撃から保護することに力を入れています。まず最も重要なのは、完全で正しいリクエストだけをサーバーへ転送することです。第一の理由は、バイトストリームとの同期を保つために必要なプロトコル要素を、HAProxyが見つける必要があるためです。第二の理由は、リクエストが完成するまで、その意味を変える要素が含まれるか分からないためです。直接の利点は、サーバーが不正・不完全なリクエストにさらされないことです。これはslowloris攻撃に非常に有効で、この攻撃はHAProxyにほとんど影響を与えません。
もう一つ重要なのは、HAProxyがリクエストとレスポンスを保存するバッファーを備えていることです。リクエストが完全になってからサーバーへ送り、ローカルネットワークからレスポンス全体を素早く読み取るため、サーバー側の接続を使う時間が非常に短くなり、サーバーのリソースをできるだけ節約できます。
この延長として、HAProxyはサーバーへの同時接続数や未完了のリクエスト数に制限をかけられます。トラフィックの急増時に処理能力の100%で動き続けても、サーバーが過負荷にならないことを保証します。超過したリクエストはキューに入り、空き枠ができたときに処理されます。この大きなリソース節約により、サーバーのレスポンス時間が十分に改善し、結果として過負荷にした場合より速くなることがほとんどです。キュー内のリクエストは、ほかのサーバーへ再配分でき、クライアントが中断した場合はキュー内で中断することもできます。これにより、「再読み込みの影響」からもサーバーを保護します。読み込みの遅いページで訪問者が「再読み込み」を押すたびに、通常は新しいリクエストが発生し、サーバーの過負荷状態が続いてしまう現象です。
slow-startの仕組みは、再起動中のサーバーがまだ起動処理を終えていなかったり、クラスをコンパイルしていたりする間に、大量のトラフィックが届くことも防ぎます。
プロトコルレベルの保護では、HTTPパーサーの制約を緩め、標準に準拠していなくても無害なリクエストやレスポンスを受け入れ、修正することもできます。これにより、修正の開発中も、不具合のあるアプリケーションを利用できます。同時に、問題のあるメッセージは詳細なレポートとともに完全に取得され、開発者がアプリケーションの問題を見つけるのに役立ちます。最も危険なプロトコル違反は、適切に検出し、対処・修正します。たとえば、Content-lengthヘッダーが二つある不正なリクエストやレスポンスは、値が完全に同じなら修正し、異なるならセキュリティ上の問題となるため拒否します。プロトコル検査はHTTPに限らず、TLSやRDPなどにも利用できます。
プロトコル違反や攻撃を検出した際の応答には、一般的な"HTTP 400 bad request"を返す、TCPリセットで接続を閉じる、長く待たせてからエラーを返したように見せて攻撃者を混乱させる(“tarpit”)など、さまざまな選択肢があります。いずれも、攻撃の継続コストを高めて攻撃元のクライアントに断念させ、サーバーの保護に役立ちます。
HAProxyは、偶発的なデータ漏えいやセッションの混在を防ぐ、さらに高度なオプションも提供します。疑わしいサーバーレスポンスを記録するだけでなく、訪問者の機密性に影響し得るレスポンスを記録し、必要に応じてブロックします。その一例が、キャッシュ可能なレスポンスにキャッシュ可能なCookieが含まれる場合です。中間キャッシュが別の訪問者へそれを渡してしまい、意図せずセッションが共有される可能性があります。