Documentation

4. プロキシーのサポート

プロキシーサーバーは、リソースを別のサーバーから求めているクライアントが出した要求を仲介する役割を果たします。クライアントは、プロキシーサーバーに接続して、別のサーバーからサービスや利用可能なリソースを要求します。そして、このプロキシーサーバーは複雑な内容を簡素化して制御する方法の 1 つとして、その要求を評価します。

注釈

SSL オフロード、または Tower 向けの SSL を処理するプロキシーの使用はサポートされています。プロキシー/ロードバランサーはリモートのホスト情報を渡すように設定しておく必要があります。

SSL をロードバランサーまたはプロキシーにオフロードする場合は、nginx_disable_https=true を追加変数として設定して、設定 Playbook に渡す必要があります。設定 Playbook に追加変数を適用する方法は「Playbook の設定」を参照してください。

Tower のセッションは、作成時に IP アドレスと関連付けられます。Tower ポリシーでは、セッションを使用する場合には、セッションと、元に関連付けられた IP アドレスと一致することが要件となっています。

Tower の設定 (/etc/tower/conf.d/remote_host_headers.py) の REMOTE_HOST_HEADERS のリスト変数を使用して (Tower の前部の ALB、NLB、HAProxy、Squid、Nginx、tinyproxy など)、プロキシー化された要求を Tower が処理して、プロキシーサーバーをサポートします。デフォルトでは、REMOTE_HOST_HEADERS['REMOTE_ADDR', 'REMOTE_HOST'] に設定されています。

プロキシーサーバーのサポートを有効にするには、REMOTE_HOST_HEADERSREMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', 'REMOTE_HOST'] のように設定します。

注釈

Ansible Tower の新規インストールには、remote_host_headers.py ファイルが含まれていませんが、Tower の設定ユーザーインターフェースのシステム設定でこれらの値を設定できます。

_images/configure-tower-system.png

Tower はリモートホストの IP アドレスを判断するために、最初の IP アドレスが特定されるまで、REMOTE_HOST_HEADERS のヘッダー一覧を検索します。

注釈

ヘッダー名は、以下のロジックを使用して作成されます。

CONTENT_LENGTHCONTENT_TYPE の例外を除いて、要求内の HTTP ヘッダーは META キーに変換されます。これは、すべての文字を大文字に変換して、ハイフンはアンダースコアに置き換え、名前に HTTP_ のプリフィックスを追加することで変換されます。たとえば、X-Barkley と呼ばれるヘッダーは META キー HTTP_X_Barkley にマッピングされます。

HTTP 要求および応答オブジェクトに関する情報は、https://docs.djangoproject.com/en/1.8/ref/request-response/#django.http.HttpRequest.META を参照してください。

注釈

ロードバランサーで SSL 中断を使用して、Tower ノードの別のポート (443 -> 80) にトラフィックを転送する場合は /etc/tower/conf.d/custom.py ファイルに適切に以下の値を設定します。

USE_X_FORWARDED_PORT = True
USE_X_FORWARDED_HOST = True

4.1. 既知のプロキシーの設定

Tower が REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', 'REMOTE_HOST'] で設定された場合には、X-Forwarded-For の値は Tower の前にあるプロキシー/ロードバランサーから取得していると想定されます。Tower にプロキシー/ロードバランサーを使用せずに到達できる場合や、プロキシーがヘッダーを検証しない場合には、X-Forwarded-For は比較的簡単になりすましを行い、送信元の IP アドレスを偽造することができます。REMOTE_HOST_HEADERS 設定で HTTP_X_FORWARDED_FOR を使用すると、アクセスすべきでない特定のリソースにも基本的にアクセス権を与えるので、攻撃を受けやすくなります。

これを回避するには、許可済みの「既知のプロキシー」を設定してください。これは、設定 API 経由で PROXY_IP_ALLOWED_LIST 設定で行います。この一覧に記載されていないロードバランサーやホストは拒否要求に追加されることになります。

PROXY_IP_ALLOWED_LIST は、この一覧のプロキシーが正しくヘッダー入力をサニタイズし、X-Forwarded-For の値をクライアントの実際のソース IP と同等に正しく設定した場合にのみ機能します。この設定で重要な点は、Tower が PROXY_IP_ALLOWED_LIST 内の IP/ホスト名に依存して、X-Forwarded-For フィールドに攻撃を受けない値を指定することができる点です。

HTTP_X_FORWARDED_FOR は、以下の点が満たされていない限り、REMOTE_HOST_HEADERS の項目として設定 しない ようにしてください。

  • SSL Termination でプロキシー環境を使用している

  • プロキシーにより X-Forwarded-For ヘッダーのサニタイズおよび検証が行われクライアントの攻撃を防止することができる

  • /etc/tower/conf.d/remote_host_headers.py は、信頼されたプロキシー/ロードバランサーの送信元 IP のみを含む PROXY_IP_ALLOWED_LIST を定義する

注釈

すべてのトラフィックをプロキシー経由とする必要がない場合には、no_proxy フィールドで除外する IP スキームを指定できます。一覧は、IP の範囲、個別の IP をコンマ区切りで指定できます。この例では、JSON 形式の IP を指定しています。

"https_proxy": "example.proxy.com:8080",
"http_proxy": "example.proxy.com:8080",
"no_proxy": "10.0.0.0/8"

また、SCM が no_proxy 設定で更新された場合は、CIDR 表記が特定の SCM で機能しない可能性があります。http_proxy および no_proxy のサポートは、アプリケーション (git|hg|svn) の実装により異なります。たとえば、git は C ライブラリーによる制約があるため no_proxy の CIDR 表記をサポートしません (https://curl.haxx.se/libcurl/c/CURLOPT_NOPROXY.html)。

4.2. リバースプロキシー

リバースプロキシーの背後に環境がある場合には、HTTP_X_FORWARDED_FOR のヘッダーフィールドを設定するようにしてください。X-Forwarded-For (XFF) HTTP ヘッダーフィールドで、HTTP プロキシーまたはロードバランサー経由で Web サーバーに接続するクライアントの送信元 IP アドレスを指定します。

REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', 'REMOTE_HOST']

4.3. Websocket の設定

Websocket の設定を nginx/ロードバランサーの設定に合わせるために考慮すべき主な設定に、websocket の設定があります。

Tower ノードは、WebSocket を介して他のすべての Tower ノードに接続します。この相互接続は、すべての WebSocket が発信したメッセージを他のすべての Tower ノードに配信するために使用されます。これは、任意のブラウザークライアント WebSocket が、任意の Tower ノードで実行している可能性がある任意のジョブにサブスクライブできるために必要です。つまり、WebSocket クライアントは特定の Tower ノードにルーティングされません。任意の Tower ノードは、任意の WebSocket リクエストを処理できます。したがって、各 Tower ノードは、すべてのクライアントに向けたすべての WebSocket メッセージを認識している必要があります。

データベース内のインスタンスレコードから他の Tower ノードの検出を自動的に処理します。Tower は、ポート、プロトコルに、websocket 接続の確立時に証明書を検証するかどうかを指示します。これは以下の 3 つの設定を使用して設定されます。

BROADCAST_WEBSOCKET_PROTOCOL = 'http'
BROADCAST_WEBSOCKET_PORT = 80
BROADCAST_WEBSOCKET_VERIFY_CERT = False

たとえば、Tower 前でロードバランサーレベルで SSL 終了を行うトポロジーには、次の設定があります。

BROADCAST_WEBSOCKET_PROTOCOL = 'http'
BROADCAST_WEBSOCKET_PORT = 80

nginx を介して各 Tower ノードで SSL を実行するトポロジーには、以下の設定があります。

BROADCAST_WEBSOCKET_PROTOCOL = 'https'
BROADCAST_WEBSOCKET_PORT = 443
BROADCAST_WEBSOCKET_VERIFY_CERT = True

注釈

ノードがプライベートで信頼されるサブネット (オープンインターネット以外) に Websocket トラフィックをブロードキャストしていることが意図されています。そのため、websocket ブロードキャストの HTTPS をオフにすると (Ansible Playbook の標準出力 (stdout) のほとんどを構成する)、websocket トラフィックは暗号化されずに Tower ノード間で送信されます。