bin/kc.[sh|bat] start --proxy-headers forwarded
分散環境では、リバースプロキシの使用が頻繁に必要になります。Keycloakは、そのような環境と安全に統合するためのいくつかのオプションを提供しています。
Keycloakはデフォルトで次のポートで実行されます
8443
(--http-enabled=true
でHTTPを明示的に有効にした場合は 8080
)
9000
ポート 8443
(または HTTP が有効な場合は 8080
) は、ホスト名の設定 (v2) ガイドで説明されているように、Admin UI、アカウントコンソール、SAMLおよびOIDCエンドポイント、およびAdmin REST APIに使用されます。
ポート 9000
は、管理インターフェースの設定 ガイドで説明されているように、ヘルスチェックとメトリクスのエンドポイントを含む管理に使用されます。
フロントエンド/バックエンドと管理に異なるホスト名を使用する場合でも、本番環境向けKeycloakの設定 で説明されているように、ポート 8443
(または 8080
) のみをプロキシする必要があります。ヘルスチェックとメトリクスはこれらのポートを直接使用し、この情報を外部の呼び出し元に公開したくないため、ポート 9000
をプロキシしないでください。
Keycloakは、いくつかの値を受け入れる proxy-headers
オプションに基づいて、リバースプロキシヘッダーを解析します。
デフォルトでは、オプションが指定されていない場合、リバースプロキシヘッダーは解析されません。これは、プロキシが使用されていない場合、またはHTTPSパススルーで使用する必要があります。
forwarded
は、RFC7239 に従って、Forwarded
ヘッダーの解析を有効にします。
xforwarded
は、X-Forwarded-For
、X-Forwarded-Proto
、X-Forwarded-Host
、および X-Forwarded-Port
などの非標準の X-Forwarded-*
ヘッダーの解析を有効にします。
HTTPSパススルー以外の目的でリバースプロキシを使用しており、proxy-headers オプションを設定しない場合、デフォルトでは、オリジンチェックを実行するプロキシ経由のリクエストに対して 403 Forbidden レスポンスが表示されます。 |
例
bin/kc.[sh|bat] start --proxy-headers forwarded
forwarded または xforwarded のいずれかが選択されている場合は、リバースプロキシが Forwarded ヘッダーまたは X-Forwarded-* ヘッダーをそれぞれ適切に設定および上書きしていることを確認してください。これらのヘッダーを設定するには、リバースプロキシのドキュメントを参照してください。HTTPSパススルーで forwarded または xforwarded を使用しないでください。誤った設定は、Keycloakをセキュリティ脆弱性にさらす可能性があります。 |
クライアントアドレスが Forwarded
ヘッダーまたは X-Forwarded-For
ヘッダーを介してリバースプロキシによって適切に設定されていることを確認するために、特別な予防措置を講じてください。このヘッダーが正しく構成されていない場合、不正なクライアントがこのヘッダーを設定し、クライアントが実際のアドレスとは異なるIPアドレスから接続されているとKeycloakに誤認させることができます。IPアドレスの拒否または許可リストを作成する場合、この予防措置はより重要になる可能性があります。
xforwarded 設定を使用する場合、X-Forwarded-Port は X-Forwarded-Host に含まれるポートよりも優先されます。 |
TLS接続がリバースプロキシ (エッジターミネーション) で終端される場合、http-enabled 設定を介してHTTPを有効にする必要があります。 |
Keycloakは、Keycloakが構成されているのと同じコンテキストパスでリバースプロキシを介して公開されていると想定しています。デフォルトでは、Keycloakはルート (/
) を介して公開されています。つまり、リバースプロキシでも /
で公開されることを期待しています。このような場合、hostname
オプションに完全なURLを使用できます。たとえば、Keycloakがリバースプロキシの /auth
で公開されている場合は、--hostname=https://my.keycloak.org/auth
を使用します。
Administration REST APIおよびコンソールを含む、異なるホスト名またはコンテキストパスでKeycloakを公開する方法の詳細については、ホスト名の設定 (v2) を参照してください。
あるいは、http-relative-path
オプションを使用して、Keycloak自体のコンテキストパスをリバースプロキシのコンテキストパスに一致するように変更することもできます。これにより、Keycloak自体のコンテキストパスがリバースプロキシで使用されるコンテキストパスに一致するように変更されます。
一般的なクラスタデプロイメントは、ロードバランサー (リバースプロキシ) とプライベートネットワーク上の2台以上のKeycloakサーバーで構成されています。パフォーマンス上の理由から、ロードバランサーが特定のブラウザセッションに関連するすべてのリクエストを同じKeycloakバックエンドノードに転送すると役立つ場合があります。
その理由は、Keycloakが現在の認証セッションとユーザーセッションに関連するデータを保存するために、Infinispan分散キャッシュを内部で使用しているためです。Infinispan分散キャッシュは、オーナーの数が制限されて構成されています。つまり、セッション関連データは一部のクラスタノードにのみ格納され、他のノードがデータにアクセスするにはリモートでデータを検索する必要があります。
たとえば、ID 123 の認証セッションが node1 の Infinispan キャッシュに保存され、node2 がこのセッションを検索する必要がある場合、特定のセッションエンティティを返すために、ネットワーク経由で node1 にリクエストを送信する必要があります。
特定のセッションエンティティが常にローカルで利用可能な場合は有益です。これは、スティッキーセッションを使用することで実現できます。パブリックフロントエンドロードバランサーと2つのバックエンドKeycloakノードを備えたクラスタ環境でのワークフローは次のようになります。
ユーザーがKeycloakログイン画面を表示するための初期リクエストを送信します。
このリクエストは、フロントエンドロードバランサーによって処理され、ランダムなノード (例: node1) に転送されます。厳密に言うと、ノードはランダムである必要はなく、他の基準 (クライアントIPアドレスなど) に従って選択できます。これはすべて、基盤となるロードバランサー (リバースプロキシ) の実装と構成によって異なります。
Keycloakは、ランダムなID (例: 123) で認証セッションを作成し、Infinispanキャッシュに保存します。
Infinispan分散キャッシュは、セッションIDのハッシュに基づいてセッションのプライマリオーナーを割り当てます。これに関する詳細については、Infinispanドキュメントを参照してください。Infinispanが node2 をこのセッションのオーナーとして割り当てたと仮定しましょう。
Keycloakは、<session-id>.<owner-node-id>
のような形式でクッキー AUTH_SESSION_ID を作成します。この例の場合、123.node2
になります。
レスポンスは、Keycloakログイン画面とブラウザの AUTH_SESSION_ID クッキーと共にユーザーに返されます。
この時点から、ロードバランサーが次のすべてのリクエストを node2 に転送すると有益です。これは、node2 が ID 123 の認証セッションのオーナーであり、Infinispan がこのセッションをローカルで検索できるためです。認証が完了すると、認証セッションはユーザーセッションに変換され、同じ ID 123 を持つため、node2 にも保存されます。
スティッキーセッションはクラスタ構成には必須ではありませんが、上記の理由からパフォーマンスに優れています。ロードバランサーが AUTH_SESSION_ID クッキーを維持するように構成する必要があります。この変更を行うための適切な手順は、ロードバランサーによって異なります。
プロキシがバックエンドノードからのクッキーを処理せずにセッションアフィニティをサポートしている場合は、ノードをクッキーにアタッチすることを避け、リバースプロキシの機能のみに依存するために、spi-sticky-session-encoder-infinispan-should-attach-route
オプションを false
に設定する必要があります。
bin/kc.[sh|bat] start --spi-sticky-session-encoder-infinispan-should-attach-route=false
デフォルトでは、spi-sticky-session-encoder-infinispan-should-attach-route
オプションの値は true
であるため、ノード名がクッキーにアタッチされ、後続のリクエストを送信する必要があるノードをリバースプロキシに示すことができます。
リバースプロキシを使用する場合、Keycloakは特定のパスのみを公開する必要があります。次の表は、公開が推奨されるパスを示しています。
Keycloakパス | リバースプロキシパス | 公開 | 理由 |
---|---|---|---|
/ |
- |
いいえ |
すべてのパスを公開すると、管理パスが不必要に公開されます。 |
/admin/ |
- |
いいえ |
公開された管理パスは、不必要な攻撃ベクトルにつながります。 |
/realms/ |
/realms/ |
はい |
このパスは、たとえば、OIDCエンドポイントが正しく機能するために必要です。 |
/resources/ |
/resources/ |
はい |
このパスは、アセットを正しく提供するために必要です。Keycloakパスの代わりにCDNから提供される場合があります。 |
/metrics |
- |
いいえ |
公開されたメトリクスは、不必要な攻撃ベクトルにつながります。 |
/health |
- |
いいえ |
公開されたヘルスチェックは、不必要な攻撃ベクトルにつながります。 |
リバースプロキシ/ゲートウェイのパブリックAPIのルートパス /
でKeycloakを実行することを前提としています。そうでない場合は、パスに目的のプレフィックスを付けます。
信頼できるプロキシからのプロキシヘッダーのみが使用されるようにするには、proxy-trusted-addresses
オプションを、IPアドレス (IPv4またはIPv6) またはクラスレスドメイン間ルーティング (CIDR) 表記のコンマ区切りリストに設定します。
例
bin/kc.[sh|bat] start --proxy-headers forwarded --proxy-trusted-addresses=192.168.0.32,127.0.0.0/8
proxy-protocol-enabled
オプションは、サーバーがプロキシの背後からのリクエストを処理するときに HA PROXY プロトコルを使用するかどうかを制御します。true に設定すると、返されるリモートアドレスは、実際に接続しているクライアントからのアドレスになります。proxy-headers
オプションを使用している場合、値は true
にすることはできません。
これは、リクエストヘッダーを操作できないため、互換性のあるHTTPSパススループロキシの背後で実行する場合に役立ちます。
例
bin/kc.[sh|bat] start --proxy-protocol-enabled true
プロキシがTLS終端プロキシとして構成されている場合、クライアント証明書情報を特定のHTTPリクエストヘッダーを介してサーバーに転送し、クライアントの認証に使用できます。使用しているプロキシに応じて、サーバーがクライアント証明書情報を取得する方法を構成できます。
X.509認証用のプロキシヘッダーを介したクライアント証明書ルックアップは、セキュリティに敏感であると見なされます。誤って構成すると、偽造されたクライアント証明書ヘッダーが認証に使用される可能性があります。プロキシヘッダーを介して渡されるクライアント証明書情報が信頼できることを保証するために、特別な予防措置を講じる必要があります。
|
サーバーは、次のような最も一般的なTLS終端プロキシをサポートしています。
プロキシ | プロバイダー |
---|---|
Apache HTTP Server |
apache |
HAProxy |
haproxy |
NGINX |
nginx |
リクエストからクライアント証明書を取得する方法を構成するには、次のことを行う必要があります。
bin/kc.[sh|bat] build --spi-x509cert-lookup-provider=<provider>
bin/kc.[sh|bat] start --spi-x509cert-lookup-<provider>-ssl-client-cert=SSL_CLIENT_CERT --spi-x509cert-lookup-<provider>-ssl-cert-chain-prefix=CERT_CHAIN --spi-x509cert-lookup-<provider>-certificate-chain-length=10
HTTPヘッダーを構成するときは、使用している値が、クライアント証明書情報とともにプロキシによって転送されるヘッダーの名前に対応していることを確認する必要があります。
プロバイダーを構成するために使用可能なオプションは次のとおりです。
オプション | 説明 |
---|---|
ssl-client-cert |
クライアント証明書を保持するヘッダーの名前 |
ssl-cert-chain-prefix |
チェーン内の追加の証明書を保持し、チェーンの長さに応じて個々の証明書を取得するために使用されるヘッダーのプレフィックス。たとえば、値 |
certificate-chain-length |
証明書チェーンの最大長。 |
trust-proxy-verification |
証明書をKeycloakに転送してKeycloakで検証する代わりに、NGINXプロキシ証明書検証を信頼することを有効にします。 |
cert-is-url-encoded |
転送された証明書がURLエンコードされているかどうか。NGINXでは、これは |
NGINX SSL/TLSモジュールは、クライアント証明書チェーンを公開しません。KeycloakのNGINX証明書ルックアッププロバイダーは、Keycloakトラストストアを使用して再構築します。
このプロバイダーを使用している場合は、Keycloakトラストストアを構成する方法について、信頼できる証明書の構成 を参照してください。