1. ガイドの概要
このガイドの目的は、Keycloakサーバーの初回起動の前に完了する必要があるいくつかの手順について説明することです。Keycloakをテストしたいだけの場合は、組み込みのローカル専用のデータベースでそのまま実行する方がよいでしょう。実際にプロダクション環境にデプロイしたい場合は、まずどのようにランタイム(スタンドアローン・モードまたはドメインモード)でサーバー設定を管理するか決定して、Keycloakの共有データベースを設定し、暗号化とHTTPSの設定を行い、最後にKeycloakをセットアップしてクラスター内で起動する必要があります。このガイドは、Keycloakサーバーをデプロイする前に、起動に先んじて定義と設定が必要なすべての手順を、ひとつひとつ説明していきます。
ただし、KeycloakはWildFlyアプリケーション・サーバーに基づいていて、Keycloakの設定はWildFlyの設定項目と密接に関わっています。そのためこのガイドでは、詳細な説明について、このチュートリアルとは別の外部ドキュメントを紹介することがあります。その点は留意ください。
2. インストール
Keycloakのインストールは、ダウンロードして解凍するだけです。この章では、配布物のディレクトリー構造とシステム要件について説明します。
2.1. システム要件
Keycloak認証サーバーを実行するための要件は、以下のとおりです。
-
Javaが実行可能なオペレーティング・システム
-
Java 8 JDK
-
zipまたはgzip、およびtar
-
RAM512M以上
-
ディスクスペース1G以上
-
PostgreSQL、MySQL、Oracleなどの共有外部データベース。Keycloakをクラスターで実行する場合は、外部共有データベースが必要です。詳細については、このガイドのデータベース設定のセクションを参照してください。
-
クラスターを構成する場合はマルチキャスト・ネットワークのサポート。Keycloakは マルチキャストなしでもクラスターを構成できますが、多くの設定変更が必要になります。詳しくは、このガイドのクラスタリングセクションを参照してください。
-
Linuxにおいては、セキュリティー・ポリシーにより
/dev/random
の使用が義務付けられている場合を除き、ランダムデータのソースとして/dev/urandom
を使用することをお勧めします。エントロピー不足が原因でKeycloakが固まるのを防ぐことができます。Oracle JDK 8およびOpenJDK 8でこれを使用するには、 起動時のjava.security.egd
システム・プロパティーをfile:/dev/urandom
に設定してください。
2.2. 配布ファイルのインストール
Keycloakサーバーには、ダウンロード可能な3つの配布物があります。
-
'keycloak-4.8.3.Final.[zip|tar.gz]'
-
'keycloak-overlay-4.8.3.Final.[zip|tar.gz]'
-
'keycloak-demo-4.8.3.Final.[zip|tar.gz]'
'keycloak-4.8.3.Final.[zip|tar.gz]'ファイルはサーバーのみの配布物です。Keycloakサーバーを実行するスクリプトとバイナリー以外は含んでおりません。このファイルを開くには、動作システムの unzip
または gunzip
および tar
のユーティリティーを実行します。
'keycloak-overlay-4.8.3.Final.[zip|tar.gz]'ファイルは、WildFlyの配布物に追加してKeycloakサーバーをインストールするWildFlyのアドオンです。アプリケーションとKeycloakを同じサーバー・インスタンスで実行した場合は、サポートされません。Keycloakサービスパックをインストールするには、WildFlyの配布物のルート・ディレクトリー内で解凍し、シェルでbinディレクトリーを開いて、 ./jboss-cli.[sh|bat] --file=keycloak-install.cli
を実行します。
'keycloak-demo-4.8.3.Final.[zip|tar.gz]' には、サーバー・バイナリー、ドキュメントおよびサンプルが含まれています。OIDCとSAML、両方のクライアント・アプリケーション・アダプターがあらかじめ設定されており、サンプルをそのままデプロイすることができます。特に何か設定する必要はありません。しかし、プロダクション環境でデモ配布物の実行はサポートされないため、この配布物はKeycloakをテストする場合にのみ使用することをお勧めします。
これらのファイルを解凍するには、unzip
または gunzip
および tar
ユーティリティーを実行します。
2.3. 配布物のディレクトリー構造
この章では、サーバー配布物のディレクトリー構造について説明します。
いくつかのディレクトリーの目的について学んでいきましょう。
- bin/
-
サーバーの起動またはサーバー上でその他管理操作を行う、さまざまなスクリプトが含まれています。
- domain/
-
Keycloakをドメインモードで実行する場合の、設定ファイルとワーキング・ディレクトリーが含まれています。
- modules/
-
サーバー上で使用されるすべてのJavaライブラリーです。
- providers/
-
Keycloakの拡張を作成する場合、ここに配置することができます。詳しくは、Server Developer Guideを参照してください。
- standalone/
-
standalone modeでKeycloakを実行する場合、設定ファイルとワーキング・ディレクトリーは含まれません。
- themes/
-
このディレクトリーには、サーバーによって表示されるUI画面を表示するために使用されるすべてのHTML、スタイルシート、JavaScriptファイル、および画像が含まれます。ここでは、既存のテーマを変更したり、独自のテーマを作成したりすることができます。詳細については、 Server Developer Guide を参照してください。
3. 動作モードの選択
プロダクション環境でKeycloakをデプロイする前に、どのタイプの動作モードを使用するか決定する必要があります。クラスター内でKeycloakを実行しますか?サーバー設定を一元管理しますか?どの動作モードを選択するかによって、データベースやキャッシュをどのように設定するか、さらにはサーバーをどのように起動するかさえ変わってきます。
KeycloakはWildFlyアプリケーション・サーバー上に構築されています。このガイドでは、基本的な特定のモードでのデプロイメントについて説明します。詳しくは、WildFly 13 Documentationを参照してください。 |
3.1. スタンドアローン・モード
スタンドアローン動作モードは、サーバーに1つのKeycloakサーバー・インスタンスを起動する場合にのみ有効です。クラスター構成には使用できません。また、キャッシュは分散されておらずローカル専用です。スタンドアローン・モードは単一障害点となりえるので、プロダクション環境での使用はお勧めしません。スタンドアローン・モードのサーバーがダウンした場合、ユーザーはログインできなくなります。そのため、このモードはテストおよびKeycloakの機能を試す目的にのみ有効です。
3.1.1. スタンドアローン起動スクリプト
スタンドアローン・モードでサーバーを実行する場合、オペレーティング・システム固有の起動スクリプトを実行する必要があります。これらのスクリプトはサーバー配布物の bin/ ディレクトリーにあります。
To boot the server:
$ .../bin/standalone.sh
> ...\bin\standalone.bat
3.1.2. スタンドアローン設定
このガイドの大半は、Keycloakの基盤レベルの設定について説明します。このレベルの設定は、Keycloakが構築されたアプリケーション・サーバーに特化した設定ファイル内で実行されます。スタンドアローン動作モードでは、このファイルは …/standalone/configuration/standalone.xml にあります。また、このファイルはKeycloakのコンポーネントに特化した非基盤レベルの設定にも使用されます。
サーバーの実行中にこのファイルに変更を加えても、反映されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 13 Documentationを参照してください。 |
3.2. スタンドアローン・クラスター・モード
スタンドアローン・クラスター動作モードは、クラスター内でKeycloakを実行するためのものです。このモードでは、サーバー・インスタンスを実行する各マシンにKeycloakの配布物のコピーが保存されている必要があります。このモードは、最初は非常に簡単にデプロイできますが、後でかなり煩雑になる可能性があります。設定を変更するには、各マシンの配布物を修正する必要があります。大規模なクラスターの場合、時間がかかり、エラーも発生しやすくなります。
3.2.1. スタンドアローン・クラスター設定
この配布物には、クラスター内で実行するためのアプリケーション・サーバーの設定ファイルが含まれており、その大半は設定が済んでいます。ネットワーク、データベース、キャッシュ、およびディスカバリーのための基盤設定がすべて含まれています。このファイルは …/standalone/configuration/standalone-ha.xml にあります。しかし、この設定だけでは足りません。共有データベース接続を設定せずに、クラスター内でKeycloakを実行することはできません。また、クラスターのフロントにいくつかの種類のロードバランサーをデプロイする必要があります。このガイドのクラスタリングとデータベースのセクションでは、これらのことを説明します。
サーバーの実行中にこのファイルに変更を加えても、反映されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 13 Documentationを参照してください。 |
3.2.2. スタンドアローン・クラスター起動スクリプト
Keycloakを起動するには、スタンドアローン・モードで実行したのと同じ起動スクリプトを使用します。スタンドアローン・モードとの違いは、HA設定ファイルを指し示す追加フラグを渡すという点になります。
To boot the server:
$ .../bin/standalone.sh --server-config=standalone-ha.xml
> ...\bin\standalone.bat --server-config=standalone-ha.xml
3.3. ドメイン・クラスター・モード
ドメインモードとは、サーバーの設定を一元管理し、クラスター内の各サーバーに反映させる方法です。
標準モードでクラスターを実行すると、クラスターが大きくなり、煩雑化する可能性があります。クラスター内の各ノードにおいて、都度設定を変更する必要がでてきてしまいます。一方、ドメインモードの場合は、設定を保存しパブリッシュするために一元管理する場所を提供することで、この問題を解決できます。セットアップにはかなり手間がかかりますが、最終的にはその工数は見合うことになります。この機能はKeycloakが構成されるWildFlyアプリケーション・サーバーに組み込まれています。
このガイドでは、ドメインモードの初歩的なところを説明します。クラスター内でのドメインモードのセットアップ手順について、詳しくは、WildFly 13 Documentationを参照してください。 |
ドメインモードを実行する基本的なコンセプトは、以下のとおりです。
- ドメイン・コントローラー
-
ドメイン・コントローラーとは、クラスター内の各ノードの一般的な設定を保存、管理、パブリッシュする役割をもつ、プロセスのことです。また、クラスター内の各ノードが取得する設定を一元管理するデータベースでもあります。
- ホスト・コントローラー
-
ホスト・コントローラーの役割は、特定のマシン内のサーバー・インスタンスを管理することです。1つ以上のサーバー・インスタンスを実行できるよう、ホスト・コントローラーを設定することになります。また、ドメイン・コントローラーはクラスターを管理するために、各マシン内のホスト・コントローラーと連携します。実行プロセスを減らすために、ドメイン・コントローラーに、特定のマシン内のホスト・コントローラーとしての役割を担わせることもできます。
- ドメイン・プロファイル
-
ドメイン・プロファイルとは、サーバーを起動するために使用する、名前付きの設定セットです。ドメイン・コントローラーで、複数のドメイン・プロファイルを定義することができます。そして、さまざまなサーバーがこのドメイン・プロファイルを使うことになります。
- サーバーグループ
-
サーバーグループとは、サーバーの集合体です。ひとつの集合体として管理、設定されます。サーバーグループに、ドメイン・プロファイルを割り当てることができます。そして、そのドメイン・プロファイルはサーバーグループ内のサービスの設定として使用されます。
ドメインモードでは、マスターノード上でドメイン・コントローラーが起動されます。クラスターの設定は、ドメイン・コントローラー内にあります。次に、ホスト・コントローラーがクラスター内の各マシンで起動されます。各ホスト・コントローラーのデプロイ設定では、そのマシンで起動するKeycloakサーバー・インスタンスの数を指定します。ホスト・コントローラーが起動すると、指定された数のKeycloakサーバー・インスタンスが起動します。これらのサーバー・インスタンスは、ドメイン・コントローラーから設定を取得します。
3.3.1. ドメイン設定
このガイドの各章では、データベース、HTTPネットワーク接続、キャッシュ、およびその他の基盤関連のさまざまな設定について、説明します。これらを設定するために、スタンドアローン・モードでは standalone.xml ファイルを使用するのに対して、ドメインモードでは …/domain/configuration/domain.xml を使用します。Keycloakサーバーのドメイン・プロファイルとサーバーグループは、以下で定義されます。
ドメイン・コントローラーの実行中にこのファイルに変更を加えても、変更されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 13 Documentationを参照してください。 |
この domain.xml ファイルの特徴を確認していきましょう。 auth-server-standalone
と auth-server-clustered
profile
のXMLブロックでは、どのような設定にするかの大半を定義します。そして、ネットワーク接続、キャッシュ、データベース接続などを設定します。
<profiles>
<profile name="auth-server-standalone">
...
</profile>
<profile name="auth-server-clustered">
...
</profile>
auth-server-standalone
プロファイルは、非クラスター構成のセットアップ用です。一方 auth-server-clustered
プロファイルは、クラスター構成のセットアップ用です。
スクロールダウンしていくと、定義済みの socket-binding-groups
が表示されます。
<socket-binding-groups>
<socket-binding-group name="standard-sockets" default-interface="public">
...
</socket-binding-group>
<socket-binding-group name="ha-sockets" default-interface="public">
...
</socket-binding-group>
<!-- load-balancer-socketsはプロダクション環境では取り除かれ、高度なソフトウェアまたはハードウェアに取り換えられます -->
<socket-binding-group name="load-balancer-sockets" default-interface="public">
...
</socket-binding-group>
</socket-binding-groups>
この設定では、各Keycloakサーバー・インスタンスによって開かれる、さまざまなコネクターのデフォルトのポートマッピングを定義します。 ${…}
を含む値はコマンドラインの -D
スイッチで上書きできる値です。すなわち、以下のように上書きできます。
$ domain.sh -Djboss.http.port=80
Keycloakのサーバーグループの定義は、 server-groups
のXMLブロックにあります。ホスト・コントローラーがインスタンスを起動する場合、この定義により、 default
で使用されているドメイン・プロファイル、およびJava VMのデフォルト起動引数が指定されます。また、 socket-binding-group
はサーバーグループにバインドされます。
<server-groups>
<!-- load-balancer-groupはプロダクション環境では取り除かれ、高度なソフトウェアまたはハードウェアに取り換えられます -->
<server-group name="load-balancer-group" profile="load-balancer">
<jvm name="default">
<heap size="64m" max-size="512m"/>
</jvm>
<socket-binding-group ref="load-balancer-sockets"/>
</server-group>
<server-group name="auth-server-group" profile="auth-server-clustered">
<jvm name="default">
<heap size="64m" max-size="512m"/>
</jvm>
<socket-binding-group ref="ha-sockets"/>
</server-group>
</server-groups>
3.3.2. ホスト・コントローラー設定
Keycloakには、 …/domain/configuration/ ディレクトリーにある、 host-master.xml と host-slave.xml の2つのホスト・コントローラー設定ファイルが付属しています。 host-master.xml はドメイン・コントローラー、ロードバランサー、および1つのKeycloakサーバー・インスタンスを起動するように設定されています。一方、 host-slave.xml はドメイン・コントローラーと通信し、1つのKeycloakサーバー・インスタンスを起動するように設定されています。
ロードバランサーは必須サービスではありません。これは、開発マシン上でクラスタリングを簡単にテストできるようにするものです。プロダクション環境で使用可能ですが、使いたい別のハードウェアまたはソフトウェア・ベースのロードバランサーがあるなら、置き換えるかどうかを選択できます。 |
ロードバランサー・サーバー・インスタンスを無効にするには、 host-master.xml を編集し、 "load-balancer" エントリーをコメントアウトまたは削除します。
<servers>
<!-- 次の行を削除またはコメントアウト -->
<server name="load-balancer" group="loadbalancer-group"/>
...
</servers>
このファイルに関してもう1つ興味深い点は、認証サーバー・インスタンスの宣言です。これには port-offset
が設定されています。 domain.xml の socket-binding-group
またはサーバーグループで定義されたネットワークポートには、port-offsetの値が加算されます。このサンプルでは、ロードバランサー・サーバーによって開かれたポートが、起動中の認証サーバー・インスタンスと競合しないように設定しています。
<servers>
...
<server name="server-one" group="auth-server-group" auto-start="true">
<socket-bindings port-offset="150"/>
</server>
</servers>
3.3.3. サーバー・インスタンス・ワーキング・ディレクトリー
ホスト・ファイルに定義されている各Keycloakサーバー・インスタンスにより、 …/domain/servers/{SERVER NAME} の下に作業ディレクトリーが作成されます。そこに追加の設定を保存でき、サーバー・インスタンスが必要とする、または作成する一時ファイル、ログファイル、データファイルも保存することができます。これらのサーバー・ディレクトリーごとの構造は、他のWildFlyブートサーバーと同じようなものになります。
3.3.4. ドメイン起動スクリプト
ドメインモードでサーバーを実行する場合、オペレーティング・システム固有の起動スクリプトを実行する必要があります。これらのスクリプトは、サーバー配布物の bin/ ディレクトリーにあります。
To boot the server:
$ .../bin/domain.sh --host-config=host-master.xml
> ...\bin\domain.bat --host-config=host-master.xml
起動スクリプトを実行する場合、 --host-config
スイッチ経由で、使用するホスト制御設定ファイルを渡す必要があります 。
3.3.5. クラスター構成ドメインのサンプル
そのまま利用可能な domain.xml 設定を使用してクラスタリングをテストできます。このサンプルドメインは、1台のマシンで実行され、以下を起動します。
-
ドメイン・コントローラー
-
HTTPロードバランサー
-
2つのKeycloakサーバー・インスタンス
2台のマシンでのクラスターの実行をシミュレートするには、 domain.sh
スクリプトを2回実行して2つの別々のホスト・コントローラーを起動させます。はじめに、ドメイン・コントローラー、HTTPロード・バランサー、および1つのKeycloak認証サーバー・インスタンスを起動するマスター・ホスト・コントローラーを起動させます。次に、認証サーバー・インスタンスを起動するだけのスレーブ・ホスト・コントローラーを起動させます。
ドメイン・コントローラーへのスレーブ接続セットアップ
ホスト・コントローラーを起動する前に、スレーブ・ホスト・コントローラーをドメイン・コントローラーと安全に通信できるように設定する必要があります。これを設定しなかった場合、スレーブホストはドメイン・コントローラーから一元管理された設定を取得できなくなります。安全な接続をセットアップするには、マスターとスレーブの間で共有されるサーバー管理ユーザーとシークレットを作成する必要があります。これを作成するには、 …/bin/add-user.sh
スクリプトを実行します。
スクリプトを実行する場合は Management User
を選び、新規ユーザーがASプロセスを別のプロセスに接続するかどうかを尋ねるメッセージが表示された場合は yes
と回答します。これにより、 …/domain/configuration/host-slave.xml ファイルにカット・アンド・ペーストする必要があるシークレットが生成されます。
$ add-user.sh
What type of user do you wish to add?
a) Management User (mgmt-users.properties)
b) Application User (application-users.properties)
(a): a
Enter the details of the new user to add.
Using realm 'ManagementRealm' as discovered from the existing property files.
Username : admin
Password recommendations are listed below. To modify these restrictions edit the add-user.properties configuration file.
- The password should not be one of the following restricted values {root, admin, administrator}
- The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s)
- The password should be different from the username
Password :
Re-enter Password :
What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[ ]:
About to add user 'admin' for realm 'ManagementRealm'
Is this correct yes/no? yes
Added user 'admin' to file '/.../standalone/configuration/mgmt-users.properties'
Added user 'admin' to file '/.../domain/configuration/mgmt-users.properties'
Added user 'admin' with groups to file '/.../standalone/configuration/mgmt-groups.properties'
Added user 'admin' with groups to file '/.../domain/configuration/mgmt-groups.properties'
Is this new user going to be used for one AS process to connect to another AS process?
e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls.
yes/no? yes
To represent the user add the following to the server-identities definition <secret value="bWdtdDEyMyE=" />
add-user.shにより、Keycloakサーバーにではなく、基盤となるJBoss Enterprise Application Platformにユーザーが追加されます。上記のスクリプトで使用、生成された証明書は、あくまでサンプルです。お使いのシステムで生成されたものを使用してください。 |
…/domain/configuration/host-slave.xml ファイルにシークレットの値をカット・アンド・ペーストすると、以下のようになります。
<management>
<security-realms>
<security-realm name="ManagementRealm">
<server-identities>
<secret value="bWdtdDEyMyE="/>
</server-identities>
作成したユーザーの username も …/domain/configuration/host-slave.xml ファイルに追加する必要があります。
<remote security-realm="ManagementRealm" username="admin">
3.4. クロスデータセンター・レプリケーション・モード
クロスデータセンター・レプリケーション・モードは、複数のデータセンターを横断してクラスター内でKeycloakを実行する必要がある時のためのもので、地理的に異なる地域にあるデータセンター・サイトが一般的には最も使用されます。このモードを使用する場合、各データセンターにはKeycloakサーバーの独自のクラスターがあります。
このドキュメントでは、次のアーキテクチャー図の例を参照して、単純なクロスデータセンター・レプリケーションのユースケースを図解および説明します。
3.4.1. 前提条件
これは高度なトピックのため、最初に以下を読み、背景にある重要な知識を身につけておくことをお勧めします。
-
Keycloakによるクラスタリング クロスデータセンター・レプリケーションを設定する場合、より独立したKeycloakクラスターを使用するため、クラスターの仕組みや、ロード・バランシング、共有データベース、マルチキャストなどの基本的な概念と要件を理解する必要があります。
-
JBoss Data Grid Cross-Datacenter Replication Keycloakでは、JBoss Data Grid(JDG)を使用して、データセンター間でInfinispanデータをレプリケーションします。 Configure Cross-Datacenter Replication のJDGドキュメントで記載されている
Remote Client-Server Mode
を使用します。
3.4.2. 技術的な詳細
このセクションでは、Keycloakクロスデータセンター・レプリケーションの仕組みについて概念と詳細について説明します。
Keycloakはステートフルなアプリケーションです。データソースとして以下のものを使用します。
-
データベースは、ユーザー情報などの永続的なデータを保持するために使用されます。
-
Infinispanキャッシュは、永続化データをデータベースからキャッシュし、短期間で頻繁に変化するメタデータ(ユーザー・セッションなど)を節約するためにも使用されます。Infinispanは通常、データベースよりもはるかに高速ですが、Infinispanを使用して保存されたデータは永続的ではなく、クラスターを再起動後も維持できるとは限りません。
このアーキテクチャーの例では、 site1
と site2
と呼ばれる2つのデータセンターがあります。クロスデータセンター・レプリケーションでは、両方のデータソースが確実に動作し、 site2
のKeycloakサーバーによって保存されたデータを site1
のKeycloakサーバーが最終的に読み取ることができるようにする必要があります。
環境に基づいて、次の選択肢から決める必要があります。
-
信頼性 - 通常はアクティブ/アクティブモードで使用されます。
site1
で記述されたデータはsite2
ですぐに表示される必要があります。 -
パフォーマンス - 通常はアクティブ/パッシブモードで使用されます。
site1
で記述されたデータはすぐにsite2
で表示される必要はありません。状況によって、site2
でデータが表示されないこともあります。
詳細は、モードを参照してください。
3.4.3. リクエスト処理
エンドユーザーのブラウザーは、HTTPリクエストをフロント・エンド・ロードバランサーに送信します。このロードバランサーは、通常mod_cluster、NGINX、HA Proxy、またはその他のソフトウェアかハードウェア・ロードバランサーを使用するHTTPDまたはWildFlyです。
ロードバランサーは、基になるKeycloakインスタンスに、受け取ったHTTPリクエストを転送します。このインスタンスは、複数のデータセンターに分散させることができます。ロードバランサーは通常、スティッキー・セッションをサポートしています。つまり、ロードバランサーは、同じデータセンターの同じKeycloakインスタンスに、同じユーザーのすべてのHTTPリクエストを常に転送することができます。
クライアント・アプリケーションからロードバランサーに送られたHTTPリクエストは バックチャネル・リクエスト
と呼ばれます。これらはエンドユーザーのブラウザーからは見えないので、ユーザーとロードバランサー間でスティッキー・セッションの一部になることはできません。バックチャネル・リクエストの場合、ロードバランサーは、HTTPリクエストを任意のデータセンター内のいずれかのKeycloakインスタンスに転送することができます。これは、いくつかのOpenID ConnectといくつかのSAMLフローがユーザーとアプリケーションの両方から複数のHTTPリクエストを必要とするため、難しい問題です。関連するすべてのリクエストを同じデータセンター内の同じKeycloakインスタンスに送信するのにスティッキー・セッションに完全に依存することはできないため、代わりに、データセンター間で一部のデータをレプリケートする必要があります。それにより、データは特定のフロー中の後続のHTTPリクエストによって表示されます。
3.4.4. モード
要件に応じて、クロスデータセンター・レプリケーションには2つの基本的な動作モードがあります。
-
アクティブ/パッシブ - ユーザーとクライアント・アプリケーションは、単一のデータセンター内のKeycloakノードにのみリクエストを送信します。第2のデータセンターは、データを保存するための
バックアップ
としてのみ使用されます。メインのデータセンターに障害が発生した場合、通常は第2のデータセンターからデータを復旧します。 -
アクティブ/アクティブ - ユーザーとクライアント・アプリケーションは、両方のデータセンターのKeycloakノードにリクエストを送信します。つまり、両方のサイトですぐにデータを表示し、 両方のサイトのKeycloakサーバーからデータをすぐに使用できるようにする必要があります。これは、Keycloakサーバーが
site1
に何かしらのデータを書き込む場合に特に当てはまります。また、site1
への書き込みが完了した直後に、site2
のKeycloakサーバーがデータをすぐに読み取ることができるようにする必要があります。
アクティブ/パッシブモードは、パフォーマンスに優れています。いずれかのモードでキャッシュを設定する方法の詳細については、 SYNCまたはASYNCバックアップ を参照してください。
3.4.5. データベース
Keycloakは、リレーショナル・データベース・マネジメント・システム(RDBMS)を使用して、レルム、クライアント、ユーザーなどのメタデータを保持します。詳細については、サーバーインストールガイドのこの章を参照してください。クロスデータセンター・レプリケーションのセットアップでは、両方のデータセンターが同じデータベースと通信するか、すべてのデータセンターに独自のデータベース・ノードがあり、両方のデータベース・ノードがデータセンター間で同期レプリケートされると想定しています。どちらの場合でも、 site1
のKeycloakサーバーがデータを保持してトランザクションをコミットすると、 site2
の後続のDBトランザクションによって、それらのデータがすぐに表示される必要があります。
DBのセットアップの詳細については、Keycloakの範囲外ですが、MariaDBやOracleなどのRDBMSベンダーの多くは、レプリケートされたデータベースと同期レプリケーションを提供しています。これらのベンダーを使用して、Keycloakをテストします。
-
Oracle Database 12c Release 1 (12.1) RAC
-
Galera 3.12 cluster for MariaDB server version 10.1.19-MariaDB
3.4.6. Infinispanキャッシュ
このセクションでは、Infinispanキャッシュの概要を説明していきます。キャッシュの設定の詳細は以下のとおりです。
Keycloakには、認証セッションの概念があります。 authenticationSessions
と呼ばれる別のInfinispanキャッシュがあり、特定のユーザーの認証時にデータを保存するのに使用されます。このキャッシュからのリクエストには通常、アプリケーションではなく、ブラウザーとKeycloakサーバーのみが必要になります。ここでは、アクティブ/アクティブモードであっても、スティッキー・セッションに依存することができ、 authenticationSessions
キャッシュ・コンテンツをデータセンター間でレプリケートする必要はありません。
アクション・トークンの概念もあります。アクション・トークンは、通常、ユーザーが電子メールでアクションを非同期で確認する必要があるシナリオで使用されます。たとえば、 forget password
フローの間に、 actionTokens
Infinispanキャッシュは、どのアクション・トークンがすでに使用されているかなどの関連するアクション・トークンに関するメタデータを追跡するために使用されるため、2度目は再利用できません。これは通常、データセンター間でレプリケートする必要があります。
KeycloakはInfinispanを使用して永続化データをキャッシュし、データベースへの不要なリクエストを多く回避します。キャッシュによりパフォーマンスは改善されますが、さらなる問題が加わります。一部のKeycloakサーバーがデータを更新した場合、すべてのデータセンターの他のすべてのKeycloakサーバーはそのことに気づく必要があるため、それらのキャッシュから特定のデータを無効にします。Keycloakは、 realms
、 users
、および authorization
と呼ばれるローカルInfinispanキャッシュを使用して、永続化データをキャッシュします。
すべてのデータセンターでレプリケートされる、別のキャッシュ work
を使用します。workキャッシュ自体は実際のデータをキャッシュしません。クラスターノードとデータセンター間で無効化メッセージを送信する場合にのみ使用されます。つまり、ユーザー john
などのデータが更新されると、Keycloakノードは、同じデータセンター内の他のすべてのクラスターノード、および他のすべてのデータセンターに無効化メッセージを送信します。すべてのノードは、無効通知を受信した後、ローカル・キャッシュから適切なデータを無効にします。
sessions
、 clientSessions
、 offlineSessions
、および offlineClientSessions
と呼ばれるInfinispanキャッシュがあり、それらのすべては通常、データセンター間でレプリケートされる必要があります。これらのキャッシュは、ユーザー・セッションに関するデータを保存するために使用され、ユーザーのブラウザー・セッションの長さに対して有効です。キャッシュは、エンドユーザーとアプリケーションからのHTTPリクエストを処理する必要があります。前述のとおり、このインスタンスではスティッキー・セッションを信頼性をもって使用することはできませんが、後続のHTTPリクエストが最新のデータを確認できるようにする必要があります。このため、データは通常、データセンター間でレプリケートされます。
最後に、 loginFailures
キャッシュは、ユーザー john
が不正なパスワードを入力した回数など、ログイン失敗に関するデータを追跡するために使用されます。詳細は、こちらを参照してください。このキャッシュをデータセンター間でレプリケートするかどうかは、管理者次第です。正確なログイン失敗の回数を取得するには、レプリケーションが必要です。一方、このデータをレプリケートしないことで、パフォーマンスをよくできます。したがって、パフォーマンスがログイン失敗の正確な回数よりも重要な場合は、レプリケーションを避けるという手もあります。
キャッシュの設定方法の詳細については、JDGキャッシュ設定のチューニングを参照してください。
3.4.7. コミュニケーションの詳細
Keycloakは、Infinispanキャッシュの分割されたクラスターを複数使用します。各Keycloakノードは、同じデータセンター内の他のKeycloakノードと共にクラスター内にありますが、異なるデータセンターのKeycloakノードはそのクラスター内にありません。Keycloakノードは、異なるデータセンターのKeycloakノードと直接通信できません。Keycloakノードは、データセンター間の通信に外部JDG (実際にはInfinispanサーバー)を使用します。これは、Infinispan HotRodプロトコルを使用して行われます。
Keycloak側のInfinispanキャッシュは、データがリモート・キャッシュに保存されていることを確認するために、remoteStoreを使用して設定する必要があります。JDGサーバー間に分割されたInfinispanクラスターがあるので、 site1
のJDG1に保存されていたデータは site2
のJDG2にレプリケートされます。
最後に、受信JDGサーバーは、HotRodプロトコルの機能であるクライアント・リスナーを介して、クラスター内のKeycloakサーバーに通知します。次に、 site2
のKeycloakノードがInfinispanキャッシュを更新し、特定のユーザー・セッションが site2
のKeycloakノードにも表示されます。
詳細は、アーキテクチャー図の例を参照してください。
3.4.8. 基本設定
この例では、 site1
と site2
という2つのデータセンター使用して説明します。各データセンターは、1つのInfinispanサーバーと2つのKeycloakサーバーで構成されています。合計すると、2つのInfinispanサーバーと4つのKeycloakサーバーになります。
-
Site1
は、Infinispanサーバーのjdg1
と2つのKeycloakサーバーのnode11
およびnode12
で構成されています。 -
Site2
は、Infinispanサーバーのjdg2
と2つの Keycloakサーバーのnode21
およびnode22
で構成されています。 -
Infinispanサーバーである
jdg1
とjdg2
は、 JDGのドキュメント で記載されているのと同様の方法で、RELAY2プロトコルとbackup
ベースのInfinispanキャッシュを介して相互に接続されています。 -
Keycloakサーバーである
node11
とnode12
は、お互いにクラスターを形成しますが、site2
内のサーバーとは直接通信はしません。それらはHotRodプロトコル (リモート・キャッシュ)を使用して、Infinispanサーバーjdg1
と通信します。詳細については、コミュニケーションの詳細を参照してください。 -
同じ説明が
node21
とnode22
にも当てはまります。それらはお互いにクラスター化し、HotRodプロトコルを使用して、jdg2
サーバーとのみ通信します。
この設定の例では、4つのKeycloakサーバーすべてが同じデータベースと通信することを前提としています。プロダクション環境では、データベースで説明されているとおり、データセンター間で別々の同期レプリケートされたデータベースを使用することをお勧めします。
Infinispanサーバーの設定
Infinispanサーバーの設定は、以下の手順に沿って行います。
-
Infinispan 9.3.1サーバーをダウンロードし、選択したディレクトリーに解凍します。このロケーションは、
JDG1_HOME
として後ほど参照することになります。 -
JGroupsサブシステムの設定で、
JDG1_HOME/standalone/configuration/clustered.xml
内にあるこれらを変更します。-
xsite
チャネルを追加して、channels
要素の下にあるtcp
スタックを使用します。<channels default="cluster"> <channel name="cluster"/> <channel name="xsite" stack="tcp"/> </channels>
-
relay
要素をudp
スタックの最後尾に追加します。自身のサイトはsite1
で、バックアップする他のサイトはsite2
というように設定します。<stack name="udp"> ... <relay site="site1"> <remote-site name="site2" channel="xsite"/> <property name="relay_multicasts">false</property> </relay> </stack>
-
MPING
の代わりに、tcp
スタックを設定してTCPPING
プロトコルを使用します。MPING
要素を削除してTCPPING
に置き換えます。initial_hosts
要素は、ホストjdg1
とjdg2
を指します。<stack name="tcp"> <transport type="TCP" socket-binding="jgroups-tcp"/> <protocol type="TCPPING"> <property name="initial_hosts">jdg1[7600],jdg2[7600]</property> <property name="ergonomics">false</property> </protocol> <protocol type="MERGE3"/> ... </stack>
これは、単にすばやく実行するための設定例です。プロダクション環境では、JGroups RELAY2
にtcp
スタックを使用する必要はなく、他のどのスタックを設定しても構いません。たとえば、データセンター間のネットワークがマルチキャストをサポートできる場合は、デフォルトのudpスタックを使用することができます。InfinispanとKeycloakクラスターがお互いを見つけることはできないという点だけは確認してください。同じように、TCPPING
を検出プロトコルとして使用する必要はありません。また、TCPPING
は静的な性質であるため、使用することはないでしょう。最後に、サイト名も設定することができます。この設定のより詳細な内容については、Keycloakドキュメントの範囲外になります。詳細については、InfinispanのドキュメントおよびJGroupsのドキュメントを参照してください。
-
-
JDG1_HOME/standalone/configuration/clustered.xml
のclustered
という名前のcache-containerの下に次の設定を追加します。<cache-container name="clustered" default-cache="default" statistics="true"> ... <replicated-cache-configuration name="sessions-cfg" mode="SYNC" start="EAGER" batching="false"> <locking acquire-timeout="0" /> <backups> <backup site="site2" failure-policy="FAIL" strategy="SYNC" enabled="true"> <take-offline min-wait="60000" after-failures="3" /> </backup> </backups> </replicated-cache-configuration> <replicated-cache name="work" configuration="sessions-cfg"/> <replicated-cache name="sessions" configuration="sessions-cfg"/> <replicated-cache name="clientSessions" configuration="sessions-cfg"/> <replicated-cache name="offlineSessions" configuration="sessions-cfg"/> <replicated-cache name="offlineClientSessions" configuration="sessions-cfg"/> <replicated-cache name="actionTokens" configuration="sessions-cfg"/> <replicated-cache name="loginFailures" configuration="sessions-cfg"/> </cache-container>
replicated-cache-configuration
内の設定オプションについての詳細は、JDGキャッシュ設定のチューニングで説明しています。これには、これらのオプションのいくつかを調整するための情報が含まれています。以前のバージョンとは異なり、Infinispanサーバーの replicated-cache-configuration
はtransaction
要素なしで設定する必要があります。詳細はトラブルシューティングを参照してください。 -
一部のInfinispanサーバーリリースでは、ネットワーク経由で保護されたキャッシュにアクセスする前に認可が必要です。
推奨されたInfinispan 9.3.1サーバーを使用している場合は、何も問題はありません。この手順は無視しても構いません(無視すべきです)。認可に関連する問題は、他のバージョンのInfinispanサーバーにのみ存在する可能性があります。 Keycloakはスクリプトを含む
___script_cache
キャッシュへの更新が必要です。このキャッシュにアクセスする際にエラーが発生した場合、下記のようにclustered.xml
設定で認可を設定する必要があります。-
<management>
のセクションの中で、次のようにセキュリティー・レルムを追加します。<management> <security-realms> ... <security-realm name="AllowScriptManager"> <authentication> <users> <user username="___script_manager"> <password>not-so-secret-password</password> </user> </users> </authentication> </security-realm> </security-realms>
-
サーバー・コア・サブシステムで、以下のように
<security>
を追加します。<subsystem xmlns="urn:infinispan:server:core:8.4"> <cache-container name="clustered" default-cache="default" statistics="true"> <security> <authorization> <identity-role-mapper/> <role name="___script_manager" permissions="ALL"/> </authorization> </security> ...
-
エンドポイント・サブシステムで、Hot Rodコネクターに認証設定を追加します。
<subsystem xmlns="urn:infinispan:server:endpoint:8.1"> <hotrod-connector cache-container="clustered" socket-binding="hotrod"> ... <authentication security-realm="AllowScriptManager"> <sasl mechanisms="DIGEST-MD5" qop="auth" server-name="keycloak-jdg-server"> <policy> <no-anonymous value="false" /> </policy> </sasl> </authentication>
-
-
2つ目のロケーションにサーバーをコピーします。これは、
JDG2_HOME
として後ほど参照することになります。 -
JDG2_HOME/standalone/configuration/clustered.xml
では、site1
をsite2
に置き換えると、JGroupsサブシステム内のrelay
の設定とcache-subsystem内のbackups
の設定の両方において、逆の動作をします。次に例を示します。-
relay
要素は、以下のように表示されます。<relay site="site2"> <remote-site name="site1" channel="xsite"/> <property name="relay_multicasts">false</property> </relay>
-
backups
要素は、以下のように表示されます。<backups> <backup site="site1" .... ...
現時点では、Infinispanサブシステムはサイト名を式によって置き換えることはサポートしていないため、両方のサイトのJDGサーバーに異なる設定ファイルを用意する必要があります。詳細については、この課題を参照してください。
-
-
jdg1
サーバーを起動します。cd JDG1_HOME/bin ./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true \ -Djboss.default.multicast.address=234.56.78.99 \ -Djboss.node.name=jdg1 -b PUBLIC_IP_ADDRESS
-
jdg2
サーバーを起動します。異なるマルチキャスト・アドレスがあるため、jdg1
とjdg2
サーバーは互いに直接クラスター化されません。むしろ、それらはRELAY2プロトコルを介して接続されており、TCP JGroupsスタックはそれらの間の通信に使用されます。起動コマンドは次のようになります。cd JDG2_HOME/bin ./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true \ -Djboss.default.multicast.address=234.56.78.100 \ -Djboss.node.name=jdg2 -b PUBLIC_IP_ADDRESS
-
この時点でチャネルが動作していることを検証するには、JConsoleを使用し、実行中の
JDG1
またはJDG2
サーバーに接続する必要があります。MBeanjgroups:type=protocol,cluster="cluster",protocol=RELAY2
およびprintRoutes
オペレーションを使用すると、以下のような出力が表示されます。site1 --> _jdg1:site1 site2 --> _jdg2:site2
MBean
jgroups:type=protocol,cluster="cluster",protocol=GMS
を使用すると、属性メンバーには単一のメンバーしか含まれていないということがわかります。-
JDG1
では、以下のように表示されます。(1) jdg1
-
JDG2
では、以下のように表示されます。(1) jdg2
プロダクション環境では、すべてのデータセンターにさらに多くのInfinispanサーバーを持つことができます。同じデータセンター内のInfinispanサーバーが同じマルチキャスト・アドレスを使用していること(つまり、起動中に同じ jboss.default.multicast.address
を使用していること)を確認するだけです。そうすると、GMS
プロトコルビューのjconsoleに、現在のクラスターのメンバーがすべて表示されます。
-
Keycloakサーバーの設定
-
Keycloakサーバー配布物を選択した場所に解凍します。これは
NODE11
として後ほど参照することになります。 -
KeycloakDSデータソースの共有データベースを設定します。テストを目的とする場合は、MySQLまたはMariaDBの使用をお勧めします。詳細はデータベースを参照してください。
プロダクション環境では、すべてのデータセンターにおいて別々のデータベース・サーバーを用意する必要があり、両方のデータベース・サーバーを互いに同期してレプリケートする必要があります。設定例では、単一のデータベースを使用し、4つのKeycloakサーバーすべてに接続します。
-
NODE11/standalone/configuration/standalone-ha.xml
を以下のように編集してください。-
site
属性をJGroups UDPプロトコルに追加します。<stack name="udp"> <transport type="UDP" socket-binding="jgroups-udp" site="${jboss.site.name}"/>
-
名前が
keycloak
のcache-container
要素の下に、このmodule
属性を追加します。<cache-container name="keycloak" module="org.keycloak.keycloak-model-infinispan">
-
work
キャッシュの下にremote-store
を追加します。<replicated-cache name="work"> <remote-store cache="work" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true"> <property name="rawValues">true</property> <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property> </remote-store> </replicated-cache>
-
session
キャッシュの下にremote-store
を追加します。<distributed-cache name="sessions" owners="1"> <remote-store cache="sessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true"> <property name="rawValues">true</property> <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property> </remote-store> </distributed-cache>
-
offlineSessions
、clientSessions
、offlineClientSessions
、loginFailures
、actionTokens
キャッシュでも同じことをします(sessions
キャッシュとの唯一の違いは、cache
プロパティー値が異なることです)。<distributed-cache name="offlineSessions" owners="1"> <remote-store cache="offlineSessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true"> <property name="rawValues">true</property> <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property> </remote-store> </distributed-cache> <distributed-cache name="clientSessions" owners="1"> <remote-store cache="clientSessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true"> <property name="rawValues">true</property> <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property> </remote-store> </distributed-cache> <distributed-cache name="offlineClientSessions" owners="1"> <remote-store cache="offlineClientSessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true"> <property name="rawValues">true</property> <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property> </remote-store> </distributed-cache> <distributed-cache name="loginFailures" owners="1"> <remote-store cache="loginFailures" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true"> <property name="rawValues">true</property> <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property> </remote-store> </distributed-cache> <distributed-cache name="actionTokens" owners="2"> <object-memory size="-1"/> <expiration max-idle="-1" interval="300000"/> <remote-store cache="actionTokens" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="true" shared="true"> <property name="rawValues">true</property> <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property> </remote-store> </distributed-cache>
-
リモートストアのアウトバウンド・ソケット・バインディングを
socket-binding-group
要素の設定に追加します。<outbound-socket-binding name="remote-cache"> <remote-destination host="${remote.cache.host:localhost}" port="${remote.cache.port:11222}"/> </outbound-socket-binding>
-
分散キャッシュ設定の
authenticationSessions
と他のキャッシュは変更されません。 -
オプションで、
logging
サブシステムの下でDEBUGログを有効にします。<logger category="org.keycloak.cluster.infinispan"> <level name="DEBUG"/> </logger> <logger category="org.keycloak.connections.infinispan"> <level name="DEBUG"/> </logger> <logger category="org.keycloak.models.cache.infinispan"> <level name="DEBUG"/> </logger> <logger category="org.keycloak.models.sessions.infinispan"> <level name="DEBUG"/> </logger>
-
-
NODE11
を後述するNODE12
、NODE21
、NODE22
という3つのディレクトリーにコピーしてください。 -
次のように、
NODE11
を起動してください。cd NODE11/bin ./standalone.sh -c standalone-ha.xml -Djboss.node.name=node11 -Djboss.site.name=site1 \ -Djboss.default.multicast.address=234.56.78.1 -Dremote.cache.host=jdg1 \ -Djava.net.preferIPv4Stack=true -b PUBLIC_IP_ADDRESS
-
次のように、
NODE12
を起動してください。cd NODE12/bin ./standalone.sh -c standalone-ha.xml -Djboss.node.name=node12 -Djboss.site.name=site1 \ -Djboss.default.multicast.address=234.56.78.1 -Dremote.cache.host=jdg1 \ -Djava.net.preferIPv4Stack=true -b PUBLIC_IP_ADDRESS
クラスター・ノードを接続する必要があります。このようなものは、NODE11とNODE12のどちらのログにも残っていなければなりません。
Received new cluster view for channel keycloak: [node11|1] (2) [node11, node12]
ログにあるチャネル名とは異なっている可能性があります。 -
次のように、
NODE21
を起動してください。cd NODE21/bin ./standalone.sh -c standalone-ha.xml -Djboss.node.name=node21 -Djboss.site.name=site2 \ -Djboss.default.multicast.address=234.56.78.2 -Dremote.cache.host=jdg2 \ -Djava.net.preferIPv4Stack=true -b PUBLIC_IP_ADDRESS
NODE11
とNODE12
を使用してクラスターに接続するのではなく、クラスターを分離する必要があります。Received new cluster view for channel keycloak: [node21|0] (1) [node21]
-
次のように、
NODE22
を起動してください。cd NODE22/bin ./standalone.sh -c standalone-ha.xml -Djboss.node.name=node22 -Djboss.site.name=site2 \ -Djboss.default.multicast.address=234.56.78.2 -Dremote.cache.host=jdg2 \ -Djava.net.preferIPv4Stack=true -b PUBLIC_IP_ADDRESS
NODE21
をクラスター化する必要があります。Received new cluster view for channel keycloak: [node21|1] (2) [node21, node22]
ログにあるチャネル名とは異なっている可能性があります。 -
次のように、テストを行ってください。
-
http://node11:8080/auth/
に移動し、最初の管理者ユーザーを作成します。 -
http://node11:8080/auth/admin
に移動し、管理者として管理コンソールにログインします。 -
2つ目のブラウザーを開き、
http://node12:8080/auth/admin
またはhttp://node21:8080/auth/admin
もしくはhttp://node22:8080/auth/admin
のいずれかのノードに移動します。ログイン後、4つのすべてのサーバー上の特定のユーザー、クライアントまたはレルムのSessions
タブで同じセッションを表示できます。 -
Keycloakの管理コンソールで変更(たとえば、ユーザーやレルムの更新など)を加えた後、その変更は、すぐに4つのノードのいずれかで表示され、キャッシュがどこでも適切に無効化される必要があります。
-
必要に応じてserver.logsを確認してください。ログインまたはログアウト後、以下のようなメッセージがすべての
NODEXY/standalone/log/server.log
ノードに表示される必要があります。2017-08-25 17:35:17,737 DEBUG [org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener] (Client-Listener-sessions-30012a77422542f5) Received event from remote store. Event 'CLIENT_CACHE_ENTRY_REMOVED', key '193489e7-e2bc-4069-afe8-f1dfa73084ea', skip 'false'
-
3.4.9. Cross DCデプロイメントの管理
このセクションでは、クロスデータセンター・レプリケーションに関するオプションとヒントについて説明します。
-
Keycloakサーバーをデータセンター内で実行する場合、
KeycloakDS
データソース内で参照されたデータベースがすでに実行され、そのデータセンター内で使用可能である必要があります。また、 Infinispanキャッシュのremote-store
要素から参照されるoutbound-socket-binding
によって参照されたInfinispanサーバーがすでに実行されてることが必要です。そうしないと、Keycloakサーバーは起動に失敗します。 -
データベース・フェイルオーバーと高い信頼性をサポートする必要がある場合、すべてのデータセンターでより多くのデータベース・ノードを持たせます。データベース側での設定方法とKeycloak側の
KeycloakDS
データソースで必要な設定方法の詳細については、JDBCドライバーのドキュメントを参照してください。 -
すべてのデータセンターで、より多くのInfinispanサーバーをクラスター内で実行することができます。これは、フェイルオーバーとフォールト・トレランスを強化する場合に便利です。InfinispanサーバーとKeycloakサーバー間の通信で使用されるHotRodプロトコルには、InfinispanサーバーがInfinispanクラスターの変更について、Keycloakサーバーに新しいトポロジーを自動的に送信する機能を備えています。したがって、Keycloak側のリモートストアは、どのInfinispanサーバーに接続できるのかが分かります。詳細については、InfinispanとWildFlyドキュメントを参照してください。
-
どんな サイトのKeycloakサーバーも起動する前に、すべてのサイトでマスターInfinispanサーバーを実行することを強くお勧めします。この例では、すべてのKeycloakサーバーの前に、
jdg1
とjdg2
の両方を最初に起動します。Keycloakサーバーをそれでも実行する必要があり、バックアップ・サイトがオフラインである場合は、サイトをオフラインおよびオンラインにするでの説明のとおり、サイトのInfinispanサーバー上のバックアップ・サイトを手動でオフラインに切り替えることをお勧めします。使用できない状態のサイトをオフラインに手動で切り替えることができない場合、初回起動に失敗するか、起動時にいくつか例外が発生する可能性があります。これは、失敗した操作の設定数によってバックアップ・サイトが自動的にオフラインになるまでです。
3.4.10. サイトをオフラインおよびオンラインにする
たとえば、以下のようなシナリオを想定します。
-
サイト
site2
は、site1
の観点から完全にオフラインです。これは、site2
のすべてのInfinispanサーバーがオフである、 または 、site1
とsite2
の間のネットワークが切断されていることを意味します。 -
サイト
site1
でKeycloakサーバーとInfinispanサーバーjdg1
を実行します。 -
いずれかのユーザーが
site1
のKeycloakサーバーにログインします。 -
site1
のKeycloakサーバーは、site2
のjdg2
サーバーにデータをバックアップすることを想定し、jdg1
サーバー上のリモート・キャッシュにセッションを書き込もうとします。 詳細については、コミュニケーションの詳細を参照してください。 -
jdg2
サーバーがオフラインであるか、jdg1
から到達できない状態なので、jdg1
からjdg2
へのバックアップは失敗します。 -
例外は
jdg1
のログにスローされます。デフォルトのFAIL
バックアップ失敗ポリシーが設定されているため、その失敗はjdg1
サーバーからKeycloakサーバーにも伝播されます。バックアップ・ポリシーの詳細については、バックアップ失敗ポリシーを参照してください。 -
このエラーはKeycloak側でも発生し、ユーザーはログインを完了できない可能性もあります。
使用している環境に応じて、サイト間のネットワークが利用できないか、一時的に壊れている(スプリット・ブレイン)可能性があります。これが起こった場合、 site1
のInfinispanサーバーは、 site2
のInfinispanサーバーが利用できないことに気付き、 jdg2
サイトのサーバーへアクセスしようとするのを止めるため、バックアップの失敗は発生しません。これは サイトをオフラインにする
と呼ばれています。
サイトをオフラインにするには2つの方法があります。
管理者による手作業 - 管理者は jconsole
または他のツールを使用して、いくつかのJMX操作を実行することで、手動で特定のサイトをオフラインにすることができます。これは、特に停止が計画されている場合に役立ちます。 jconsole
またはCLIを使用すると、 jdg1
サーバーに接続し、 site2
をオフラインにすることができます。この詳細については、 JDGドキュメント を参照してください。
SYNCまたはASYNCバックアップで述べた他のすべてのKeycloakキャッシュについても、通常はこれらの手順を実行する必要があります。 |
自動的作業 - バックアップに失敗した後、通常は site2
が自動的にオフラインになります。これは、Infinispanサーバーの設定で設定されたキャッシュ構成内の take-offline
要素の設定によって行われます。
<take-offline min-wait="60000" after-failures="3" />
この例では、少なくとも3回連続して失敗したバックアップがあり、60秒以内にバックアップが成功しなかった場合、特定のシングルキャッシュに対してサイトが自動的にオフラインになることを示しています。
自動的にサイトをオフラインにすることは、特に、サイト間の切断されたネットワークが計画外である場合に便利です。欠点は、ネットワークの停止が検出されるまで何らかのバックアップが失敗し、アプリケーション側で障害が起きてる可能性があります。たとえば、一部のユーザーのログインに失敗したり、大きなログインタイムアウトが発生したりします。たとえば、一部のユーザーのログインに失敗したり、大きなログインタイムアウトが発生したりします。 特に、値が FAIL
の failure-policy
が使用されている場合です。
サイトがオフラインであるかどうかの追跡は、キャッシュごとに個別に追跡されます。 |
一旦ネットワークが復旧し、 site1
と site2
がお互いに通信することができたら、サイトをオンラインにする必要があります。これは、サイトをオフラインにするのと同じように、JMXまたはCLIを使用して手動で行う必要があります。再度キャッシュをすべてチェックし、オンラインにする必要があります。
サイトをオンラインにしたら、通常は次のようにするのが良いです。
-
ステート・トランスファーを行います。
-
手動でキャッシュのクリアを行います。
3.4.11. ステート・トランスファー
ステート・トランスファーは、手動で行う必要があります。Infinispanサーバーはこれを自動的には行いません。たとえば、スプリット・ブレイン中は、管理者のみが誰がどのサイトを優先するかを決定することができます。したがって、ステート・トランスファーが両方のサイト間で双方向に、または site1
から site2
へのみ単方向で行われる必要がありますが、site2
から site1
への単方向は行われません。
双方向のステート・トランスファーによって、スプリット・ブレインの 後に site1
で作成されたエンティティーが site2
に確実に転送されます。これは site2
ではまだ発生していないので問題ありません。同じように、スプリット・ブレインの 後に site2
で作成されたエンティティーは site1
に転送されます。おそらく問題のある部分は、両方のサイトのスプリット・ブレインの 前に 存在し、両方のサイトのスプリット・ブレイン中に更新されたエンティティーです。これが発生すると、サイトの1つが 勝ち 、2番目のサイトがスプリット・ブレイン中に行った更新を上書きします。
残念ながら、これに対する広く一般的な解決方法はありません。スプリット・ブレインやネットワークの停止は状態に過ぎず、サイト間で100%の一貫性のあるデータで100%正確に処理することは通常不可能です。Keycloakの場合、これは特に重大な問題ではありません。最悪の場合、ユーザーがクライアントに再度ログインするか、loginFailuresの不正カウント数をブルートフォース保護のために追跡する必要があります。スプリット・ブレインに対処するためのヒントについては、Infinispan/JGroupsドキュメントを参照してください。
ステート・トランスファーは、JMXを介してInfinispanサーバー側でも行われます。操作名は pushState
です。状態をモニタリングしたり、プッシュ状態をキャンセルしたりするその他の操作はほとんどありません。ステート・トランスファーの詳細については、 Infinispan docs を参照してください。
3.4.12. キャッシュのクリア
スプリット・ブレイン後は、Keycloakの管理コンソールで手動でキャッシュをクリアするのが安全です。これは、 site1
のデータベースで変更されたデータがあり、イベントのために無効にする必要のあるキャッシュが、スプリット・ブレイン中に site2
へ転送されなかった可能性があるためです。したがって、 site2
のKeycloakノードでは、キャッシュ内に古いデータがまだ残っている可能性があります。
キャッシュをクリアするには、 サーバー・キャッシュのクリア を参照してください。
ネットワークが復旧したら、いずれかのサイトの1つのKeycloakノードでキャッシュをクリアするだけで十分です。キャッシュの無効化イベントは、それぞれのサイトの他のKeycloakノードすべてに送られます。ただし、すべてのキャッシュ(レルム、ユーザー、鍵)に対して実行する必要があります。詳しくは、サーバー・キャッシュのクリアを参照してください。
3.4.13. JDGキャッシュ設定のチューニング
このセクションでは、JDGキャッシュを設定するためのヒントとオプションについて説明します。
デフォルトでは、JDG clustered.xml
ファイルのInfinispanキャッシュ設定のバックアップ failure-policy
の設定は、 FAIL
として設定されています。必要に応じて WARN
または IGNORE
に変更することができます。
FAIL
と WARN
の違いは、 FAIL
が使用され、Infinispanサーバーが別のサイトにデータのバックアップを試みたときに、バックアップが失敗すると、その失敗が呼び出し側(Keycloakサーバー)に伝播されるという点です。2番目のサイトが一時的に到達不能になったり、同じエンティティーの更新を試みる同時トランザクションが発生した場合は、バックアップが失敗する可能性があります。この場合、Keycloakサーバーは複数回再試行します。ただし、その再試行が失敗した場合、より長いタイムアウト後、ユーザーにはエラーが表示されます。
WARN
を使用すると、失敗したバックアップは、InfinispanサーバーからKeycloakサーバーに伝播されません。失敗したバックアップは無視され、ユーザーにはエラーが表示されません。バックアップのデフォルトのタイムアウトは10秒間であるため短いです。これは、 backup
要素の timeout
属性によって変更することができます。タイムアウトにおける再試行はありません。タイムアウト時は、InfinispanサーバーのログにWARNINGメッセージが表示されます。
潜在的な課題としては、いくつかのケースで、再試行( FAIL
ポリシーの使用)が役に立つサイト間で短いネットワーク停止が発生する可能性があるため、 WARN
(再試行なし)では、サイト間でデータの不整合が発生します。これは、両方のサイトで同時に同じエンティティーを更新しようとする際にも発生します。
これらの不整合はどれくらいよろしくないのでしょうか?通常は、ユーザーが再認証する必要があることを意味します。
WARN
ポリシーを使用すると、 actionTokens
キャッシュにより提供され、その特定のキーを処理する、使い捨てのキャッシュが実際に1回使用されますが、同じキーが2回"正常に"書き込まれる可能性があります。しかし、たとえば、OAuth2 仕様mentionsでは、コードは使い捨てでなければならないと言及されています。 WARN
ポリシーでは、これは厳密には保証されておらず、両方のサイトで同時に書き込まれる試みがあった場合、同じコードが2回書き込まれる可能性があります。
より長いネットワーク停止またはスプリット・ブレインが起きた場合、 FAIL
と WARN
を使用すると、サイトをオフラインおよびオンラインにするで説明したとおり、少し時間を置いて失敗した後、他のサイトはオフラインになります。デフォルトの1分のタイムアウトでは、関連するキャッシュがすべてオフラインになるまで、通常は1~3分かかります。その後、エンドユーザーの観点から、動作はすべて問題なく進みます。サイトをオフラインおよびオンラインにするで説明したとおり、オンラインに戻ったときに手動でサイトを復元する必要があります。
要約すると、サイト間で頻繁により長い停止が発生する可能性があり、データの不整合と100%正確ではない使い捨てのキャッシュについては許容されますが、エラーや長いタイムアウトがエンドユーザーに表示されないようにする場合には、 WARN
に切り替えます。
WARN
と IGNORE
の違いは、 IGNORE
警告がJDGログに書き込まれていないことです。詳細については、Infinispanのドキュメントを参照してください。
デフォルト設定では、NON_DURABLE_XAモードでトランザクションを取得タイムアウト0で使用しています。これは、同じキーに対して進行中の別のトランザクションがある場合、トランザクションはすぐに失敗することを意味します。
デフォルトの10秒ではなく0に切り替えるのは、デッドロックの可能性を避けるためです。Keycloakでは、同じエンティティー(通常はセッション・エンティティーまたはloginFailure)が両方のサイトから同時に更新されることがあります。これにより、状況によってはデッドロックが発生し、トランザクションが10秒間ブロックされる可能性があります。 詳細については、このJIRAレポートを参照してください。
タイムアウト0の場合、トランザクションは直ちに失敗し、値 FAIL
のバックアップ failure-policy
が設定されていれば、Keycloakから再試行されます。2番目の同時トランザクションが終了するまで、通常は再試行が成功し、エンティティーは両方の同時トランザクションから更新を適用します。
この設定での同時トランザクションは、非常に良い一貫性と結果が得られるため、そのまま使用することをお勧めします。
唯一の(機能しない)問題は、Infinispanサーバーログの例外です。これは、ロックがすぐに利用できなくなるたびに発生します。
3.4.14. SYNCまたはASYNCバックアップ
backup
要素の重要な部分は strategy
属性です。 SYNC
と SYNC
のどちらが必要かを決める必要があります。クロスデータセンター・レプリケーションを認識できる7つのキャッシュがあり、これらは、クロスデータセンターに対する次の3つの異なるモードで設定できます。
-
SYNCバックアップ
-
ASYNCバックアップ
-
バックアップを全くしない
SYNC
バックアップが使用された場合、バックアップが同期され、バックアップが2番目のサイトで処理されると、呼び出し側(Keycloakサーバー)で操作が完了したとみなされます。これは ASYNC
よりもパフォーマンスが劣りますが、一方で、 site2
のユーザー・セッションなど特定のエンティティーの後続の読み込みによって、 site1
からの更新が確実に確認されます。また、データの一貫性が必要な場合は、これは必須になります。 ASYNC
の場合と同様に、他のサイトへのバックアップが失敗した場合は、呼び出し側には全く通知されません。
キャッシュによっては、バックアップをまったく取らず、Infinispanサーバーへのデータ書き込みを完全にスキップすることも可能です。これを設定するには、 Keycloak側( KEYCLOAK_HOME/standalone/configuration/standalone-ha.xml
ファイル)の特定のキャッシュに remote-store
要素を使用しないでください。また、特定の replicated-cache
要素もInfinispanサーバー側では必要ありません。
デフォルトでは、7つのキャッシュすべてが最も安全なオプションである SYNC
バックアップで設定されています。考慮すべき点は次のとおりです。
-
アクティブ/パッシブモード(すべてのKeycloakサーバーが単一のサイト
site1
にあり、site2
にあるInfinispanサーバーが純粋にバックアップとしてのみ使用されます。詳しくは モードを参照してください)を使用している場合、パフォーマンスを低下させないよう、すべてのキャッシュにASYNC
方式を使用するのが通常は望ましいです。 -
work
キャッシュは、主に、キャッシュ無効化イベントなどのいくつかのメッセージを他のサイトに送信するために使用されます。また、userStorageの同期化などの特別なイベントが単一のサイトでのみ発生するようにするためにも使用されます。これをSYNC
に設定することを推奨します。 -
actionTokens
キャッシュは、使い捨てのキャッシュとして使用され、トークンまたはチケットが1回だけ使用されたということを追跡します。たとえば、アクショントークンまたはOAuth2コードです。これをASYNC
に設定して、パフォーマンスをわずかに向上させることは可能ですが、特定のチケットが実際に1回だけ使用され使い捨てになるかは保証されていません。たとえば、両方のサイトで同じチケットの同時リクエストがある場合、ASYNC
方式によって両方のリクエストが成功する可能性があります。そのため、ここでの設定は、より高いセキュリティー(SYNC
方式)またはより高いパフォーマンス(ASYNC
方式)のどちらを優先するかによります。 -
loginFailures
キャッシュは、3つのモードのいずれかで使用できます。バックアップがまったくない場合、ユーザーのログイン失敗のカウントがサイトごとに個別にカウントされることを意味します(詳しくはInfinispanキャッシュを参照してください)。これにはいくつかのセキュリティー上の意味がありますが、パフォーマンス上の利点があります。また、サービス拒否(DoS)攻撃のリスクを軽減します。たとえば、攻撃者が両方のサイトでユーザーのユーザー名とパスワードを使用して1000件の同時リクエストをシミュレートすると、サイト間で多くのメッセージが渡され、ネットワークの混雑が発生する可能性があります。ASYNC
方式は、攻撃者のリクエストが他のサイトへのバックアップを待つことによってブロックされず、潜在的にさらに混雑したネットワーク・トラフィックを招くため、状況は悪化する可能性があります。ログイン失敗のカウントもASYNC
方式では正確ではありません。
データセンター間のネットワークが遅く、DoSの確率が高い環境では、 loginFailures
キャッシュをまったくバックアップしないことが推奨されます。
-
sessions
とclientSessions
キャッシュをSYNC
で保持しておくことをお勧めします。ユーザーのリクエストとバックチャネル要求(リクエスト処理で説明したクライアント・アプリケーションからKeycloakへのリクエスト)が常に同じサイトで処理されることが確かな場合にのみ、それらをASYNC
へ切り替えることが可能になります。たとえば、次のような場合はこれが当てはまります。-
モードで説明した通り、アクティブ/パッシブモードを使用しています。
-
クライアント・アプリケーションはすべてKeycloak JavaScriptアダプターを使用しています。JavaScriptアダプターは、ブラウザー内でバックチャネル要求を送信するため、それらはブラウザーのスティッキー・セッションに参加し、このユーザーの別のブラウザー・リクエストと同じクラスターノード(したがって同じサイト)で終了します。
-
ロードバランサーは、クライアントIPアドレス(ロケーション)に基づいてリクエストを処理でき、クライアント・アプリケーションは両方のサイトにデプロイされています。
たとえば、ロンドンとニューヨークの2つのサイトがあります。 アプリケーションがロンドンサイトとニューヨークサイトの両方に配備されている場合は、ロンドンユーザーからのすべてのユーザー・リクエストがロンドンサイトのアプリケーションとロンドンサイトのKeycloakサーバーにリダイレクトされるようにすることができます。 ロンドンサイトのクライアント・デプロイメントからのバックチャネル・リクエストは、ロンドンサイトのKeycloakサーバーでも終了します。 一方、米国のユーザーの場合、すべてのKeycloakリクエスト、アプリケーション・リクエスト、バックチャネル・リクエストはニューヨークサイトで処理されます。
-
-
offlineSessions
とofflineClientSessions
に関して、類似していますが、クライアント・アプリケーションのいずれに対してもオフライン・トークンを使用する予定ががない場合、それらをバックアップする必要はまったくありません。
一般的に、懸念があり、パフォーマンスがブロッカーではない場合は、キャッシュを SYNC
方式に保持する方が安全です。
SYNC/ASYNCバックアップへの切り替えに関しては、 backup 要素の strategy 属性を編集してください。たとえば、次のようになります。
|
<backup site="site2" failure-policy="FAIL" strategy="ASYNC" enabled="true">
cache-configuration要素の mode
属性に注意してください。
3.4.15. トラブルシューティング
以下のヒントは、トラブルシューティングが必要な場合に役立ちます。
-
基本設定を行い、最初にこの機能を有効にして、どのように動作するかを理解することをお勧めします。物事を理解するためにこの文書全体を読むことも賢明です。
-
Infinispanサーバーの設定で説明されているように、jconsoleクラスターのステータス(GMS)とInfinispanのJGroupsのステータス(RELAY)をチェックインします。状況が期待どおりに見えない場合、問題はInfinispanサーバーの設定にある可能性があります。
-
Keycloakサーバーの場合、サーバーの起動時に次のようなメッセージが表示されます。
18:09:30,156 INFO [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (ServerService Thread Pool -- 54) Node name: node11, Site name: site1
Keycloakサーバーの起動時に、サイト名とノード名が想定どおりに表示されていることを確認してください。
-
同じデータセンターのKeycloakサーバーだけが互いにクラスター化されていることを含め、Keycloakサーバーが期待どおりにクラスター内にあることを確認してください。これは、GMSビューを介してJConsoleでチェックすることもできます。詳細については、クラスターのトラブルシューティングを参照してください。
-
Keycloakサーバーの起動時に次のような例外が発生した場合。
17:33:58,605 ERROR [org.infinispan.client.hotrod.impl.operations.RetryOnFailureOperation] (ServerService Thread Pool -- 59) ISPN004007: Exception encountered. Retry 10 out of 10: org.infinispan.client.hotrod.exceptions.TransportException:: Could not fetch transport ... Caused by: org.infinispan.client.hotrod.exceptions.TransportException:: Could not connect to server: 127.0.0.1:12232 at org.infinispan.client.hotrod.impl.transport.tcp.TcpTransport.<init>(TcpTransport.java:82)
これは通常、Keycloakサーバーが自身のデータセンター内のInfinispanサーバーにアクセスできないことを意味します。ファイアウォールが期待どおりに設定され、Infinispanサーバーが接続可能であることを確認してください。
-
Keycloakサーバーの起動時に次のような例外が発生した場合。
16:44:18,321 WARN [org.infinispan.client.hotrod.impl.protocol.Codec21] (ServerService Thread Pool -- 57) ISPN004005: Error received from the server: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction. ...
サイトの該当するInfinispanサーバーのログをチェックし、他のサイトへのバックアップに失敗したかどうかを確認します。バックアップ・サイトが利用できない場合は、Infinispanサーバーがオフラインサイトにバックアップしようとしないようにオフラインに切り替えて、Keycloakサーバー側で正常に操作が成功するようにすることをお勧めします。詳細については、Cross DCデプロイメントの管理を参照してください。
-
JMXを介して利用可能なInfinispanの統計を確認してください。たとえば、ログインして、新しいセッションがInfinispanサーバーの両方に正常に書き込まれたかどうかを確認し、そこの
sessions
キャッシュで利用可能かどうかを確認します。これは、MBeanjboss.datagrid-infinispan:type=Cache,name="sessions(repl_sync)",manager="clustered",component=Statistics
とnumberOfEntries
属性のsessions
キャッシュ内の要素の数をチェックすることによって間接的に行うことができます。ログイン後、両方のサイトのそれぞれのInfinispanサーバーにnumberOfEntries
のための1つ以上のエントリーが存在するはずです。 -
Keycloakサーバーの設定の説明に従って、DEBUGロギングを有効にします。 たとえば、ログインして2番目のサイトで新しいセッションが利用できないと思われる場合は、Keycloakサーバーログをチェックし、Keycloakサーバーの設定で説明したようにリスナーがトリガーされていることを確認してください。 keycloak-userメーリングリストに質問したい場合は、電子メール内の両方のデータセンターのKeycloakサーバーからログファイルを送信すると便利です。ログスニペットをメールに追加するか、ログをどこかに置いて電子メールで参照してください。
-
site1
のKeycloakサーバーでuser
などのエンティティーを更新しても、site2
のKeycloakサーバーで更新したエンティティーが表示されない場合は、同期したデータベース自体のレプリケーションか、Keycloakキャッシュが適切に無効化されなかったかのどちらかに問題があります。問題がデータベースのレプリケーション・レベルにある場合は、ここで説明するように一時的にKeycloakキャッシュを無効化してください。また、データベースに手動で接続し、データが期待どおりに更新されるかどうかを確認するのに役立ちます。これはすべてのデータベースに固有のものなので、データベースのドキュメントを参照する必要があります。 -
場合によっては、Infinispanサーバーログに次のようなロックに関する例外が表示されることがあります。
(HotRodServerHandler-6-35) ISPN000136: Error executing command ReplaceCommand, writing keys [[B0x033E243034396234..[39]]: org.infinispan.util.concurrent.TimeoutException: ISPN000299: Unable to acquire lock after 0 milliseconds for key [B0x033E243034396234..[39] and requestor GlobalTx:jdg1:4353. Lock is held by GlobalTx:jdg1:4352
これらの例外は必ずしも問題ではありません。両方のデータセンターで同じエンティティーの同時編集がトリガーされると、いつでも発生する可能性があります。これは、デプロイメントの多くの場合に当てはまります。たいてい、Keycloakサーバーは、失敗した操作について通知を受けて再試行するため、ユーザーの観点からは通常問題はありません。
-
Keycloakサーバーの起動時に次のような例外が発生した場合。
16:44:18,321 WARN [org.infinispan.client.hotrod.impl.protocol.Codec21] (ServerService Thread Pool -- 55) ISPN004005: Error received from the server: java.lang.SecurityException: ISPN000287: Unauthorized access: subject 'Subject with principal(s): []' lacks 'READ' permission ...
これらのログエントリーはKeycloakの結果で、Infinispanで認証が必要かどうかを自動的に検出し、認証が必要であることを意味します。この時点で、サーバーが正常に起動され、これらを無視しても問題ないか、またはサーバーの起動に失敗していることに気づきます。サーバーの起動に失敗した場合は、Infinispanが Infinispanサーバーの設定 で説明されているように認証のために正しく設定されていることを確認してください。このログエントリーが含まれないように、
spi=connectionsInfinispan/provider=default
の設定でremoteStoreSecurityEnabled
プロパティーをtrue
に設定して認証を強制できます。<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1"> ... <spi name="connectionsInfinispan"> ... <provider name="default" enabled="true"> <properties> ... <property name="remoteStoreSecurityEnabled" value="true"/> </properties> </provider> </spi>
-
Keycloakでアプリケーションに認証しようとすると、ブラウザーの無限のリダイレクトで認証に失敗し、Keycloakサーバーログに次のようなエラーが表示されます。
2017-11-27 14:50:31,587 WARN [org.keycloak.events] (default task-17) type=LOGIN_ERROR, realmId=master, clientId=null, userId=null, ipAddress=aa.bb.cc.dd, error=expired_code, restart_after_timeout=true
おそらく、ロードバランサーを スティッキー・セッションをサポートするように設定する必要があることを意味します。Keycloakサーバー(プロパティー
jboss.node.name
)の起動時に使用される指定されたルート名に、 ロードバランサー・サーバーが現在のサーバーを識別するために使用する正しい名前が含まれていることを確認してください。 -
Infinispanの
work
キャッシュが無期限に増加した場合、https://issues.jboss.org/browse/JDG-987[このInfinispanの問題]が発生している可能性があります(キャッシュが正しく期限切れになっていないことに起因する問題)。その場合、キャッシュ宣言を次のような空の<expiration />
タグで更新してください。<replicated-cache name="work" configuration="sessions-cfg"> <expiration /> </replicated-cache>
-
Infinispanサーバーのログに次のような警告が表示された場合は、
18:06:19,687 WARN [org.infinispan.server.hotrod.Decoder2x] (HotRod-ServerWorker-7-12) ISPN006011: Operation 'PUT_IF_ABSENT' forced to return previous value should be used on transactional caches, otherwise data inconsistency issues could arise under failure situations 18:06:19,700 WARN [org.infinispan.server.hotrod.Decoder2x] (HotRod-ServerWorker-7-10) ISPN006010: Conditional operation 'REPLACE_IF_UNMODIFIED' should be used with transactional caches, otherwise data inconsistency issues could arise under failure situations
それらを無視することができます。この警告を回避するために、Infinispanサーバー側のキャッシュをトランザクション・キャッシュに変更することができますが、バグ https://issues.jboss.org/browse/ISPN-9323 によって引き起こされるいくつかの他の問題が発生する可能性があるため、これはお勧めしません。したがって、今のところこの警告は無視する必要があります。
-
Infinispanサーバーのログに次のようなエラーが表示された場合は、
12:08:32,921 ERROR [org.infinispan.server.hotrod.CacheDecodeContext] (HotRod-ServerWorker-7-11) ISPN005003: Exception reported: org.infinispan.server.hotrod.InvalidMagicIdException: Error reading magic byte or message id: 7 at org.infinispan.server.hotrod.HotRodDecoder.readHeader(HotRodDecoder.java:184) at org.infinispan.server.hotrod.HotRodDecoder.decodeHeader(HotRodDecoder.java:133) at org.infinispan.server.hotrod.HotRodDecoder.decode(HotRodDecoder.java:92) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248)
また、Keycloakログに類似のエラーが表示された場合は、互換性のないバージョンのHotRodプロトコルが使用されていることを示しています。これは、KeycloakをJDG 7.2サーバーまたは古いバージョンのInfinispanサーバーで使用しようとした場合に発生する可能性があります。Keycloak設定ファイルの
remote-store
要素に、追加のプロパティーとしてprotocolVersion
プロパティーを追加すると役に立ちます。たとえば次のように設定します。<property name="protocolVersion">2.6</property>
4. サブシステム設定の管理
Keycloakの低レベルな設定は、配布物に含まれている standalone.xml
、 standalone-ha.xml
、または domain.xml
ファイルを編集して行います。このファイルの場所は動作モードによって異なります。
ここで設定可能なセッティングは無限にありますが、このセクションでは keycloak-server サブシステムの設定について説明します。どの設定ファイルを使用していても、 keycloak-server サブシステムの設定は同じです。
keycloak-serverサブシステムは通常、以下のようにファイルの末尾で宣言されています。
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<web-context>auth</web-context>
...
</subsystem>
このサブシステム内での変更はサーバーが再起動されるまで有効になりませんので、注意してください。
4.1. SPIプロバイダーの設定
各設定の詳細については、その設定と関連する別の箇所で説明します。ただし、SPIプロバイダー設定の宣言に使用される形式について学ぶことをお勧めします。
Keycloakは、柔軟性に優れた、高度なモジュールシステムです。50以上のサービス・プロバイダー・インターフェイス(いわゆるSPI)があり、各SPIの実装を交換することができます。SPIの実装は provider によって行われます。
SPI宣言のすべての要素は任意で選択できるものですが、完全なSPI宣言は以下のようになります。
<spi name="myspi">
<default-provider>myprovider</default-provider>
<provider name="myprovider" enabled="true">
<properties>
<property name="foo" value="bar"/>
</properties>
</provider>
<provider name="mysecondprovider" enabled="true">
<properties>
<property name="foo" value="foo"/>
</properties>
</provider>
</spi>
ここでは、 myspi
というSPIに2つのプロバイダーが定義されています。 default-provider
は myprovider
と表示されています。しかし、この設定をどのように処理するかはSPIが決定します。SPIによって複数のプロバイダーを許可するものもあれば、そうでないものもあります。そのため、 default-provider
はSPIの選択の手助けになります。
また、各プロバイダーが独自の設定プロパティーを定義することについても注意してください。上記の両方のプロバイダーが foo
というプロパティーを持っている点は単なる偶然です。
プロパティー値のタイプはそれぞれプロバイダーによって解釈されます。ただし、1つ例外があります。 eventsStore
のSPIの jpa
プロバイダーについて確認してみましょう。
<spi name="eventsStore">
<provider name="jpa" enabled="true">
<properties>
<property name="exclude-events" value="["EVENT1",
"EVENT2"]"/>
</properties>
</provider>
</spi>
この値は角括弧で始まり、角括弧で終わることが分かります。これは、値がリストとしてプロバイダーに渡されることを意味します。このサンプルでは、2つの要素値 EVENT1 と EVENT2 のリストはシステムからプロバイダーに渡されます。リストに値を追加するには、各リスト要素をカンマで区切ります。残念ながら、各リスト要素を囲む引用符を "
にエスケープする必要があります。
4.2. WildFlyCLIの起動
設定変更は、手作業で編集するだけでなく、 jboss-cli ツールでコマンドを発行して行うこともできます。CLIを使用すると、サーバーをローカルでもリモートでも設定することができます。スクリプティングと組み合わせると特に便利です。
WildFlyCLIを起動するには、 jboss-cli
を実行する必要があります。
$ .../bin/jboss-cli.sh
> ...\bin\jboss-cli.bat
これを実行すると、以下のようにプロンプトが表示されます。
[disconnected /]
実行中のサーバーでコマンドを実行する場合、まず connect
コマンドを実行します。
[disconnected /] connect
connect
[standalone@localhost:9990 /]
ここでユーザー名もパスワードも入力していないと思うかもしれませんが、 jboss-cli
を実行中のスタンドアローン・サーバーまたはドメイン・コントローラーと同じマシンで実行し、アカウントに適切なファイル・アクセス権限がある場合は、管理者のユーザー名とパスワードを設定または入力する必要はありません。この設定では心配でよりセキュアにしたい場合は、詳しくはWildFly 13 Documentationを参照してください。
4.3. CLI組み込みモード
サーバーがアクティブではない間にスタンドアローン・サーバーと同じマシン上にコマンドが発行された場合は、サーバーをCLIに組み込み、受信要求を許可しない特殊モードに変更することができます。これを行うには、まず、変更したい設定ファイルで embed-server
コマンドを実行します。
[disconnected /] embed-server --server-config=standalone.xml
[standalone@embedded /]
4.4. CLI GUIモード
CLIはGUIモードでも実行できます。GUIモードでは、実行中のサーバーの管理モデル全体をグラフィカルに表示および編集できるSwingアプリケーションが起動します。GUIモードは、CLIコマンドの書式を設定したり、オプションを調べる際のヘルプとして特に便利です。GUIは、ローカルまたはリモートサーバーからサーバーログを取得することもできます。
$ .../bin/jboss-cli.sh --gui
Note: リモートサーバーに接続するには、 --connect
オプションも渡します。詳しくは、 --helpオプションを参照してください。
GUIモードを起動したら、スクロールダウンすると subsystem=keycloak-server
ノードが見つかります。ノードを右クリックして Explore subsystem=keycloak-server
をクリックすると、keycloak-serverサブシステムのみを表示する新しいタブが表示されます。
4.5. CLIスクリプト
CLIには、さまざまなスクリプト機能があります。スクリプトはCLIコマンドを含む単なるテキストファイルです。テーマとテンプレートのキャッシュをオフにする簡単なスクリプトを見ていきましょう。
/subsystem=keycloak-server/theme=defaults/:write-attribute(name=cacheThemes,value=false)
/subsystem=keycloak-server/theme=defaults/:write-attribute(name=cacheTemplates,value=false)
スクリプトを実行するには、CLI GUI の Scripts
メニューに従う、または以下のようにコマンドラインからスクリプトを実行します。
$ cd bin
$ ./jboss-cli.sh --file=adapter-install-offline.cli
4.6. CLIレシピ
ここでは、設定タスクおよびそれらをCLIコマンドで実行する方法について説明します。代入すべきという意味で、またはkeycloak-serverサブシステムという意味でワイルドカード・パス **
を使用しています。その点は注意してください。
スタンドアローンの場合、これは単に以下の意味になります。
**
= /subsystem=keycloak-server
ドメインモードの場合、これは以下のような意味になります。
**
= /profile=auth-server-clustered/subsystem=keycloak-server
4.6.1. サーバーのwebコンテキストの変更
/subsystem=keycloak-server/:write-attribute(name=web-context,value=myContext)
4.6.6. dblock SPIの設定
**/spi=dblock/:add(default-provider=jpa)
**/spi=dblock/provider=jpa/:add(properties={lockWaitTimeout => "900"},enabled=true)
4.6.7. プロバイダーのシングル・プロパティー値の追加または変更
**/spi=dblock/provider=jpa/:map-put(name=properties,key=lockWaitTimeout,value=3)
5. Profiles
Keycloakには、デフォルトでは有効とされていない機能があり、完全にはサポートされていないものがあります。さらに、デフォルトで有効とされている機能を無効にすることもできます。
有効および無効にできる機能は、以下のとおりです。
Name | Description | デフォルトで有効 | サポートレベル |
---|---|---|---|
account2 |
新しいアカウント管理コンソール |
No |
Experimental |
account_api |
アカウント管理REST API |
No |
Preview |
admin_fine_grained_authz |
きめ細かい管理権限 |
No |
Preview |
authz_drools_policy |
認可サービス用のDroolsポリシー |
No |
Preview |
docker |
Dockerレジストリーのプロトコル |
No |
Supported |
impersonation |
管理者がユーザーに成り代わる機能 |
Yes |
Supported |
openshift_integration |
OpenShiftを保護するための拡張 |
No |
Preview |
script |
Javaスクリプトを使用したカスタム認証の記述 |
Yes |
Preview |
token_exchange |
Token Exchangサービス |
No |
Preview |
すべてのプレビュー機能を有効にするには、次のようにサーバーを起動します。
bin/standalone.sh|bat -Dkeycloak.profile=preview
standalone/configuration/profile.properties
(またはドメインモード内の server-one
用の domain/servers/server-one/configuration/profile.properties
)ファイルを作成することにより、これを永続的に設定することができます。以下をファイルに追加します。
profile=preview
特定の機能を有効にするには、以下のようにサーバーを起動します。
bin/standalone.sh|bat -Dkeycloak.profile.feature.<feature name>=enabled
サンプルとして、Dockerを有効にするには -Dkeycloak.profile.feature.docker=enabled
を使用します。
profile.properties
ファイルに以下を追加することにより、永続的に設定することができます。
feature.docker=enabled
特定の機能を無効にするには、以下のようにサーバーを起動します。
bin/standalone.sh|bat -Dkeycloak.profile.feature.<feature name>=disabled
サンプルとして、代理ログイン機能を無効にするには -Dkeycloak.profile.feature.impersonation=disabled
を使用します。
profile.properties
ファイルに以下を追加することにより、永続的に設定することができます。
feature.impersonation=disabled
6. リレーショナル・データベースの設定
Keycloakには、H2というJavaベースのリレーショナル・データベースが組み込まれています。これは、Keycloakがデータを保存するために使用するデフォルトのデータベースで、単に認証サーバーをそのまま実行できるように組み込まれただけのものです。そのため、プロダクション用の外部データベースに置き換えることを強くお勧めします。H2データベースは並行性の高いシチュエーションではあまり実用的ではないので、クラスター内でも使用しないでください。この章では、Keycloakをより成熟度の高いデータベースに接続する方法を説明します。
Keycloakでは、リレーショナル・データを保存するために2つの階層化技術が使用されます。最下層の技術はJDBCです。JDBCは、RDBMSへの接続に使用されるJavaAPIです。データベース・ベンダーによって提供されるデータベース・タイプ毎に、さまざまなJDBCドライバーがあります。この章では、これらのベンダー固有のドライバーのいずれかを使用するようにKeycloakを設定する方法について説明します。
データを保存するための最上層の技術は、Hibernate JPAです。これは、Javaオブジェクトをリレーショナル・データにマップするORマッピングAPIの1つです。Keycloakのデプロイメントで、Hibernateの設定に触れる必要はほとんどありませんが、そのまれなケースに遭遇した場合どうなるかを説明します。
データソースの設定については、 WildFly 13 Documentation の中のデータソース設定の章the datasource configuration chapterで詳しく説明しています。 |
6.1. RDBMS設定のチェックリスト
Keycloak用にRDBMSを設定するための手順は、以下のとおりです。
-
データベース用のJDBCドライバーの検索とダウンロード
-
ドライバーのJARをモジュールにパッケージ化し、このモジュールをサーバーにインストール
-
サーバーの設定プロファイルでJDBCドライバーを宣言
-
データベースのJDBCドライバーを使用するようにデータソース設定を変更
-
データベースへの接続パラメーターを定義するようにデータソース設定を変更
この章では、すべてのサンプルにおいてPostgreSQLを使用します。他のデータベースも同じ手順でインストールできます。
6.2. JDBCドライバーのパッケージ化
RDBMS用のJDBCドライバーのJARを検索してダウンロードします。このドライバーを使用する前に、モジュールにパッケージ化してサーバーにインストールする必要があります。モジュールによって、KeycloakのクラスパスにロードされるJAR、およびこれらのJARが他のモジュールに持つ依存関係が定義されます。設定は非常に簡単です。
Keycloakの配布物の …/modules/ ディレクトリー内で、モジュール定義を保持するディレクトリー構造を作成する必要があります。規約では、ディレクトリー構造の名前にJDBCドライバーのJavaパッケージ名を使用します。PostgreSQLの場合、 org/postgresql/main ディレクトリーを作成します。このディレクトリーにデータベース・ドライバーのJARをコピーし、その中に空の module.xml ファイルも作成します。
これを行った後、 module.xml ファイルを開き、以下のXMLを作成します。
<?xml version="1.0" ?>
<module xmlns="urn:jboss:module:1.3" name="org.postgresql">
<resources>
<resource-root path="postgresql-9.4.1212.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
モジュール名は、モジュールのディレクトリー構造と一致する必要があります。したがって、 org/postgresql は org.postgresql
にマッピングされます。ドライバーのJARファイル名は、 resource-root
の path
の属性によって指定される必要があります。残りの部分は、JDBCドライバーのJARが持つ通常の依存関係になります。
6.3. JDBCドライバーの宣言とロード
次に、新しくパッケージ化されたJDBCドライバーをデプロイメント・プロファイルに宣言して、ロードし、サーバーの起動時に使用できるようにする必要があります。この操作を行う場所は、動作モードによって異なります。標準モードでデプロイしている場合は、 …/standalone/configuration/standalone.xml を編集します。ドメインモードでデプロイしている場合は、 …/domain/configuration/domain.xml を編集します。ドメインモードでは、 auth-server-standalone
または auth-server-clustered
のどちらか使用している方のプロファイルを必ず編集する必要があります。
プロファイル内で、 datasources
サブシステム内の drivers
のXMLブロックを検索すると、H2 JDBCドライバー用に宣言された定義済みのドライバーが見つかります。ここで、外部データベース用のJDBCドライバーを宣言します。
<subsystem xmlns="urn:jboss:domain:datasources:5.0">
<datasources>
...
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
drivers
のXMLブロック内で、追加のJDBCドライバーを宣言する必要があります。それに name
を付けて、必要時に選択できるようにします。ドライバーのJAR用に以前作成した module
パッケージを指す、 module
属性を指定します。最後に、ドライバーのJavaクラスを指定します。サンプルとして、この章で以前定義したモジュールのサンプル内にある、PostgreSQLドライバーをインストールすると下記のとおりになります。
<subsystem xmlns="urn:jboss:domain:datasources:5.0">
<datasources>
...
<drivers>
<driver name="postgresql" module="org.postgresql">
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
</driver>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
6.4. Keycloakデータソースの変更
JDBCドライバーを宣言したら、Keycloakが新しい外部データベースに接続するために使用する既存のデータソース設定を変更する必要があります。これは、JDBCドライバーを登録したのと同じ設定ファイルとXMLブロック内で行います。サンプルとして、新しいデータベースへの接続を設定すると以下のとおりになります。
<subsystem xmlns="urn:jboss:domain:datasources:5.0">
<datasources>
...
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
<connection-url>jdbc:postgresql://localhost/keycloak</connection-url>
<driver>postgresql</driver>
<pool>
<max-pool-size>20</max-pool-size>
</pool>
<security>
<user-name>William</user-name>
<password>password</password>
</security>
</datasource>
...
</datasources>
</subsystem>
KeycloakDS
用の datasource
定義を検索します。まず connection-url
を変更する必要があります。この接続URL値の形式は、ベンダーのJDBC実装のドキュメントで指定されています。
次に、使用する driver
を定義します。これは、この章の前のセクションで宣言したJDBCドライバーの論理名になります。
トランザクションを実行するたびにデータベースへの新しい接続を開くのは処理コストがかかります。これを補うために、データソース実装は開いた接続のプールを維持します。 max-pool-size
によって、プールする接続の最大数が指定されます。システムの負荷に応じて、この値を変更することができます。
最後に、少なくともPostgreSQLでは、データベースへの接続に必要なデータベースのユーザー名とパスワードを定義する必要があります。このサンプルでは、これが簡単なテキストであることを心配されるかもしれませんが、難読化する方法は複数あります。しかし、それはこのガイドの範囲外となります。
データソース機能について、詳しくは WildFly 13 Documentation 内のthe datasource configuration chapterを参照してください。 |
6.5. データベース設定
配布物内の standalone.xml
、 standalone-ha.xml
、 domain.xml
のいずれかの中にこのコンポーネント用の設定があります。このファイルの場所は動作モードによって異なります。
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
...
<spi name="connectionsJpa">
<provider name="default" enabled="true">
<properties>
<property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
<property name="initializeEmpty" value="false"/>
<property name="migrationStrategy" value="manual"/>
<property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
</properties>
</provider>
</spi>
...
</subsystem>
設定可能なオプションは、以下のとおりです。
- dataSource
-
データソースのJNDI名
- jta
-
データソースがJTA対応かどうか指定するbooleanプロパティー
- driverDialect
-
データベース・ダイアレクトの値。ほとんどの場合、ダイアレクトはHibernateによって自動検出されるため、このプロパティーを指定する必要はありません。
- initializeEmpty
-
空の場合はデータベースを初期化します。falseに設定する場合、データベースを手動で初期化する必要があります。データベースを手動で初期化するには、migrationStrategyを
manual
に設定し、データベース初期化用のSQLコマンドが書かれたファイルを作成します。デフォルトはtrueになっています。 - migrationStrategy
-
データベースの移行に使用する戦略。有効な値は
update
、manual
、validate
です。updateは、自動的にデータベース・スキーマを移行します。manualは、データベースに対して手動実行可能な、必要な変更のSQLコマンドが書かれたファイルをエクスポートします。validateは、データベースが最新であるかどうかを単にチェックするものです。 - migrationExport
-
手動によるデータベース初期化または移行用ファイルを書き込む場所のパス。
- showSql
-
Hibernateがコンソール内にすべてのSQLコマンドを表示するかどうかを指定します(デフォルトはfalse)。これは非常に冗長な出力となります。」
- formatSql
-
HibernateがSQLコマンドをフォーマットするかどうかを指定します(デフォルトはtrue)。
- globalStatsInterval
-
実行されたDBクエリーなどに関する、Hibernateのグローバル統計情報をログに出力します。統計情報は、秒単位で指定された間隔でサーバーログに常にレポートされ、各レポート後にクリアされます。
- schema
-
使用するデータベース・スキーマを指定します。
これらの設定スイッチなどについては、WildFly 13 Development Guideで説明します。 |
6.6. データベースのユニコードに関する考慮事項
Keycloakのデータベース・スキーマは、以下の特別なフィールドにユニコード文字列を記述します。
-
Realms:表示名、HTML表示名
-
Federation Providers:表示名
-
Users:ユーザー名、氏名、属性名、値
-
Groups:名前、属性名、値
-
Roles:名前
-
オブジェクトの説明
上記以外の場合は、8ビットのデータベース・エンコーディングに含まれる文字に制限されます。ただし、データベース・システムによっては、ユニコード文字のUTF-8エンコーディングを有効にし、すべてのテキストフィールド内で完全なユニコード文字セットを使用することができます。これは8ビットエンコーディングの場合よりも文字列の最大長を短くすることによって相殺されます。
データベースによっては、ユニコード文字を処理できるようにデータベースとJDBCドライバーの両方、またはいずれかに特別な設定をする必要があります。以下のデータベースの設定を確認してください。データベースがここにリストされている場合、データベースとJDBCドライバーの両方のレベルでUTF-8エンコーディングが適切に処理されていれば、正常に動きます。この点には注意してください。
技術的には、すべてのフィールド内のユニコード・サポートの重要な基準は、データベースによって VARCHAR
フィールドと CHAR
フィールドにユニコード文字セットが設定できるかどうかになります。設定できる場合は、通常はフィールド長を犠牲にすることで、ユニコードは妥当となります。 NVARCHAR
フィールドと NCHAR
フィールド内のユニコードしかサポートされていない場合は、Keycloakスキーマは VARCHAR
フィールドと CHAR
フィールドを広範囲にわたって使用するため、すべてのテキストフィールドのユニコード・サポートはほとんどありません。
6.6.1. Oracle Database
VARCHAR
フィールドと CHAR
フィールド内でユニコード・サポートを使用してデータベースを作成した場合は、ユニコード文字は適切に処理されます(例: AL32UTF8
文字セットがデータベース文字セットとして使用された場合)。JDBCドライバーに特別な設定は必要ありません。
データベース文字セットがユニコードではない場合、ユニコード文字を特別なフィールド内で使用するために、JDBCドライバーを設定して接続プロパティー oracle.jdbc.defaultNChar
を true
に設定する必要があります。厳密には必須ではないのですが、 oracle.jdbc.convertNcharLiterals
接続プロパティーも true
にしておいた方が賢明です。これらのプロパティーは、システム・プロパティーまたは接続プロパティーとして設定することができます。しかし oracle.jdbc.defaultNChar
の設定はパフォーマンスに悪影響を与える可能性がありますので、この点は注意してください。詳しくは、Oracle JDBCドライバーの設定ドキュメントを参照してください。
6.6.2. Microsoft SQL Server Database
ユニコード文字は、特別なフィールドに対してのみ適切に処理されます。JDBCドライバーやデータベースの特別な設定は必要ありません。
6.6.3. MySQL Database
CREATE DATABASE
コマンドで、 VARCHAR
と CHAR
のフィールド内のユニコード・サポートを使用してデータベースが作成される場合は、ユニコード文字は適切に処理されます(例:MySQL5.5でデフォルトのデータベース文字セットとして utf8
文字セットを使用する場合。 utf8
文字セット[1]に求められるさまざまなストレージ要件により、 utf8mb4
文字セットは動作しませんので注意してください)。この場合、バイト数ではなく文字数に合わせて列が作成されるため、通常のフィールドには長さ制限は適用されないことに注意が必要です。データベースのデフォルト文字セットでユニコードの格納が許可されていない場合、特別なフィールドでのみユニコード値の格納が許可されることになります。
JDBCドライバー設定については、JDBC接続設定に接続プロパティー characterEncoding=UTF-8
を追加する必要があります。
7. ネットワーク設定
Keycloakは、いくつかのネットワーク制限付きですぐに実行することができます。まず1つ目の制限は、すべてのネットワーク・エンドポイントが localhost
にバインドされることにより、Keycloakサーバーは1台のローカルマシンでしか使用できないことです。2つ目の制限は、HTTPベースの接続には、80、443のようなデフォルトのポートが使用できないことです。HTTPS/SSLはそのまま使用できるように設定されておらず、その設定がされていないと、Keycloakはセキュリティー上非常に脆弱です。最後の制限は、Keycloakが外部サーバーに対するセキュアなSSLとHTTPS接続を必要とすることです。そのため、トラストストアを設定してエンドポイントを正しく検証する必要があります。この章では、これらの設定についてすべて説明します。
7.1. バインドアドレス
デフォルトでは、Keycloakはローカルホストのループバック・アドレス 127.0.0.1
にバインドされています。しかし、利用中のネットワーク上で認証サーバーを使用するには、これはあまり便利なデフォルトではありません。通常は、リバース・プロキシーまたはロードバランサーをパブリック・ネットワークにデプロイし、トラフィックをプライベート・ネットワーク上の個々のKeycloakサーバー・インスタンスにルーティングすることをお勧めします。どちらの場合でも、ネットワーク・インターフェイスを設定して localhost
以外のものにバインドする必要があります。
バインドアドレスの設定は簡単です。動作モードの選択の章で説明した standalone.sh または domain.sh 起動スクリプトを使用して、コマンドライン上で設定することができます。
$ standalone.sh -b 192.168.0.5
-b
スイッチにより、パブリック・インターフェイス用のIPバインドアドレスは設定されます。
また、コマンドラインでバインドアドレスを設定したくない場合はその代わりの方法として、プロファイル設定を編集することもできます。動作モードに応じて standalone.xml または domain.xml になりますが、そのいずれかのプロファイル設定ファイルを開き、XMLブロックの interfaces
を検索します。
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
public
インターフェイスは、公開用ソケットを作成するサブシステムに対応しています。これらのサブシステムのサンプルとしては、Keycloakの認証エンドポイントを提供するwebレイヤーというものがあります。一方、 management
インターフェイスは、WildFlyのmanagementレイヤーによって開かれたソケットに対応しています。具体的には、 jboss-cli.sh
コマンドライン・インターフェイスとWildFlyのwebコンソールを使用できるソケットになります。
public
インターフェイスを確認すると、特別な文字列 ${jboss.bind.address:127.0.0.1}
が表示されています。この文字列は、 127.0.0.1
という値を示していますが、コマンドラインでJavaシステム・プロパティーを設定して上書きすることができます。
$ domain.sh -Djboss.bind.address=192.168.0.5
-b
は、このコマンドの簡略表記です。したがって、このバインドアドレス値は、プロファイル設定で直接変更、または起動時にコマンドラインで変更することができます。
interface 定義を設定すると、さらに多くのオプションを使用できます。詳しくは、 WildFly 13 Documentation 内のthe network interfaceを参照してください。
|
7.2. ソケットポート・バインディング
各ソケット用に開けられたポートには、コマンドラインまたは設定内で上書きできるデフォルト値があらかじめ定義されています。この設定方法を学ぶために、スタンドアローン・モードで実行していると仮定し、 …/standalone/configuration/standalone.xml を開いてみましょう。そして socket-binding-group
を検索します。
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="localhost" port="25"/>
</outbound-socket-binding>
</socket-binding-group>
socket-bindings
によってソケット接続が定義され、サーバーで開かれます。これらのバインディングは、 interface
のバインドアドレスとポート番号を指定します。最も重要な項目は、以下のとおりです。
- http
-
KeycloakのHTTP接続に使用されるポートの定義
- https
-
KeycloakのHTTPS接続に使用されるポートの定義
- ajp
-
このソケット・バインディングは、AJPプロトコルに使用されるポートを定義します。このプロトコルは、Apache HTTPDサーバーをロードバランサーとして使用している場合、ApacheHTTPDサーバーによって
mod-cluster
と共に使用されます。 - management-http
-
WildFly CLIとwebコンソールで使用されるHTTP接続を定義します。
ドメインモードで実行する場合、 domain.xml ファイルに複数の socket-binding-groups
が定義されているサンプルと同様に、ソケット設定は少し難しくなります。 server-group
の定義までスクロールダウンすると、各 server-group
にどの socket-binding-group
が使用されているのか確認することができます。
<server-groups>
<server-group name="load-balancer-group" profile="load-balancer">
...
<socket-binding-group ref="load-balancer-sockets"/>
</server-group>
<server-group name="auth-server-group" profile="auth-server-clustered">
...
<socket-binding-group ref="ha-sockets"/>
</server-group>
</server-groups>
socket-binding-group を定義すると、さらに多くのオプションを使用できるようになります。詳しくは、 WildFly 13 Documentation 内のthe socket binding groupを参照してください。
|
7.3. HTTPS/SSLの設定
Keycloakは、デフォルトではSSL/HTTPSを処理するように設定されていません。Keycloakサーバー上、またはKeycloakサーバーのフロントにあるリバース・プロキシー上のいずれかでSSLを有効にすることを強くお勧めします。 |
このデフォルトの動作は、各KeycloakレルムのSSL/HTTPSモードによって定義されています。これについて詳しくはServer Administration Guideで説明しますが、これらのモードの関連事項と簡単な概要についてはここで示します。
- external requests
-
SSLが無効でも、
localhost
、127.0.0.1
、10.0.x.x
、192.168.x.x
、172.16.x.x
のようなプライベートIPアドレス以外であれば、Keycloakをそのまま実行することは可能です。サーバーにSSL/HTTPSが設定されていない場合、またはプライベートIPアドレス以外からHTTP経由でKeycloakにアクセスする場合はエラーになります。 - none
-
KeycloakはSSLを要求しません。この設定は、開発段階でいろいろと検証している時にのみ使用すべきです。
- all requests
-
KeycloakはすべてのIPアドレスに対してSSLを要求します。
各レルム用のSSLモードは、Keycloak管理コンソール内で設定できます。
7.3.1. Keycloakサーバー用SSL/HTTPSの有効化
HTTPSトラフィックを処理するためにリバース・プロキシーまたはロードバランサーを使用していない場合、Keycloakサーバー用にHTTPSを有効にする必要があります。これには下記が含まれます。
-
SSL/HTTPトラフィック用の秘密鍵と証明書を含むキーストアの取得または生成
-
このキーペアと証明書を使用するためのKeycloakサーバー設定
証明書とJavaキーストアの作成
HTTPS接続が許可されるには、Keycloakサーバーがデプロイされているwebコンテナー内でHTTPSを有効にする前に、自己署名証明書または第三者署名証明書を取得してJavaキーストアにインポートする必要があります。
自己署名証明書
開発段階で、Keycloakの配備をテストするための第三者署名証明書を用意していない場合、Java JDKに付属する keytool
ユーティリティーを使用して自己署名証明書を生成する必要があります。
$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950
Enter keystore password: secret
Re-enter new password: secret
What is your first and last name?
[Unknown]: localhost
What is the name of your organizational unit?
[Unknown]: Keycloak
What is the name of your organization?
[Unknown]: Red Hat
What is the name of your City or Locality?
[Unknown]: Westford
What is the name of your State or Province?
[Unknown]: MA
What is the two-letter country code for this unit?
[Unknown]: US
Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct?
[no]: yes
What is your first and last name ?
という質問にはサーバーをインストールしたマシンのDNS名を答えてください。 テスト目的なので、 localhost
を使用します。このコマンドを実行すると、 keytool
コマンドが実行されたのと同じディレクトリー内で keycloak.jks
ファイルが生成されます。
第三者署名証明書が必要だが用意していない場合、 cacert.org から無料で取得することができます。しかしこの方法で取得する前に、少し設定が必要になります。
まず、証明書署名要求を生成します。
$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq
yourdomain
はこの証明書が生成されるDNS名になります。Keytoolにより以下のように生成されます。
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y
ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY
Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1
29RvyeUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as
H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw
Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35
2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i
n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf
PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ
9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X
MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S
vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8=
-----END NEW CERTIFICATE REQUEST-----
この証明書署名要求を認証局に送信します。認証局は署名された証明書を発行し、送り返します。ただし、新しい証明書をインポートする前に、まず認証局のルート証明書を取得してインポートする必要があります。認証局からルート証明書(例:root.crt)をダウンロードし、以下のとおりインポートします。
$ keytool -import -keystore keycloak.jks -file root.crt -alias root
最後に、以下のように新しい認証局の生成した証明書をキーストアにインポートします。
$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer
キーストアを使用するためのKeycloak設定
適切な証明書を含むJavaキーストアができたため、それを使用するようにKeycloakのインストールを設定する必要があります。まず、キーストアを使用してHTTPSを有効にするために、 standalone.xml 、 standalone-ha.xml 、または host.xml の各ファイルを編集する必要があります。その後、キーストア・ファイルをデプロイメントの configuration/ ディレクトリに移動するか、または任意の場所に配置して絶対パスを指定します。絶対パスを使用している場合は、設定からオプションの relative-to
パラメータを削除してください(動作モードを参照)。
次のようにCLIを使用して、新しい security-realm
要素を追加します。
$ /core-service=management/security-realm=UndertowRealm:add()
$ /core-service=management/security-realm=UndertowRealm/server-identity=ssl:add(keystore-path=keycloak.jks, keystore-relative-to=jboss.server.config.dir, keystore-password=secret)
ドメインモードを使用している場合は、コマンドはすべてのホストで /host=<host_name>/
プレフィックスを使用して実行します(すべてのホストで security-realm
を作成するために)。次のように、各ホスト分繰り返します。
$ /host=<host_name>/core-service=management/security-realm=UndertowRealm/server-identity=ssl:add(keystore-path=keycloak.jks, keystore-relative-to=jboss.server.config.dir, keystore-password=secret)
スタンドアローンまたはホスト設定ファイルでは、 security-realms
要素は次のようになります。
<security-realm name="UndertowRealm">
<server-identities>
<ssl>
<keystore path="keycloak.jks" relative-to="jboss.server.config.dir" keystore-password="secret" />
</ssl>
</server-identities>
</security-realm>
次に、スタンドアローンまたは各ドメイン設定ファイルで、 security-realm
のインスタンスを検索します。作成したレルムを使用するように、次のように https-listener
を修正します。
$ /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=security-realm, value=UndertowRealm)
ドメインモードを使用している場合は、使用されているプロファイルをコマンドの先頭に /profile=<profile_name>/
のように付けます。
結果として得られる要素 server name="default-server"
は、これは subsystem xmlns="urn:jboss:domain:undertow:6.0"
の子要素であり、次のような内容を含みます。
<subsystem xmlns="urn:jboss:domain:undertow:6.0">
<buffer-cache name="default"/>
<server name="default-server">
<https-listener name="https" socket-binding="https" security-realm="UndertowRealm"/>
...
</subsystem>
7.4. 外部へのHTTPリクエスト
Keycloakサーバーは、ブラウザーを介さないHTTPリクエストを、セキュリティー保護されたアプリケーションやサービスに送信する必要が多々あります。Keycloakサーバーは、HTTPクライアント接続プールを維持することによって、これらの外部接続を管理します。 standalone.xml
、 standalone-ha.xml
または domain.xml
内で少し設定する必要があります。このファイルの場所は、動作モードによって異なります。
<spi name="connectionsHttpClient">
<provider name="default" enabled="true">
<properties>
<property name="connection-pool-size" value="256"/>
</properties>
</provider>
</spi>
設定可能なオプションは、以下のとおりです。
- establish-connection-timeout-millis
-
ソケット接続を確立する際のタイムアウトです。
- socket-timeout-millis
-
外部へのリクエストがこの時間の間にデータを受信しない場合、接続をタイムアウトします。
- connection-pool-size
-
プールされる接続数です(デフォルトでは128)。
- max-pooled-per-route
-
ホストごとにプールされる接続数です(デフォルトでは64)。
- connection-ttl-millis
-
ミリ秒単位での最大接続時間です。デフォルトでは設定されていません。
- max-connection-idle-time-millis
-
接続プール内でアイドル状態を維持する最大時間です(デフォルトでは900秒)。Apache HTTPクライアントのバックグラウンドクリーナースレッドを開始します。-
1
にセットすると、このチェックとバックグラウンドスレッドは無効になります。 - disable-cookies
-
デフォルトでは
true
です。trueを設定した場合、Cookieキャッシュは無効になります。 - client-keystore
-
これはJavaキーストア・ファイルへのファイルパスです。このキーストアには、双方向SSL用のクライアント証明書を含めます。
- client-keystore-password
-
クライアント・キーストア用のパスワードです。
client-keystore
が設定されている場合、これは REQUIRED です。 - client-key-password
-
Password for the client’s key. This is REQUIRED if
client-keystore
is set. - proxy-mappings
-
送信するHTTPリクエストのプロキシー設定を示します。詳細については、送信HTTPリクエストのプロキシー・マッピングのセクションを参照してください。
7.4.1. 送信HTTPリクエストのプロキシー・マッピング
Keycloakによって送信された送信HTTPリクエストは、プロキシー・マッピングのカンマで区切られたリストに基づいて、オプションでプロキシー・サーバーを使用できます。プロキシー・マッピングは、正規表現ベースのホスト名パターンと hostnamePattern;proxyUri
形式のproxy-uriの組み合わせを示します。例:
.*\.(google|googleapis)\.com;http://www-proxy.acme.com:8080
送信するHTTPリクエストのプロキシーを判別するために、ターゲットホスト名が、設定されたホスト名パターンと照合されます。最初に一致するパターンで、使用するproxy-uriが決定します。指定されたホスト名と一致する設定済みのパターンが無い場合、プロキシーは使用されません。
proxy-uriに対する特別な値 NO_PROXY
は、関連するホスト名パターンと一致するホストに対して、プロキシーを使用しないことを示すために使用できます。プロキシー・マッピングの終わりにcatch-allパターンを指定して、送信するすべてのリクエストのデフォルト・プロキシーを定義することが可能です。
次の例は、プロキシー・マッピングの設定を示しています。
# All requests to Google APIs should use http://www-proxy.acme.com:8080 as proxy
.*\.(google|googleapis)\.com;http://www-proxy.acme.com:8080
# All requests to internal systems should use no proxy
.*\.acme\.com;NO_PROXY
# All other requests should use http://fallback:8080 as proxy
.*;http://fallback:8080
これは、以下の jboss-cli
コマンドで設定できます。以下に示す正規表現パターンを適切にエスケープする必要があることに注意してください。
echo SETUP: Configure proxy routes for HttpClient SPI
# In case there is no connectionsHttpClient definition yet
/subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:add(enabled=true)
# Configure the proxy-mappings
/subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:write-attribute(name=properties.proxy-mappings,value=[".*\\.(google|googleapis)\\.com;http://www-proxy.acme.com:8080",".*\\.acme\\.com;NO_PROXY",".*;http://fallback:8080"])
jboss-cli
コマンドの結果、以下のサブシステム設定になります。 "
で "
文字をエンコードする必要があることに注意してください。
<spi name="connectionsHttpClient">
<provider name="default" enabled="true">
<properties>
<property
name="proxy-mappings"
value="[".*\\.(google|googleapis)\\.com;http://www-proxy.acme.com:8080",".*\\.acme\\.com;NO_PROXY",".*;http://fallback:8080"]"/>
</properties>
</provider>
</spi>
7.4.2. 外部へのHTTPSリクエストのトラストストア
KeycloakがリモートのHTTPSエンドポイントを呼び出す場合、信頼できるサーバーへの接続かどうかを確認するために、リモートサーバーの証明書を検証する必要があります。これは、中間者攻撃を防ぐために必要です。リモートサーバーや署名した認証局の証明書は、トラストストアに保存されている必要があります。このトラストストアは、Keycloakサーバーによって管理されます。
トラストストアは、アイデンティティー・ブローカーやLDAPアイデンティティー・プロバイダーに安全に接続する場合、電子メールを送信する場合、およびクライアント・アプリケーションとのバックチャネル通信をする場合に使用されます。
デフォルトでは、トラストストア・プロバイダーは設定されておらず、https接続は Javaの JSSE Reference Guideで説明されている標準のJavaトラストストア設定にフォールバックします。信頼が確立されていない場合、これらの送信するHTTPSリクエストはエラーになります。 |
keytool を使用し、新しいトラストストア・ファイルを作成、または信頼できるホスト証明書を既存のトラストストア・ファイルに追加することができます。
$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer
トラストストアは、配布物内の standalone.xml
、 standalone-ha.xml
または domain.xml
で設定されます。このファイルの場所は、動作モードによって異なります。以下のテンプレートを使用して、トラストストア設定を追加することができます。
<spi name="truststore">
<provider name="file" enabled="true">
<properties>
<property name="file" value="path to your .jks file containing public certificates"/>
<property name="password" value="password"/>
<property name="hostname-verification-policy" value="WILDCARD"/>
<property name="disabled" value="false"/>
</properties>
</provider>
</spi>
設定可能なオプションは以下のとおりです。
- file
-
Javaキーストア・ファイルへのパスです。HTTPSリクエストでは、通信を行うサーバーのホストを検証する必要があります。これはトラストストアの役割です。キーストアには、1つ以上の信頼できるホスト証明書または認証局が含まれています。このトラストストア・ファイルには、セキュリティー保護されたホストのパブリック証明書のみを含めるべきです。
disabled
がtrueでない場合、これは REQUIRED です。 - password
-
トラストストア用のパスワードです。
disabled
がtrueでない場合、これは REQUIRED です。 - hostname-verification-policy
-
デフォルトでは
WILDCARD
です。HTTPSリクエストを行うために、サーバー証明書のホスト名を検証します。ANY
はホスト名が検証されないことを意味します。WILDCARD
によって、サブドメイン名にワイルドカードが使用できるようになります。サンプルとしては、 *.foo.comです。STRICT
の場合、CNはホスト名と正確に一致する必要があります。 - disabled
-
true(デフォルト値)の場合、トラストストアの設定は無視され、証明書チェックは前述のJSSE設定にフォールバックします。falseに設定されている場合は、トラストストア用に
file
とpassword
を設定する必要があります。
8. クラスタリング
このセクションでは、Keycloakをクラスター内で実行するように設定する方法について説明します。クラスターを設定する場合、多くの設定が必要になります。具体的には以下のとおりです。
-
ロードバランサーの設定
-
IPマルチキャストをサポートするプライベート・ネットワークの提供
動作モードの選択と共有データベースの設定については、このガイドの前半で説明しました。この章では、ロードバランサーの設定とプライベート・ネットワークの提供について説明します。また、クラスター内でホストを起動する場合の注意点についても説明します。
IPマルチキャストなしでもKeycloakをクラスター構成にすることは可能ですが、このトピックについてはこのガイドの範囲を超えています。詳しくは、 WildFly 13 Documentation のJGroupsを参照してください。 |
8.1. 推奨ネットワーク・アーキテクチャー
Keycloakをデプロイするための推奨ネットワーク・アーキテクチャーは、パブリックIPアドレスを持つHTTP/HTTPSロードバランサーを配置し、プライベート・ネットワーク上のKeycloakサーバーへのリクエストをルーティングさせます。これにより、クラスタリング接続はすべて分離され、サーバーを保護する優れた手段が提供されます。
デフォルトでは、許可されていないノードがクラスターに加わり、マルチキャスト・メッセージをブロードキャストするのを防ぐものは何もありません。このため、クラスター・ノードはプライベート・ネットワーク内に置かれ、ファイアウォールによって外部の攻撃から保護される必要があります。 |
8.2. クラスタリングのサンプル
Keycloakには、ドメインモードでそのまま利用できるクラスタリングのデモが付属しています。詳しくはクラスター構成ドメインのサンプルの章を参照してください。
8.3. Setting Up a Load Balancer or Proxy
このセクションでは、クラスター構成のKeycloakの前にリバース・プロキシーまたはロードバランサーを配置するにあたって、設定が必要な項目について説明します。また、組み込みのロードバランサーの設定についても説明します。これはクラスター構成ドメインのサンプルでも確認できます。
8.3.1. クライアントIPアドレスの特定
Keycloakのいくつかの機能は、認証サーバーに接続するHTTPクライアントのリモート・アドレスがクライアント・マシンの実際のIPアドレスであることを前提としています。例は、以下のとおりです。
-
イベントログ - 間違ったソースIPアドレスでログインエラーが記録されます
-
SSLの要求 - SSLの要求がexternal(デフォルト)に設定されている場合、すべての外部リクエストに対してSSLを要求します
-
認証フロー - IPアドレスを使用して、たとえば外部リクエストに対してのみOTPを表示するようなカスタム認証フロー
-
動的クライアント登録
Keycloak認証サーバーの前にリバース・プロキシーまたはロードバランサーが置いてある場合、問題になる可能性があります。通常の設定では、パブリック・ネットワーク上にフロントエンドのプロキシを置いています。このプロキシはプライベート・ネットワーク内のバックエンドのKeycloakサーバー・インスタンスに負荷を分散してリクエストを転送するものです。実際のクライアントIPアドレスが転送され、Keycloakサーバー・インスタンスによって処理されるように、追加設定する必要があります。具体的には以下のとおりです。
-
X-Forwarded-For
、X-Forwarded-Proto
HTTPヘッダーを適切にセットするように、リバース・プロキシーまたはロードバランサーを設定します。 -
オリジナルの 'Host' HTTPヘッダーを保持するように、リバース・プロキシーまたはロードバランサーを設定します。
-
X-Forwarded-For
ヘッダーからクライアントのIPアドレスを読み取るように、認証サーバーを設定します。
X-Forwarded-For
、 X-Forwarded-Proto
HTTPヘッダーを生成するためにプロキシーを設定し、オリジナルの Host
HTTPヘッダーを保持する方法については、このガイドの説明範囲を超えています。 X-Forwared-For
ヘッダーがプロキシーによって設定されているか、特に注意して確認してください。プロキシーが正しく設定されていない場合、不正な クライアントがこのヘッダーを自身で設定して、クライアントが実際とは異なるIPアドレスから接続しているとKeycloakに認識させることができてしまいます。IPアドレスのブラックリストまたはホワイトリストを作成している場合、この設定は非常に重要です。
プロキシーの他にも、いくつかKeycloak側で設定する必要があります。プロキシーがHTTPプロトコル経由でリクエストを転送している場合、クライアントのIPアドレスをネットワーク・パケットからではなく X-Forwarded-For
ヘッダーから取得するように、Keycloakを設定する必要があります。これを行うには、プロファイル設定ファイル(動作モードに応じて standalone.xml 、 standalone-ha.xml または domain.xml )を開き、 urn:jboss:domain:undertow:6.0
XMLブロックを検索します。
X-Forwarded-For
HTTP設定<subsystem xmlns="urn:jboss:domain:undertow:6.0">
<buffer-cache name="default"/>
<server name="default-server">
<ajp-listener name="ajp" socket-binding="ajp"/>
<http-listener name="default" socket-binding="http" redirect-socket="https"
proxy-address-forwarding="true"/>
...
</server>
...
</subsystem>
http-listener
要素に proxy-address-forwarding
属性を追加します。値を true
に設定します。
プロキシーがリクエストを転送するためにHTTPの代わりにAJPプロトコルを使用している場合(サンプルとしては、Apache HTTPD + mod-clusterなど)、少し異なる設定が必要になります。 http-listener
を変更する代わりに、AJPパケットからこの情報を取得するフィルターを追加する必要があります。
X-Forwarded-For
AJP設定<subsystem xmlns="urn:jboss:domain:undertow:6.0">
<buffer-cache name="default"/>
<server name="default-server">
<ajp-listener name="ajp" socket-binding="ajp"/>
<http-listener name="default" socket-binding="http" redirect-socket="https"/>
<host name="default-host" alias="localhost">
...
<filter-ref name="proxy-peer"/>
</host>
</server>
...
<filters>
...
<filter name="proxy-peer"
class-name="io.undertow.server.handlers.ProxyPeerAddressHandler"
module="io.undertow.core" />
</filters>
</subsystem>
8.3.2. リバース・プロキシーでのHTTPS/SSLの有効化
リバース・プロキシーがSSL用にポート8443を使用しない場合、HTTPSトラフィックのどのポートをリダイレクトするか設定する必要があります。
<subsystem xmlns="urn:jboss:domain:undertow:6.0">
...
<http-listener name="default" socket-binding="http"
proxy-address-forwarding="true" redirect-socket="proxy-https"/>
...
</subsystem>
http-listener
要素に redirect-socket
属性を追加します。値には proxy-https
を設定しますが、これは定義が必要なソケット・バインディングを指しています。
次に、新しい socket-binding
要素を socket-binding-group
要素に追加します。以下のようになります。
<socket-binding-group name="standard-sockets" default-interface="public"
port-offset="${jboss.socket.binding.port-offset:0}">
...
<socket-binding name="proxy-https" port="443"/>
...
</socket-binding-group>
8.3.3. 設定の確認
リバース・プロキシー経由で /auth/realms/master/.well-known/openid-configuration
のパスを開き、リバース・プロキシーまたはロードバランサーの設定を確認することができます。たとえば、リバース・プロキシーのアドレスが https://acme.com/
の場合、 https://acme.com/auth/realms/master/.well-known/openid-configuration
のURLを開きます。そうすると、Keycloak用のエンドポイントの数を示すJSONドキュメントが表示されます。エンドポイントが、リバース・プロキシーまたはロードバランサーのアドレス(スキーム、ドメイン、ポート)で始まることを確認します。このようにして、Keycloakが正しいエンドポイントを使用しているか確認します。
また、KeycloakがリクエストのソースIPアドレスを正しく認識しているか確認する必要があります。無効なユーザー名とパスワードの両方またはいずれかで管理コンソールにログインし、確認してください。これを行うと、サーバーログに以下のような警告が表示されます。
08:14:21,287 WARN XNIO-1 task-45 [org.keycloak.events] type=LOGIN_ERROR, realmId=master, clientId=security-admin-console, userId=8f20d7ba-4974-4811-a695-242c8fbd1bf8, ipAddress=X.X.X.X, error=invalid_user_credentials, auth_method=openid-connect, auth_type=code, redirect_uri=http://localhost:8080/auth/admin/master/console/?redirect_fragment=%2Frealms%2Fmaster%2Fevents-settings, code_id=a3d48b67-a439-4546-b992-e93311d6493e, username=admin
ipAddress
の値はログインしようとしているマシンのIPアドレスで、リバース・プロキシーまたはロードバランサーのIPアドレスではないということを確認してください。
8.3.4. 組み込みロードバランサーの使用
このセクションでは、クラスター構成ドメインのサンプルで説明している組み込みのロードバランサーの設定方法について説明します。
クラスター構成ドメインのサンプルは1台のマシンで実行するためにのみ作られています。他のホストでスレーブを起動するには、次の操作が必要です。
-
新しいホスト・スレーブを指し示すように、 domain.xml ファイルを編集します。
-
サーバー配布物をコピーします。 domain.xml 、 host.xml または host-master.xml は必要ありません。 standalone/ ディレクトリーも必要ありません。
-
使用しているバインドアドレスを変更、またはコマンドラインでそのアドレスを上書きするように、 host-slave.xml ファイルを編集します。
ロードバランサーでの新しいホスト登録
まず、 domain.xml 内のロードバランサーを設定して、新しいホスト・スレーブを登録する方法について学んでいきましょう。このファイルを開き、 load-balancer
プロファイル内のundertow設定に移動します。 reverse-proxy
のXMLブロック内で、 remote-host3
と呼ばれる host
の新しい定義を追加します。
<subsystem xmlns="urn:jboss:domain:undertow:6.0">
...
<handlers>
<reverse-proxy name="lb-handler">
<host name="host1" outbound-socket-binding="remote-host1" scheme="ajp" path="/" instance-id="myroute1"/>
<host name="host2" outbound-socket-binding="remote-host2" scheme="ajp" path="/" instance-id="myroute2"/>
<host name="remote-host3" outbound-socket-binding="remote-host3" scheme="ajp" path="/" instance-id="myroute3"/>
</reverse-proxy>
</handlers>
...
</subsystem>
output-socket-binding
は domain.xml 内で後ほど設定する socket-binding
を指す論理名です。instance-id
属性は、負荷を分散する時にスティッキー・セッションを有効にできるようにこの値がCookieによって使用されるため、 新しいホスト固有のものでなければなりません。
次に、 load-balancer-sockets
と socket-binding-group
へとスクロールダウンし、 remote-host3
用の outbound-socket-binding
を追加します。この新しいバインディングは、新しいホストのホスト名とポートを指し示す必要があります。
<socket-binding-group name="load-balancer-sockets" default-interface="public">
...
<outbound-socket-binding name="remote-host1">
<remote-destination host="localhost" port="8159"/>
</outbound-socket-binding>
<outbound-socket-binding name="remote-host2">
<remote-destination host="localhost" port="8259"/>
</outbound-socket-binding>
<outbound-socket-binding name="remote-host3">
<remote-destination host="192.168.0.5" port="8259"/>
</outbound-socket-binding>
</socket-binding-group>
マスター・バインドアドレス
次に、マスターホスト用の public
と management
バインドアドレスを変更する必要があります。バインドアドレス内で説明した domain.xml ファイルを編集するか、以下のとおりコマンドライン上でこれらのバインドアドレスを指定します。
$ domain.sh --host-config=host-master.xml -Djboss.bind.address=192.168.0.2 -Djboss.bind.address.management=192.168.0.2
ホスト・スレーブ・バインドアドレス
次は、 public
、 management
、ドメイン・コントローラー・バインドアドレス( jboss.domain.master-address
)を変更する必要があります 。 host-slave.xml ファイルを編集するか、以下のとおりコマンドラインでこれらを指定します。
$ domain.sh --host-config=host-slave.xml
-Djboss.bind.address=192.168.0.5
-Djboss.bind.address.management=192.168.0.5
-Djboss.domain.master.address=192.168.0.2
jboss.bind.address
と jboss.bind.addres.management
の値はホストスレーブのIPアドレスに関係します。 jboss.domain.master.address
の値は、マスターホストの管理アドレスであるドメイン・コントローラーのIPアドレスとする必要があります。
8.3.5. その他のロードバランサー設定
その他のソフトウェア・ベースのロードバランサーの使用方法については、 WildFly 13 Documentation 内のthe load balancingのセクションを参照してください。
8.4. スティッキー・セッション
典型的なクラスター構成は、ロードバランサー(リバース・プロキシー)とプライベート・ネットワーク上の2つ以上のKeycloakサーバーで構成されています。パフォーマンスのために、ロードバランサーが特定のブラウザー・セッションに関するリクエストをすべて同じKeycloakバックエンド・ノードに転送することは有用かもしれません。
なぜなら、Keycloakが現在の認証セッションとユーザー・セッションに関するデータを保存するために、Infinispanの分散キャッシュを使用しているためです。Infinispanの分散キャッシュは、デフォルトで所有者は1つと設定されています。つまり、特定のセッションは1つのクラスター・ノードに保存され、他のノードがこのセッションにアクセスする場合は、リモートで検索する必要があります。
たとえば、ID 123
を持つ認証セッションが node1
上のInfinispanキャッシュに保存されていて、 node2
はこのセッションを検索する必要がある場合は、特定のセッション・エンティティーを返すためにネットワーク経由で node1
へリクエストを送信する必要があります。
特定のセッション・エンティティーが常にローカルで使用できる場合は、スティッキー・セッションに助けを借りることができます。パブリック・フロントエンド・ロードバランサーと2つのバックエンドKeycloakノードを持つクラスター環境内のワークフローは、以下のようになります。
-
ユーザーはKeycloakのログイン画面を表示するため初回リクエストを送信します。
-
このリクエストは、フロントエンド・ロードバランサーによって処理され、このフロントエンド・ロードバランサーがランダムにノード(たとえばnode1)に転送します。厳密には、ノードはランダムである必要はなく、他のいくつかの基準(クライアントIPアドレスなど)によって選択することができます。それらはすべて、ロードバランサー(リバース・プロキシー)の実装と設定に依存します。
-
Keycloakは認証セッションを任意のID(たとえば123)で作成し、Infinispanキャッシュに保存します。
-
Infinispanの分散キャッシュは、セッションIDのハッシュに基づいてセッションの主な所有者を割り当てます。これに関する詳細は、Infinispan documentationを参照してください。Infinispanがこのセッションの所有者として
node2
を割り当てたとしましょう。 -
Keycloakは
<session-id>.<owner-node-id>
のような形式のCookieAUTH_SESSION_ID
を作成します.サンプルとしては、123.node2
となります。 -
レスポンスは、Keycloakのログイン画面とブラウザーの
AUTH_SESSION_ID
Cookieでユーザーに返されます。
以上の点から、ID 123
を持つ認証セッションの所有者はこのノードであり、それゆえにInfinispanはローカルでこのセッションを検索できるため、ロードバランサーが node2
に対して以降のリクエストすべてを転送するなら有益なのです。認証セッションは、認証されるとユーザー・セッションに変換され、同じID 123
を持っているため node2
に保存されます。
スティッキー・セッションはクラスターの設定のために必須ではありませんが、上記の理由からパフォーマンスをあげるために有効です。 AUTH_SESSION_ID
Cookieで固定するようロードバランサーを設定する必要があります。どのように行うかはロードバランサーによります。
Keycloak側では、起動時にシステム・プロパティー jboss.node.name
を使用し、経路名に対応する値を使用することをお勧めします。たとえば、 -Djboss.node.name=node1
は経路を識別するために node1
を使います。この経路はInfinispanのキャッシュで使用され、ノードが特定のキーの所有者である場合は、AUTH_SESSION_ID
Cookieに関連付けられます。このシステム・プロパティーを使用した起動コマンドの例を以下に示します。
cd $RHSSO_NODE1
./standalone.sh -c standalone-ha.xml -Djboss.socket.binding.port-offset=100 -Djboss.node.name=node1
通常、プロダクション環境では経路名はバックエンド・ホストと同じ名前を使うべきですが、必要ではありません。たとえば、プライベート・ネットワーク内のKeycloakサーバーのホスト名を隠す場合などに、別の経路名を使用できます。
8.4.1. 経路の追加を無効にする
いくつかのロードバランサーは、バックエンドのKeycloakノードに頼るのではなく、経路情報を自身で追加するように設定できます。ただし、前述のとおり、Keycloakによる経路の追加が推奨されます。これは、Keycloakが特定のセッションの所有者であり、必ずしもローカルノードではないノードにルーティングできるエンティティーを認識しているため、このようにパフォーマンスが向上するためです。
必要に応じて、Keycloakサブシステム設定の RHSSO_HOME/standalone/configuration/standalone-ha.xml
ファイルに以下を追加することにより、AUTH_SESSION_ID
Cookieへの経路情報の追加を無効にすることができます。
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
...
<spi name="stickySessionEncoder">
<provider name="infinispan" enabled="true">
<properties>
<property name="shouldAttachRoute" value="false"/>
</properties>
</provider>
</spi>
</subsystem>
8.5. マルチキャスト・ネットワークの設定
ほとんど設定せずにクラスタリングを利用するには、IPマルチキャストが必要となります。マルチキャストとはネットワーク・ブロードキャスト・プロトコルのことです。このプロトコルは、起動時にクラスターを検出して参加させるために使用されます。また、Keycloakが使用する分散キャッシュのレプリケーションおよび無効化のためのメッセージをブロードキャストするためにも使用されます。
Keycloakのクラスタリング・サブシステムは、JGroupsスタック上で実行されます。クラスタリングのためのバインドアドレスは、デフォルトのIPアドレスとして127.0.0.1で、プライベート・ネットワーク・インターフェイスにバインドされています。バインドアドレスの章で説明した standalone-ha.xml または domain.xml セクションを編集する必要があります。
<interfaces>
...
<interface name="private">
<inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
...
<socket-binding name="jgroups-mping" interface="private" port="0" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
<socket-binding name="jgroups-tcp" interface="private" port="7600"/>
<socket-binding name="jgroups-tcp-fd" interface="private" port="57600"/>
<socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
<socket-binding name="jgroups-udp-fd" interface="private" port="54200"/>
<socket-binding name="modcluster" port="0" multicast-address="224.0.1.105" multicast-port="23364"/>
...
</socket-binding-group>
設定したい項目は jboss.bind.address.private
、 jboss.default.multicast.address
そしてクラスタリング・スタック上のサービスのポートになるでしょう。
IPマルチキャストなしでKeycloakをクラスタリングすることは可能ですが、このトピックはこのガイドの説明範囲を超えています。詳しくは、 WildFly 13 Documentation 内のJGroupsを参照してください。 |
8.6. クラスター通信のセキュリティー保護
クラスター・ノードがプライベート・ネットワークで隔離されている場合は、クラスターに参加したり、クラスター内の通信を表示したりするために、プライベート・ネットワークへのアクセスが必要です。また、クラスター通信の認証と暗号化を有効にすることもできます。プライベート・ネットワークが安全である限り、認証と暗号化を有効にする必要はありません。どちらの場合も、Keycloakはクラスター上で機密情報を送信しません。
クラスタリング通信の認証と暗号化を有効にする場合は、 JBoss EAP Configuration Guide のSecuring a Clusterを参照してください。
8.7. シリアライズされたクラスターの起動
Keycloakクラスター・ノードは並行して起動することができます。Keycloakサーバー・インスタンスが起動すると、データベースの移行、インポート、初回の初期化を行います。DBロックは、クラスター・ノードが同時に起動した場合、起動アクションが競合するのを防ぐために使用されます。
デフォルトでは、このロックの最大タイムアウトは900秒です。ノードがこのタイムアウト時間を超えてロック状態のままだった場合、起動は失敗します。通常は、デフォルト値を増減する必要はありません。しかし、配布物内の standalone.xml
、 standalone-ha.xml
または domain.xml
ファイルで、念のためこの増減を設定することができます。このファイルの場所は、動作モードに依存します。
<spi name="dblock">
<provider name="jpa" enabled="true">
<properties>
<property name="lockWaitTimeout" value="900"/>
</properties>
</provider>
</spi>
8.8. クラスターの起動
クラスター内でのKeycloakの起動は動作モードによって異なります。
$ bin/standalone.sh --server-config=standalone-ha.xml
$ bin/domain.sh --host-config=host-master.xml
$ bin/domain.sh --host-config=host-slave.xml
追加のパラメーターまたはシステム・プロパティーを使用する必要があります。たとえば、バインディング・ホストの場合は -b
パラメーターで、ルートの名前を指定する場合は jboss.node.name
システム・プロパティーです(スティッキー・セッションのセクションで説明しています)。
8.9. トラブルシューティング
-
クラスターを実行すると、両方のクラスターノードのログに以下のようなメッセージが表示されます。
INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (Incoming-10,shared=udp) ISPN000094: Received new cluster view: [node1/keycloak|1] (2) [node1/keycloak, node2/keycloak]
ノードが1つだけ表示されている場合、クラスターホストが同じクラスターに参加していない可能性があります。
通常、プライベート・ネットワーク上にクラスターノードを置き、ファイアウォールは置かずに通信するのがベスト・プラクティスです。その代わり、ネットワークへのパブリック・アクセス・ポイントでは、ファイアウォールを有効にすることができます。何らかの理由によりクラスターノードでファイアウォールを有効にする場合、ポートをいくつか開く必要があります。デフォルト値は、マルチキャスト・アドレス230.0.0.4のUDPポート55200とマルチキャスト・ポート45688です。JGroupsスタックの診断機能などの追加機能を有効にするには、ポートをさらに開く必要がありますので、その点は注意してください。Keycloakは、InfinispanまたはJGroupsにクラスタリング作業のほとんどを委譲します。詳しくは、 WildFly 13 Documentation のJGroupsを参照してください。
-
フェイルオーバーのサポート(高可用性)、エビクション、有効期限およびキャッシュ・チューニングに関心がある場合は、サーバー・キャッシュ設定を参照してください。
9. サーバー・キャッシュ設定
Keycloakには、2タイプのキャッシュがあります。1つ目は、データベースの前に置かれていて、DBの負荷を減らし、データをメモリーに保持することで全体の応答時間を短縮します。レルム、クライアント、ロール、およびユーザー・メタデータは、この1つ目のタイプのキャッシュに保持されます。このキャッシュはローカル・キャッシュです。クラスターにより多くのKeycloakサーバーがある場合でも、ローカル・キャッシュはレプリケーションを使用しません。その代わり、ローカル・キャッシュはローカルにのみコピーを保持し、エントリーが更新された場合は無効化メッセージが残りのクラスターに送られてエントリーは追い出されます。別途レプリケーションされたキャッシュ work
がありますが、このタスクは、何のエントリーがローカル・キャッシュから取り除かれるかについて、クラスター全体に無効化メッセージを送信するタスクになります。これによって、ネットワーク・トラフィックがかなり減り、効率化され、機密性の高いメタデータ通信の送信が回避されます。
2つ目のキャッシュは、ユーザー・セッション、オフライン・トークン、ログイン・エラーの履歴保持の管理を担当し、サーバーがパスワード・フィッシングやその他の攻撃を検出できるようにします。これらのキャッシュ内のデータは一時的で、メモリーにのみ保持されるものですが、クラスター全体にレプリケーションされる可能性があります。
この章では、クラスター構成と非クラスター構成の両方のためのキャッシュ用設定オプションについて説明します。
これらのキャッシュのより高度な設定については、 WildFly 13 Documentation のInfinispanのセクションを参照してください。 |
9.1. 退避と有効期限
Keycloakには、さまざまなキャッシュの設定があります。まず、レルムキャッシュというものがあり、セキュリティー保護されたアプリケーション、一般的なセキュリティー・データおよび設定オプションに関する情報を保持しています。また、ユーザー・メタデータを含むユーザー・キャッシュがあります。このキャッシュのデフォルト値は最大10000エントリーで、最近最も使われなかったものを退避する戦略が使用されます。また、これらのキャッシュはそれぞれ、クラスター構成内での退避を制御するオブジェクト・リビジョン・キャッシュにも関連付けられています。このキャッシュは暗黙的に作成され、値は設定値の2倍あります。認可データを保持する authorization
キャッシュについても同様です。 keys
キャッシュは外部キーに関するデータを保持し、専用のリビジョン・キャッシュを保持する必要はありません。それはむしろ明示的に expiration
が宣言されているので、キーは定期的に期限切れとなり、外部のクライアントやアイデンティティー・プロバイダーから定期的にダウンロードされます。
これらのキャッシュの退避ポリシーと最大エントリーは、動作モードに応じて standalone.xml 、 standalone-ha.xml または domain.xml 内で設定することができます。設定ファイルには、infinispanサブシステムの次のような部分があります。
<subsystem xmlns="urn:jboss:domain:infinispan:6.0">
<cache-container name="keycloak">
<local-cache name="realms">
<object-memory size="10000"/>
</local-cache>
<local-cache name="users">
<object-memory size="10000"/>
</local-cache>
...
<local-cache name="keys">
<object-memory size="1000"/>
<expiration max-idle="3600000"/>
</local-cache>
...
</cache-container>
許可されたエントリーの数を制限したり拡張したりするには、特定のキャッシュ設定の object
要素または expiration
要素を追加または編集するだけでできます。
さらに、 sessions
、 clientSessions
、 offlineSessions
、 offlineClientSessions
、 loginFailures
、 actionTokens
といったキャッシュもあります。これらのキャッシュはクラスター環境で分散され、デフォルトではサイズが制限されていません。制限がある場合、一部のセッションが失われる可能性があります。制限なしにこれらのキャッシュサイズが増大することを避けるために、期限切れのセッションはKeycloak自身によって内部的にクリアされます。多数のセッションが原因でメモリーの問題が発生した場合は、次の操作を試すことができます。
-
クラスターのサイズを大きくします(クラスター内のノードが多いほど、セッションはノード間でより均等に分散されます)
-
Keycloakサーバープロセスのメモリーを増やします
-
キャッシュが1つの場所に保存されるように、所有者の数を減らしてください。詳細はレプリケーションとフェイルオーバーを参照してください
-
分散キャッシュのl1-lifespanを無効にします。詳細については、Infinispanのマニュアルを参照してください。
-
セッション・タイムアウトを減らします。これはKeycloak管理コンソールの各レルムで個別に実行できます。しかし、これはエンドユーザーのユーザビリティーに影響する可能性があります。詳細については、 Timeouts を参照してください。
クラスターノード間でメッセージを送信するために主に使用される追加のレプリケーション・キャッシュ work
があります。デフォルトでは無制限です。ただし、このキャッシュ内のエントリーは非常に短期間であるため、このキャッシュがメモリーの問題を引き起こすことはありません。
9.2. レプリケーションとフェイルオーバー
sessions
、 authenticationSessions
、 offlineSessions
、 loginFailures
などのキャッシュがあります(詳細は退避と有効期限を参照)。クラスター化された設定を使用するときは分散キャッシュとして設定されます。エントリーはすべてのノードにひとつひとつレプリケーションされるわけではありませんが、1つ以上のノードがそのデータの所有者として選ばれます。ノードが特定のキャッシュ・エントリーの所有者ではない場合は、そのキャッシュ・エントリーを取得するためにクラスターに問い合わせをします。これがフェイルオーバーに対して何を意味するかというと、データを保持しているノードがすべてダウンした場合は、そのデータは永遠に失われてしまうということです。デフォルトでは、Keycloakが指定するデータの所有者は1つだけです。そのため、その1つのノードがダウンした場合は、そのデータは失われることになります。このことは通常、ユーザーはログアウトされ、再度ログインし直さなければならないということを意味します。
distributed-cache
の宣言で owners
属性を変更すると、データをレプリケートするノードの数を変更することができます。
<subsystem xmlns="urn:jboss:domain:infinispan:6.0">
<cache-container name="keycloak">
<distributed-cache name="sessions" owners="2"/>
...
ここで上記のとおりに変更すると、少なくとも2つのノードが1つの特定のユーザー・ログイン・セッションをレプリケーションします。
推奨される所有者数は、構成によって異なります。ノードがダウンした時にユーザーがログアウトされてもされなくても良い場合は、所有者は1つで十分であり、レプリケーションを避けることができます。 |
スティッキー・セッションでロードバランサーを使用するように環境を設定することは、一般的には賢明です。通常は、特定のリクエストが処理されるKeycloakサーバーが分散キャッシュデータの所有者であるため、ローカルでデータをルックアップできますので、パフォーマンスを向上させるために有益です。詳細はスティッキー・セッションを参照してください。 |
9.3. キャッシングの無効化
レルムまたはユーザー・キャッシュを無効にするには、配布物内の standalone.xml
、 standalone-ha.xml
または domain.xml
を編集する必要があります。このファイルの場所は、動作モードによって異なります。初期状態の設定は以下のようになっています。
<spi name="userCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="realmCache">
<provider name="default" enabled="true"/>
</spi>
キャッシュを無効にするには、無効にするキャッシュの enabled
属性をfalseに設定します。この変更を有効にするには、サーバーを再起動する必要があります。
10. Keycloakセキュリティー・プロキシー
Keycloakには、Keycloakアダプターをインストールすることができないwebアプリケーションとサービスのフロントに置くことができる、HTTP(S)プロキシがあります。ブラウザー・ログインとベアラー・トークン認証の両方、またはそのいずれかによって特定のURLが保護されるように、URLフィルターを設定することができます。また、アプリケーション内のURLパターンのためのロール制約を定義することもできます。
10.1. プロキシーのインストールと実行
KeycloakのダウンロードページからKeycloakプロキシー配布物をダウンロードし、解凍します。
$ unzip keycloak-proxy-dist.zip
これを実行するには、プロキシー設定ファイルが必要です(このファイルについては、直後に説明します)。
$ java -jar bin/launcher.jar [your-config.json]
プロキシー設定ファイルへのパスを指定しない場合、ランチャーは proxy.json
という名前のファイルを現在の作業ディレクトリー内で探します。
10.2. プロキシー設定
設定ファイルのサンプルは以下のとおりです。
{
"target-url": "http://localhost:8082",
"target-request-timeout": "60000",
"send-access-token": true,
"bind-address": "localhost",
"http-port": "8080",
"https-port": "8443",
"keystore": "classpath:ssl.jks",
"keystore-password": "password",
"key-password": "password",
"applications": [
{
"base-path": "/customer-portal",
"error-page": "/error.html",
"adapter-config": {
"realm": "demo",
"resource": "customer-portal",
"realm-public-key": "MIGfMA0GCSqGSIb",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external",
"principal-attribute": "name",
"credentials": {
"secret": "password"
}
}
,
"constraints": [
{
"pattern": "/users/*",
"roles-allowed": [
"user"
]
},
{
"pattern": "/admins/*",
"roles-allowed": [
"admin"
]
},
{
"pattern": "/users/permit",
"permit": true
},
{
"pattern": "/users/deny",
"deny": true
}
]
}
]
}
10.2.1. 基本設定
サーバー用の基本的な設定オプションは以下のとおりです。
- target-url
-
このサーバーがプロキシーするURL。 REQUIRED 。
- target-request-timeout
-
プロキシーされたリクエストのタイムアウト(ミリ秒)。 OPTIONAL 。 デフォルトは30000です。
- send-access-token
-
Booleanフラグ。trueの場合、プロキシーされるサーバーにKEYCLOAK_ACCESS_TOKENヘッダーを介してアクセストークンが送信されます。 OPTIONAL 。デフォルトはfalseです。
- bind-address
-
プロキシー・サーバーのソケットをバインドするDNS名またはIPアドレス。 OPTIONAL 。デフォルト値は localhost です。
- http-port
-
HTTPリクエストをリッスンするポート。この値を指定しないと、プロキシーは通常のHTTPリクエストをリッスンしません。 OPTIONAL 。
- https-port
-
HTTPSリクエストをリッスンするポート。この値を指定しないと、プロキシーは通常のHTTPSリクエストをリッスンしません。 OPTIONAL 。
- keystore
-
サーバーがHTTPSリクエストを処理できるようにする、秘密鍵と証明書を含むJavaキーストア・ファイルのパス。ファイルパスにすることは可能ですが、
classpath:
を付けると、クラスパス内でこのファイルを検索することができます。 OPTIONAL 。キーストアを定義していない状態で、HTTPSを有効にした場合、プロキシーは自己署名証明書を自動生成して使用します。 - buffer-size
-
HTTPサーバー・ソケットのバッファーサイズ。通常、デフォルトのままで十分です。 OPTIONAL 。
- buffers-per-region
-
リージョン毎のHTTPサーバー・ソケット・バッファー。通常、デフォルトのままで十分です。 OPTIONAL 。
- io-threads
-
IOを処理するスレッド数。通常、デフォルトのままで十分です。 OPTIONAL 。 デフォルトは使用できるプロセッサーの数 * 2です。
- worker-threads
-
要求を処理するスレッド数。通常、デフォルトのままで十分です。 OPTIONAL 。デフォルトは使用できるプロセッサーの数 * 16です。
10.3. アプリケーション設定
次に、 applications
配列の属性の下に、プロキシーしているホスト毎に1つ以上のアプリケーションを定義することができます。
- base-path
-
アプリケーションのベース・コンテキスト・ルート。これは '/' で始まる必要があります。 REQUIRED 。
- error-page
-
プロキシーにエラーがあると、ターゲット・アプリケーションのエラーページの相対URLが表示されます。 OPTIONAL 。これは、base-pathへの相対パスです。上記のサンプルでは、
/customer-portal/error.html
になります。 - adapter-config
-
REQUIRED 。他のKeycloakアダプターと同じ設定です。
- proxy-address-forwarding
-
他のプロキシー/ロードバランサーの背後に配置した場合は、X-Forwarded-For、X-Forwarded-Host、X-Forwarded-Protoを使用可能にします。
10.3.1. 制約の設定
次に、各アプリケーションの下に、 constraints
配列の属性内で1つ以上の制約を定義することができます。制約ではbase-pathを基準にしてURLパターンを定義します。特定のURLパターンに対しての拒否、許可または認証を要求することができます。また、そのパス用に許可される特定のロールも同様に指定することができます。具体的な制約は、一般的な制約より優先されます。
- pattern
-
アプリケーションのbase-pathを基準にして一致させるURLパターン。これは '/' で始まる必要があります。 REQUIRED 。ワイルドカードは1つだけ利用でき、パターンの末尾に入れなければなりません。
-
有効:
/foo/bar/*
と/foo/*.txt
-
無効:
/*/foo/*
.
-
- roles-allowed
-
このURLパターンへのアクセスが許可されたロールの文字列配列。 OPTIONAL 。
- methods
-
このパターンとHTTPリクエストに対して完全に一致する、HTTPメソッドの文字列配列。 OPTIONAL 。
- excluded-methods
-
このパターンと一致すると無視されるHTTPメソッドの文字列配列。 OPTIONAL 。
- deny
-
このURLパターンへのすべてのアクセスを拒否します。 OPTIONAL 。
- permit
-
認証またはロール・マッピングを要求せずに、すべてのアクセスを許可します。 OPTIONAL 。
- permit-and-inject
-
すべてのアクセスを許可しますが、ユーザーがすでに認証されている場合はヘッダーを挿入します。 OPTIONAL 。
- authenticate
-
このパターンに対して認証は要求しますが、ロールマッピングは要求しません。 OPTIONAL 。
10.3.2. ヘッダー名の設定
次に、アプリケーションのリストの下で、プロキシーによって挿入されたデフォルトのヘッダー・フィールド名を上書きすることができます(Keycloakアイデンティティー・ヘッダーを参照してください)。このマッピングはオプションです。
- keycloak-subject
-
例:MYAPP_USER_ID
- keycloak-username
-
例:MYAPP_USER_NAME
- keycloak-email
-
例:MYAPP_USER_EMAIL
- keycloak-name
-
例:MYAPP_USER_ID
- keycloak-access-token
-
例:MYAPP_ACCESS_TOKEN
10.4. Keycloakアイデンティティー・ヘッダー
プロキシー・サーバーにリクエストを転送する場合、Keycloakプロキシーは、認証のために受け取ったOIDCアイデンティティー・トークンから取得した値で、追加のヘッダーをいくつか設定します。
- KEYCLOAK_SUBJECT
-
ユーザーID。JWT
sub
に対応し、Keycloakがこのユーザーを保存するために使用するユーザーIDになります。 - KEYCLOAK_USERNAME
-
ユーザー名。 JWT
preferred_username
に対応します。 - KEYCLOAK_EMAIL
-
設定されている場合、ユーザーの電子メールアドレス。
- KEYCLOAK_NAME
-
設定されている場合、ユーザーのフルネーム。
- KEYCLOAK_ACCESS_TOKEN
-
アクセストークンを送信するようにプロキシーが設定されている場合、このヘッダーで送信します。このトークンを使用して、ベアラートークンのリクエストを行うことができます。ヘッダー・フィールド名は、以下のように設定ファイル内で
header-names
のマップを使用して設定することができます。{ "header-names" { "keycloak-subject": "MY_SUBJECT" } }