このガイドは、KeycloakのレガシーなWildFlyディストリビューション用です。 Quarkusによる新しいディストリビューションについては、新しい Server Guides をチェックしてください。 |
ガイドの概要
このガイドの目的は、Keycloakサーバーの初回起動の前に完了する必要があるいくつかの手順について説明することです。Keycloakをテストしたいだけの場合は、組み込みのローカル専用のデータベースでそのまま実行する方がよいでしょう。実際にプロダクション環境にデプロイしたい場合は、まずどのようにランタイム(スタンドアローン・モードまたはドメインモード)でサーバー設定を管理するか決定して、Keycloakの共有データベースを設定し、暗号化とHTTPSの設定を行い、最後にKeycloakをセットアップしてクラスター内で起動する必要があります。このガイドは、Keycloakサーバーをデプロイする前に、起動に先んじて定義と設定が必要なすべての手順を、ひとつひとつ説明していきます。
ただし、KeycloakはWildFly Application Serverに基づいていて、Keycloakの設定はWildFlyの設定項目と密接に関わっています。そのためこのガイドでは、詳細な説明について、このチュートリアルとは別の外部ドキュメントを紹介することがあります。その点は留意ください。
ソフトウェアのインストール
Keycloakのインストールは、ダウンロードして解凍するだけです。この章では、配布物のディレクトリー構造とシステム要件について説明します。
インストールの前提条件
これらの前提条件は、Keycloak サーバーをインストールするために存在します。
-
Javaが実行可能なオペレーティング・システム
-
Java 8 JREまたはJava 11 JRE
-
zipまたはgzip、およびtar
-
RAM512M以上
-
ディスクスペース1G以上
-
PostgreSQL、MySQL、Oracleなどの共有外部データベース。Keycloakをクラスターで実行する場合は、外部共有データベースが必要です。詳細については、このガイドのデータベース設定のセクションを参照してください。
-
マルチキャストなしでもクラスターを構成できますが、多くの設定変更が必要になります。詳しくは、このガイドのクラスタリングセクションを参照してください。
-
Linuxにおいては、セキュリティー・ポリシーにより
/dev/random
の使用が義務付けられている場合を除き、ランダムデータのソースとして/dev/urandom
を使用することをお勧めします。エントロピー不足が原因でKeycloakが固まるのを防ぐことができます。Oracle JDK 8およびOpenJDK 8でこれを使用するには、起動時のjava.security.egd
システム・プロパティーをfile:/dev/urandom
に設定してください。
Keycloakサーバーのインストール
Keycloakサーバーには、ダウンロード可能な2つの配布物があります。
-
keycloak-19.0.3.[zip|tar.gz]
このファイルは、サーバーのみの配布物です。Keycloakサーバーを実行するためのスクリプトとバイナリー以外は何も含まれていません。
-
keycloak-overlay-19.0.3.[zip|tar.gz]
このファイルは、既存のWildFlyディストリビューションの上にKeycloakサーバーをインストールするために使用できるWildFlyアドオンです。 アプリケーションとKeycloakを同じサーバー・インスタンスで動作させたいというユーザーには対応していません。
-
Keycloakサーバーをインストールするには、お使いのOSの
unzip
またはgunzip
とtar
ユーティリティーをkeycloak-19.0.3.[zip|tar.gz]
ファイル上で実行します。 -
Keycloak Service Packをインストールするには、別のサーバー・インスタンスにインストールする必要があります。
-
あなたのWildFlyディストリビューションのルート・ディレクトリーに移動します。
-
keycloak-overlay-19.0.3.[zip|tar.gz]
ファイルを解凍してください。 -
シェルでbinディレクトリーを開きます。
-
./jboss-cli.[sh|bat] --file=keycloak-install.cli
を実行します。
-
重要なディレクトリ
サーバー配布物の中で重要なディレクトリを以下に示します。
- bin/
-
サーバーの起動またはサーバー上でその他管理操作を行う、さまざまなスクリプトが含まれています。
- domain/
-
Keycloakをドメインモードで実行する場合の、設定ファイルとワーキング・ディレクトリーが含まれています。
- modules/
-
サーバー上で使用されるすべてのJavaライブラリーです。
- standalone/
-
Keycloakをスタンドアローン・モードで実行する場合の、設定ファイルとワーキング・ディレクトリーが含まれています。
- standalone/deployments/
-
Keycloakの拡張を作成する場合、ここに配置することができます。詳しくは、 Server Developer Guide を参照してください。
- themes/
-
このディレクトリーには、サーバーによって表示されるUI画面を表示するために使用されるすべてのHTML、スタイルシート、JavaScriptファイル、および画像が含まれます。ここでは、既存のテーマを変更したり、独自のテーマを作成したりすることができます。詳細については、 Server Developer Guide を参照してください。
動作モードの使い方
プロダクション環境にKeycloakを導入する前に、どのタイプの動作モードを使用するかを決める必要があります。
-
Keycloakをクラスター内で実行するか?
-
サーバーの設定を一元的に管理したいか?
動作モードの選択は、データベースの設定やキャッシングの設定、さらにはサーバーの起動方法にも影響します。
KeycloakはWildFlyアプリケーション・サーバー上に構築されています。このガイドでは、基本的な特定のモードでのデプロイメントについて説明します。詳しくは、WildFly 23 Documentationを参照してください。 |
スタンドアローン・モードの使用
スタンドアローン動作モードは、サーバーに1つのKeycloakサーバー・インスタンスを起動する場合にのみ有効です。クラスター構成には使用できません。また、キャッシュは分散されておらずローカル専用です。スタンドアローン・モードは単一障害点となりえるので、プロダクション環境での使用はお勧めしません。スタンドアローン・モードのサーバーがダウンした場合、ユーザーはログインできなくなります。そのため、このモードはテストおよびKeycloakの機能を試す目的にのみ有効です。
スタンドアローン・モードでの起動
スタンドアローン・モードでサーバーを実行する場合、使用するオペレーティング・システムに応じて、サーバーを起動するために必要な特定のスクリプトがあります。これらのスクリプトは、サーバー配布物の bin/ ディレクトリーにあります。
サーバーを起動するには下記を実行します。
$ .../bin/standalone.sh
> ...\bin\standalone.bat
スタンドアローン・モード構成
このガイドの大半は、Keycloakの基盤レベルの設定について説明します。このレベルの設定は、Keycloakが構築されたアプリケーション・サーバーに特化した設定ファイル内に定義されます。スタンドアローン動作モードでは、このファイルは …/standalone/configuration/standalone.xml にあります。また、このファイルはKeycloakのコンポーネントに特化した非基盤レベルの設定にも使用されます。
サーバーの実行中にこのファイルに変更を加えても、反映されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 23 Documentationを参照してください。 |
スタンドアローン・クラスター・モードの使用
スタンドアローン・クラスター動作モードは、クラスター内でKeycloakを実行するときに適用します。このモードでは、サーバー・インスタンスを実行する各マシンにKeycloakの配布物のコピーが保存されている必要があります。このモードは、最初は非常に簡単にデプロイできますが、後でかなり煩雑になる可能性があります。設定を変更するには、各マシンの配布物を修正します。大規模なクラスターの場合、時間がかかり、エラーも発生しやすくなります。
スタンドアローン・クラスター設定
この配布物には、クラスター内で実行するためのアプリケーション・サーバーの設定ファイルが含まれており、その大半は設定が済んでいます。ネットワーク、データベース、キャッシュ、およびディスカバリーのための基盤設定がすべて含まれています。このファイルは …/standalone/configuration/standalone-ha.xml にあります。しかし、この設定だけでは足りません。共有データベース接続を設定せずに、クラスター内でKeycloakを実行することはできません。また、クラスターのフロントに何らかのロードバランサーを配備する必要があります。このガイドのクラスタリングとデータベースのセクションでは、これらのことを説明します。
サーバーの実行中にこのファイルに変更を加えても、反映されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 23 Documentationを参照してください。 |
スタンドアローン・クラスター・モードでの起動
Keycloakを起動するには、スタンドアローン・モードで実行したのと同じ起動スクリプトを使用します。スタンドアローン・モードとの違いは、HA設定ファイルを指し示す追加フラグを渡すという点になります。
サーバーを起動するには下記を実行します。
$ .../bin/standalone.sh --server-config=standalone-ha.xml
> ...\bin\standalone.bat --server-config=standalone-ha.xml
ドメイン・クラスター・モードの使用
ドメインモードとは、サーバーの設定を一元管理し、クラスター内の各サーバーに反映させる方法です。
標準モードでクラスターを実行すると、クラスターが大きくなり、煩雑化する可能性があります。設定を変更する必要があるたびに、クラスター内の各ノードでそれを実行します。一方、ドメインモードの場合は、設定を保存しパブリッシュするために一元管理する場所を提供することで、この問題を解決できます。セットアップにはかなり手間がかかりますが、最終的にはその工数は見合うことになります。この機能はKeycloakが構成されるWildFlyアプリケーション・サーバーに組み込まれています。
このガイドでは、ドメインモードの初歩的なところを説明します。クラスター内でのドメインモードのセットアップ手順について、詳しくは、WildFly 23 Documentationを参照してください。 |
ドメインモードを実行する基本的なコンセプトは、以下のとおりです。
- ドメイン・コントローラー
-
ドメイン・コントローラーとは、クラスター内の各ノードの一般的な設定を保存、管理、パブリッシュする役割をもつ、プロセスのことです。また、クラスター内の各ノードが取得する設定を一元管理するデータベースでもあります。
- ホスト・コントローラー
-
ホスト・コントローラーの役割は、特定のマシン内のサーバー・インスタンスを管理することです。1つ以上のサーバー・インスタンスを実行できるよう、ホスト・コントローラーを設定することになります。また、ドメイン・コントローラーはクラスターを管理するために、各マシン内のホスト・コントローラーと連携します。実行プロセスを減らすために、ドメイン・コントローラーに、特定のマシン内のホスト・コントローラーとしての役割を担わせることもできます。
- ドメイン・プロファイル
-
ドメイン・プロファイルとは、サーバーを起動するために使用する、名前付きの設定セットです。ドメイン・コントローラーで、複数のドメイン・プロファイルを定義することができます。そして、さまざまなサーバーがこのドメイン・プロファイルを使うことになります。
- サーバーグループ
-
サーバーグループとは、サーバーの集合体です。ひとつの集合体として管理、設定されます。サーバーグループに、ドメイン・プロファイルを割り当てることができます。そして、そのドメイン・プロファイルはサーバーグループ内のサービスの設定として使用されます。
ドメインモードでは、マスターノード上でドメイン・コントローラーが起動されます。クラスターの設定は、ドメイン・コントローラー内にあります。次に、ホスト・コントローラーがクラスター内の各マシンで起動されます。各ホスト・コントローラーのデプロイ設定では、そのマシンで起動するKeycloakサーバー・インスタンスの数を指定します。ホスト・コントローラーが起動すると、指定された数のKeycloakサーバー・インスタンスが起動します。これらのサーバー・インスタンスは、ドメイン・コントローラーから設定を取得します。
Microsoft Azureなどの一部の環境では、ドメインモードは適用されません。WildFlyのドキュメントを参照してください。 |
ドメイン設定
このガイドの各章では、データベース、HTTPネットワーク接続、キャッシュ、およびその他の基盤関連のさまざまな設定について説明します。これらを設定するために、スタンドアローン・モードでは standalone.xml ファイルを使用するのに対して、ドメインモードでは …/domain/configuration/domain.xml を使用します。Keycloakサーバーのドメイン・プロファイルとサーバーグループは、以下で定義されます。
ドメイン・コントローラーの実行中にこのファイルに変更を加えても、変更されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 23 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 should be removed in production systems and replaced with a better software or hardware based one -->
<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 should be removed in production systems and replaced with a better software or hardware based one -->
<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>
ホスト・コントローラー設定
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>
<!-- remove or comment out next line -->
<server name="load-balancer" group="loadbalancer-group"/>
...
</servers>
このファイルのもう一つの興味深い点は、認証サーバー・インスタンスの宣言です。これには、 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>
サーバー・インスタンス・ワーキング・ディレクトリー
ホスト・ファイルに定義されている各Keycloakサーバー・インスタンスにより、 …/domain/servers/{SERVER NAME} の下に作業ディレクトリーが作成されます。そこに追加の設定を保存でき、サーバー・インスタンスが必要とする、または作成する一時ファイル、ログファイル、データファイルも保存することができます。これらのサーバー・ディレクトリーごとの構造は、他のWildFlyブートサーバーと同じようなものになります。
ドメイン・クラスター・モードでの起動
ドメインモードでサーバーを実行する場合、オペレーティング・システム固有の起動スクリプトを実行する必要があります。これらのスクリプトは、サーバー配布物の bin/ ディレクトリーにあります。
サーバーを起動するには下記を実行します。
$ .../bin/domain.sh --host-config=host-master.xml
> ...\bin\domain.bat --host-config=host-master.xml
起動スクリプトを実行する場合、 --host-config
スイッチ経由で、使用するホスト制御設定ファイルを渡す必要があります。
クラスター化されたドメインのサンプルを使ったテスト
サンプルの domain.xml 設定を使用してクラスタリングをテストできます。このサンプルドメインは、1台のマシンで実行され、以下を起動します。
-
ドメイン・コントローラー
-
HTTPロードバランサー
-
2つのKeycloakサーバー・インスタンス
-
2つのホスト・コントローラーを起動するために、
domain.sh
スクリプトを2回実行します。1つ目はマスター・ホスト・コントローラーで、ドメイン・コントローラー、HTTPロードバランサー、1つのKeycloak認証サーバー・インスタンスを起動します。2つ目はスレーブ・ホスト・コントローラーで、認証サーバーのインスタンスのみを起動します。
-
スレーブ・ホスト・コントローラーがドメイン・コントローラーと安全に通信できるように設定します。以下の手順を実行してください。
これらの手順を省略すると、スレーブホストはドメイン・コントローラーから集中管理された設定を取得できません。
-
マスターとスレーブの間で共有されるサーバー管理者のユーザーとシークレットを作成し、安全な接続を設定します。
…/bin/add-user.sh
スクリプトを実行してください。 -
スクリプトで追加するユーザーの種類を尋ねられたら、
Management User
を選択します。この選択により、 …/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">
-
ブートスクリプトを2回実行して、1台の開発マシンで2つのノードクラスターをシミュレートします。
マスターの起動$ domain.sh --host-config=host-master.xml
スレーブの起動$ domain.sh --host-config=host-slave.xml
-
ブラウザーを開いてhttp://localhost:8080/authにアクセスし、試してみてください。
クロスサイト・レプリケーション・モードの使用
cross-site replication modeは、 テクノロジー・プレビュー であり、完全にはサポートされていません。 |
クロスサイト・レプリケーション・モードを使用して、複数のデータセンターにまたがるクラスターでKeycloakを実行します。一般的には、異なる地域にあるデータセンターのサイトを使用します。このモードを使用すると、各データセンターはKeycloakサーバーの独自のクラスターを持つことになります。
このドキュメントでは、以下のアーキテクチャー図の例を参照して、シンプルなクロスサイト・レプリケーションのユースケースを説明します。
前提条件
これは高度なトピックのため、最初に以下を読み、背景にある重要な知識を身につけておくことをお勧めします。
-
Keycloakによるクラスタリング クロスデータセンター・レプリケーションを設定する場合、より独立したKeycloakクラスターを使用するため、クラスターの仕組みや、ロード・バランシング、共有データベース、マルチキャストなどの基本的な概念と要件を理解する必要があります。
-
Infinispan Cross-Site Replication は、地理的に離れた場所にあるクラスター間でデータをレプリケーションします。
技術的な詳細
このセクションでは、Keycloakクロスサイト・レプリケーションの仕組みについて概念と詳細について説明します。
Keycloakはステートフルなアプリケーションです。データソースとして以下のものを使用します。
-
データベースは、ユーザー情報などの永続的なデータを保持するために使用されます。
-
Infinispanキャッシュは、永続化データをデータベースからキャッシュし、短期間で頻繁に変化するメタデータ(ユーザー・セッションなど)を節約するためにも使用されます。Infinispanは通常、データベースよりもはるかに高速ですが、Infinispanを使用して保存されたデータは永続的ではなく、クラスターを再起動後も維持できるとは限りません。
このアーキテクチャーの例では、 site1
と site2
と呼ばれる2つのデータセンターがあります。クロスサイト・レプリケーションでは、両方のデータソースが確実に動作し、 site2
のKeycloakサーバーによって保存されたデータを site1
のKeycloakサーバーが最終的に読み取ることができるようにする必要があります。
環境に基づいて、次の選択肢から決める必要があります。
-
信頼性 - 通常はアクティブ/アクティブモードで使用されます。
site1
で記述されたデータはsite2
ですぐに表示される必要があります。 -
パフォーマンス - 通常はアクティブ/パッシブモードで使用されます。
site1
で記述されたデータはすぐにsite2
で表示される必要はありません。状況によって、site2
でデータが表示されないこともあります。
詳細は、モードを参照してください。
リクエスト処理
エンドユーザーのブラウザーは、HTTPリクエストをフロント・エンド・ロードバランサーに送信します。このロードバランサーは、通常mod_cluster、NGINX、HA Proxy、またはその他のソフトウェアかハードウェア・ロードバランサーを使用するHTTPDまたはWildFlyです。
ロードバランサーは、基になるKeycloakインスタンスに、受け取ったHTTPリクエストを転送します。このインスタンスは、複数のデータセンターに分散させることができます。ロードバランサーは通常、スティッキー・セッションをサポートしています。つまり、ロードバランサーは、同じデータセンターの同じKeycloakインスタンスに、同じユーザーのすべてのHTTPリクエストを常に転送することができます。
クライアント・アプリケーションからロードバランサーに送られたHTTPリクエストは バックチャネル・リクエスト
と呼ばれます。これらはエンドユーザーのブラウザーからは見えないので、ユーザーとロードバランサー間でスティッキー・セッションの一部になることはできません。バックチャネル・リクエストの場合、ロードバランサーは、HTTPリクエストを任意のデータセンター内のいずれかのKeycloakインスタンスに転送することができます。これは、いくつかのOpenID ConnectといくつかのSAMLフローがユーザーとアプリケーションの両方から複数のHTTPリクエストを必要とするため、難しい問題です。関連するすべてのリクエストを同じデータセンター内の同じKeycloakインスタンスに送信するのにスティッキー・セッションに完全に依存することはできないため、代わりに、データセンター間で一部のデータをレプリケートする必要があります。それにより、データは特定のフロー中の後続のHTTPリクエストによって表示されます。
モード
要件に応じて、クロスサイト・レプリケーションには2つの基本的な動作モードがあります。
-
アクティブ/パッシブ - ユーザーとクライアント・アプリケーションは、単一のデータセンター内のKeycloakノードにのみリクエストを送信します。第2のデータセンターは、データを保存するための
バックアップ
としてのみ使用されます。メインのデータセンターに障害が発生した場合、通常は第2のデータセンターからデータを復旧します。 -
アクティブ/アクティブ - ユーザーとクライアント・アプリケーションは、両方のデータセンターのKeycloakノードにリクエストを送信します。つまり、両方のサイトですぐにデータを表示し、 両方のサイトのKeycloakサーバーからデータをすぐに使用できるようにする必要があります。これは、Keycloakサーバーが
site1
に何かしらのデータを書き込む場合に特に当てはまります。また、site1
への書き込みが完了した直後に、site2
のKeycloakサーバーがデータをすぐに読み取ることができるようにする必要があります。
アクティブ/パッシブモードは、パフォーマンスに優れています。いずれかのモードでキャッシュを設定する方法の詳細については、 SYNCまたはASYNCバックアップ を参照してください。
データベース
Keycloakは、リレーショナル・データベース・マネジメント・システム(RDBMS)を使用して、レルム、クライアント、ユーザーなどのメタデータを保持します。詳細については、サーバーインストールガイドのこの章を参照してください。クロスサイト・レプリケーションのセットアップでは、両方のデータセンターが同じデータベースと通信するか、すべてのデータセンターに独自のデータベース・ノードがあり、両方のデータベース・ノードがデータセンター間で同期レプリケートされると想定しています。どちらの場合でも、 site1
のKeycloakサーバーがデータを保持してトランザクションをコミットすると、 site2
の後続のDBトランザクションによって、それらのデータがすぐに表示される必要があります。
DBのセットアップの詳細については、Keycloakの範囲外ですが、MariaDBやOracleなどのRDBMSベンダーの多くは、レプリケートされたデータベースと同期レプリケーションを提供しています。これらのベンダーを使用して、Keycloakをテストしています。
-
Oracle Database 19c RAC
-
Galera 3.12 cluster for MariaDB server version 10.1.19-MariaDB
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
が不正なパスワードを入力した回数など、ログイン失敗に関するデータを追跡するために使用されます。詳細は、こちらを参照してください。このキャッシュをデータセンター間でレプリケートするかどうかは、管理者次第です。正確なログイン失敗の回数を取得するには、レプリケーションが必要です。一方、このデータをレプリケートしないことで、パフォーマンスをよくできます。したがって、パフォーマンスがログイン失敗の正確な回数よりも重要な場合は、レプリケーションを避けるという手もあります。
キャッシュの設定方法の詳細については、Infinispanキャッシュ設定のチューニングを参照してください。
コミュニケーションの詳細
Keycloakは、Infinispanキャッシュの分割されたクラスターを複数使用します。各Keycloakノードは、同じデータセンター内の他のKeycloakノードと共にクラスター内にありますが、異なるデータセンターのKeycloakノードはそのクラスター内にありません。Keycloakノードは、異なるデータセンターのKeycloakノードと直接通信できません。Keycloakノードは、データセンター間の通信に外部JDG(実際にはInfinispanサーバー)を使用します。これは、 Infinispan HotRodプロトコル を使用して行われます。
Keycloak側のInfinispanキャッシュは、データがリモート・キャッシュに保存されていることを確認するために、 remoteStore を使用して設定する必要があります。JDGサーバー間に分割されたInfinispanクラスターがあるので、 site1
のJDG1に保存されていたデータは site2
のJDG2にレプリケートされます。
受信Infinispanサーバーは、Hot Rodプロトコルの機能であるクライアント・リスナーを介して、クラスター内のKeycloakサーバーに通知します。次に、 site2
のKeycloakノードがInfinispanキャッシュを更新し、特定のユーザー・セッションが site2
のKeycloakノードにも表示されます。
詳細は、アーキテクチャー図の例を参照してください。
クロスサイト・レプリケーションの設定
以下の手順で、Infinispan 11.0.8のクロスサイト・レプリケーションの基本的な設定を行います。
Infinispanの正確な手順は、Infinispan 8.1に適用されるこの手順と若干異なる場合があります。説明通りに動作しない手順については、Infinispanのドキュメントを確認してください。 |
Infinispan 11.0.8のこの例には、 site1
と site2
の2つのデータセンターが含まれます。各データセンターは、1つのInfinispanサーバーと2つのKeycloakサーバーで構成されています。合計すると、2つのInfinispanサーバーと4つのKeycloakサーバーになります。
-
Site1
は、Infinispanサーバーのserver1
と2つのKeycloakサーバーのnode11
およびnode12
で構成されています。 -
Site2
は、Infinispanサーバーのserver2
と2つのKeycloakサーバーのnode21
およびnode22
で構成されています。 -
Infinispanサーバーである
server1
とserver2
は、 Infinispan のドキュメント で記載されているのと同様の方法で、RELAY2プロトコルとbackup
ベースのInfinispanキャッシュを介して相互に接続されています。 -
Keycloakサーバーである
node11
とnode12
は、お互いにクラスターを形成しますが、site2
内のサーバーとは直接通信はしません。それらはHot Rodプロトコル (リモート・キャッシュ)を使用して、Infinispanサーバーserver1
と通信します。詳細については、コミュニケーションの詳細を参照してください。 -
同じ説明が
node21
とnode22
にも当てはまります。それらはお互いにクラスター化し、Hot Rodプロトコルを使用して、server2
サーバーとのみ通信します。
この設定の例では、4つのKeycloakサーバーすべてが同じデータベースと通信することを前提としています。プロダクション環境では、データベースで説明されているとおり、データセンター間で別々の同期レプリケートされたデータベースを使用することをお勧めします。
Infinispanサーバーのセットアップ
クロスサイト・レプリケーションの場合、KeycloakのデータをバックアップできるリモートInfinispanクラスターを作成することから始めます。
-
Infinispanサーバー11.0.8をダウンロードしてインストールします。
Infinispanサーバー11.0.8にはJava 11が必要です。 |
-
Infinispanからのクライアント接続を認証するユーザーを作成します。次に例を示します。
$ bin/cli.sh user create myuser -p "qwer1234!"
Keycloakにリモートキャッシュを作成するときに、HotRodクライアントの設定でこれらのクレデンシャルを指定します。
-
InfinispanとKeycloakの間の接続を保護するために、SSLキーストアとトラストストアを作成します。次に例を示します。
-
キーストアを作成して、InfinispanクラスターにSSLのIDを提供します
keytool -genkey -alias server -keyalg RSA -keystore server.jks -keysize 2048
-
キーストアからSSL証明書をエクスポートします。
keytool -exportcert -keystore server.jks -alias server -file server.crt
-
KeycloakがInfinispanのSSLのIDを確認するために使用できるトラストストアに、SSL証明書をインポートします。
keytool -importcert -keystore truststore.jks -alias server -file server.crt
-
server.crt
を削除します。rm server.crt
-
Infinispanクラスターの設定
データセンター間でKeycloakデータを複製するようにInfinispanクラスターを設定します。
-
Infinispanサーバーをインストールしてセットアップします。
-
編集のために
infinispan.xml
を開きます。デフォルトでは、Infinispanサーバーはクラスター・トランスポートやセキュリティー機構などの静的設定に
server/conf/infinispan.xml
を使用します。 -
クラスター検出プロトコルとしてTCPPINGを使用するスタックを作成します。
<stack name="global-cluster" extends="tcp"> <!-- Remove MPING protocol from the stack and add TCPPING --> <TCPPING initial_hosts="server1[7800],server2[7800]" (1) stack.combine="REPLACE" stack.position="MPING"/> </stack>
1 server1
とserver2
のホスト名を一覧表示します。 -
Infinispanのクラスター・トランスポートを設定して、クロスサイト・レプリケーションを実行します。
-
RELAY2プロトコルをJGroupsスタックに追加します。
<jgroups> <stack name="xsite" extends="udp"> (1) <relay.RELAY2 site="site1" (2) max_site_masters="1000"/> (3) <remote-sites default-stack="global-cluster"> (4) <remote-site name="site1"/> <remote-site name="site2"/> </remote-sites> </stack> </jgroups>
1 デフォルトのUDPクラスター・トランスポートを拡張する xsite
という名前のスタックを作成します。2 RELAY2プロトコルを追加し、設定しているクラスターに site1
という名前を付けます。サイト名は、各Infinispanクラスターに固有である必要があります。3 クラスターのリレーノードの数として1000を設定します。Infinispanクラスター内のノードの最大数以上の値を設定する必要があります。 4 InfinispanデータでキャッシュをバックアップするすべてのInfinispanクラスターに名前を付け、クラスター間転送にデフォルトのTCPスタックを使用します。 -
スタックを使用するようにInfinispanクラスター・トランスポートを設定します。
<cache-container name="default" statistics="true"> <transport cluster="${infinispan.cluster.name:cluster}" stack="xsite"/> (1) </cache-container>
1 クラスターに xsite
スタックを使用します。
-
-
サーバー・セキュリティー・レルムでキーストアをSSLのIDとして設定します。
<server-identities> <ssl> <keystore path="server.jks" (1) relative-to="infinispan.server.config.path" keystore-password="password" (2) alias="server" /> (3) </ssl> </server-identities>
1 SSLのIDを含むキーストアのパスを指定します。 2 キーストアにアクセスするためのパスワードを指定します。 3 キーストア内の証明書のエイリアスに名前を付けます。 -
HotRodエンドポイントの認証機構を設定します。
<endpoints socket-binding="default"> <hotrod-connector name="hotrod"> <authentication> <sasl mechanisms="SCRAM-SHA-512" (1) server-name="infinispan" /> (2) </authentication> </hotrod-connector> <rest-connector name="rest"/> </endpoints>
1 Hot RodのエンドポイントのSASL認証メカニズムを設定します。SCRAM-SHA-512は、Hot RodのデフォルトのSASLメカニズムです。ただし、GSSAPIなど、環境に応じて適切なものを使用できます。 2 Infinispanサーバーがクライアントに提示する名前を定義します。この名前は、Keycloakを設定するときにHotRodクライアントの設定で指定します。 -
キャッシュ・テンプレートを作成します。
Infinispanクラスター内の各ノードの infinispan.xml
にキャッシュ・テンプレートを追加します。<cache-container ... > <replicated-cache-configuration name="sessions-cfg" (1) mode="SYNC"> (2) <locking acquire-timeout="0" /> (3) <backups> <backup site="site2" strategy="SYNC" /> (4) </backups> </replicated-cache-configuration> </cache-container>
1 sessions-cfg
という名前のキャッシュ・テンプレートを作成します。2 クラスター全体でデータを同期的に複製するキャッシュを定義します。 3 ロック獲得のタイムアウトを無効にします。 4 設定しているInfinispanクラスターのバックアップ・サイトに名前を付けます。 -
Infinispanのserver1を起動します。
./server.sh -c infinispan.xml -b PUBLIC_IP_ADDRESS -k PUBLIC_IP_ADDRESS -Djgroups.mcast_addr=228.6.7.10
-
Infinispanのserver2を起動します。
./server.sh -c infinispan.xml -b PUBLIC_IP_ADDRESS -k PUBLIC_IP_ADDRESS -Djgroups.mcast_addr=228.6.7.11
-
Infinispanサーバーログをチェックして、クラスターがクロスサイト・ビューを形成していることを確認します。
INFO [org.infinispan.XSITE] (jgroups-5,${server.hostname}) ISPN000439: Received new x-site view: [site1] INFO [org.infinispan.XSITE] (jgroups-7,${server.hostname}) ISPN000439: Received new x-site view: [site1, site2]
Infinispanキャッシュの生成
Keycloakが必要とするInfinispanキャッシュを生成します。
infinispan.xml
にキャッシュを追加するのではなく、実行時にInfinispanクラスターにキャッシュを作成することをお勧めします。この戦略により、キャッシュがクラスター全体で自動的に同期され、永続的に保存されます。
次の手順では、Infinispanコマンドライン・インターフェイス(CLI)を使用して、必要なすべてのキャッシュを1つのバッチコマンドで作成します。
-
Infinispanクラスターを設定します。
-
たとえば、次にようにキャッシュを含むバッチファイルを作成します。
cat > /tmp/caches.batch<<EOF echo "creating caches..." create cache work --template=sessions-cfg create cache sessions --template=sessions-cfg create cache clientSessions --template=sessions-cfg create cache offlineSessions --template=sessions-cfg create cache offlineClientSessions --template=sessions-cfg create cache actionTokens --template=sessions-cfg create cache loginFailures --template=sessions-cfg echo "verifying caches" ls caches EOF
-
CLIを使用してキャッシュを作成します。
$ bin/cli.sh -c https://server1:11222 --trustall -f /tmp/caches.batch
引数 --trustall
の代わりに、引数-t
でトラストストアを指定し、-s
引数でトラストストア・パスワードを指定できます。 -
他のサイトにキャッシュを作成します。
Keycloakでのリモート・キャッシュ・ストアの設定
リモートのInfinispanクラスターをセットアップした後、KeycloakでInfinispanサブシステムを設定して、リモートストアを介してそれらのクラスターにデータを外部化します。
-
クロスサイト設定用にリモートInfinispanクラスターをセットアップします。
-
InfinispanServerのIDを持つSSL証明書を含むトラストストアを作成します。
-
トラストストアをKeycloakの配備に追加します。
-
Infinispanクラスターを指すソケット・バインディングを作成します。
<outbound-socket-binding name="remote-cache"> (1) <remote-destination host="${remote.cache.host:server_hostname}" (2) port="${remote.cache.port:11222}"/> (3) </outbound-socket-binding>
1 ソケット・バインディングに remote-cache
という名前を付けます。2 Infinispanクラスターに対して1つ以上のホスト名を指定します。 3 HotRodエンドポイントがリッスンする 11222
のポートを定義します。 -
org.keycloak.keycloak-model-infinispan
モジュールをInfinispanサブシステムのkeycloak
キャッシュ・コンテナーに追加します。<subsystem xmlns="urn:jboss:domain:infinispan:12.0"> <cache-container name="keycloak" modules="org.keycloak.keycloak-model-infinispan"/>
-
Infinispanサブシステムの
work
キャッシュを更新して、次の設定にします。<replicated-cache name="work"> (1) <remote-store cache="work" (2) remote-servers="remote-cache" (3) 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> <property name="infinispan.client.hotrod.auth_username">myuser</property> <property name="infinispan.client.hotrod.auth_password">qwer1234!</property> <property name="infinispan.client.hotrod.auth_realm">default</property> <property name="infinispan.client.hotrod.auth_server_name">infinispan</property> <property name="infinispan.client.hotrod.sasl_mechanism">SCRAM-SHA-512</property> <property name="infinispan.client.hotrod.trust_store_file_name">/path/to/truststore.jks</property> <property name="infinispan.client.hotrod.trust_store_type">JKS</property> <property name="infinispan.client.hotrod.trust_store_password">password</property> </remote-store> </replicated-cache>
1 Infinispanの設定でキャッシュに名前を付けます。 2 リモートInfinispanクラスター上の対応するキャッシュに名前を付けます。 3 remote-cache
ソケット・バインディングを指定します。上記のキャッシュ設定には、Infinispanキャッシュの推奨設定が含まれています。Hot Rodクライアント設定プロパティーは、Infinispanユーザー・クレデンシャルとSSLのキーストアおよびトラストストアの詳細を指定します。
各プロパティーの説明については、 Infinispan ドキュメント を参照してください。
-
次の各キャッシュに対する分散キャッシュをInfinispanサブシステムに追加します。
-
sessions
-
clientSessions
-
offlineSessions
-
offlineClientSessions
-
actionTokens
-
loginFailures
たとえば、次の設定で
sessions
という名前のキャッシュを追加します。<distributed-cache name="sessions" (1) owners="1"> (2) <remote-store cache="sessions" (3) remote-servers="remote-cache" (4) 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> <property name="infinispan.client.hotrod.auth_username">myuser</property> <property name="infinispan.client.hotrod.auth_password">qwer1234!</property> <property name="infinispan.client.hotrod.auth_realm">default</property> <property name="infinispan.client.hotrod.auth_server_name">infinispan</property> <property name="infinispan.client.hotrod.sasl_mechanism">SCRAM-SHA-512</property> <property name="infinispan.client.hotrod.trust_store_file_name">/path/to/truststore.jks</property> <property name="infinispan.client.hotrod.trust_store_type">JKS</property> <property name="infinispan.client.hotrod.trust_store_password">password</property> </remote-store> </distributed-cache>
1 Infinispanの設定でキャッシュに名前を付けます。 2 Infinispanクラスター全体で各キャッシュ・エントリーのレプリカを1つ設定します。 3 リモートInfinispanクラスター上の対応するキャッシュに名前を付けます。 4 remote-cache
ソケット・バインディングを指定します。
-
-
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=server1 \ -Djava.net.preferIPv4Stack=true -b PUBLIC_IP_ADDRESS
ログに次の警告メッセージが表示された場合は、無視しても問題ありません。
WARN [org.infinispan.CONFIG] (MSC service thread 1-5) ISPN000292: Unrecognized attribute 'infinispan.client.hotrod.auth_password'. Please check your configuration. Ignoring! WARN [org.infinispan.CONFIG] (MSC service thread 1-5) ISPN000292: Unrecognized attribute 'infinispan.client.hotrod.auth_username'. Please check your configuration. Ignoring!
-
次のように、
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=server1 \ -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=server2 \ -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=server2 \ -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'
-
クロスサイト・デプロイメントの管理
このセクションでは、クロスサイト・レプリケーションに関連するヒントやオプションをご紹介します。
-
Keycloakサーバーをデータセンター内で実行する場合、
KeycloakDS
データソース内で参照されたデータベースがすでに実行され、そのデータセンター内で使用可能である必要があります。また、 Infinispanキャッシュのremote-store
要素から参照されるoutbound-socket-binding
によって参照されたInfinispanサーバーがすでに実行されてることが必要です。そうしないと、Keycloakサーバーは起動に失敗します。 -
データベース・フェイルオーバーと高い信頼性をサポートする必要がある場合、すべてのデータセンターでより多くのデータベース・ノードを持たせます。データベース側での設定方法とKeycloak側の
KeycloakDS
データソースで必要な設定方法の詳細については、JDBCドライバーのドキュメントを参照してください。 -
すべてのデータセンターで、より多くのInfinispanサーバーをクラスター内で実行することができます。これは、フェイルオーバーとフォールト・トレランスを強化する場合に便利です。InfinispanサーバーとKeycloakサーバー間の通信で使用されるHot Rodプロトコルには、InfinispanサーバーがInfinispanクラスターの変更について、Keycloakサーバーに新しいトポロジーを自動的に送信する機能を備えています。したがって、Keycloak側のリモートストアは、どのInfinispanサーバーに接続できるのかが分かります。詳細については、InfinispanとWildFlyドキュメントを参照してください。
-
どんな サイトのKeycloakサーバーも起動する前に、すべてのサイトでマスターInfinispanサーバーを実行することを強くお勧めします。この例では、すべてのKeycloakサーバーの前に、
server1
とserver2
の両方を最初に起動します。Keycloakサーバーをそれでも実行する必要があり、バックアップ・サイトがオフラインである場合は、サイトをオフラインおよびオンラインにするでの説明のとおり、サイトのInfinispanサーバー上のバックアップ・サイトを手動でオフラインに切り替えることをお勧めします。使用できない状態のサイトをオフラインに手動で切り替えることができない場合、初回起動に失敗するか、起動時にいくつか例外が発生する可能性があります。これは、失敗した操作の設定数によってバックアップ・サイトが自動的にオフラインになるまでです。
サイトをオフラインおよびオンラインにする
たとえば、以下のようなシナリオを想定します。
-
サイト
site1
から見たサイトsite2
は、完全にオフラインです。これは、site2
のすべてのInfinispanサーバーがオフである、 または 、site1
とsite2
の間のネットワークが切断されていることを意味します。 -
サイト
site1
でKeycloakサーバーとInfinispanサーバーserver1
を実行します。 -
いずれかのユーザーが
site1
のKeycloakサーバーにログインします。 -
site1
のKeycloakサーバーは、site2
のserver2
サーバーにデータをバックアップすることを想定し、server1
サーバー上のリモート・キャッシュにセッションを書き込もうとします。詳細については、コミュニケーションの詳細を参照してください。 -
server2
サーバーがオフラインであるか、server1
から到達できない状態なので、server1
からserver2
へのバックアップは失敗します。 -
例外は
server1
のログにスローされます。デフォルトのFAIL
バックアップ失敗ポリシーが設定されているため、その失敗はserver1
サーバーからKeycloakサーバーにも伝播されます。バックアップ・ポリシーの詳細については、バックアップ失敗ポリシーを参照してください。 -
このエラーはKeycloak側でも発生し、ユーザーはログインを完了できない可能性もあります。
使用している環境に応じて、サイト間のネットワークが利用できないか、一時的に壊れている(スプリット・ブレイン)可能性があります。これが起こった場合、 site1
のInfinispanサーバーは、 site2
のInfinispanサーバーが利用できないことに気付き、 server2
サイトのサーバーへアクセスしようとするのを止めるため、バックアップの失敗は発生しません。これは サイトをオフラインにする
と呼ばれています。
サイトをオフラインにするには2つの方法があります。
管理者による手作業 - 管理者は jconsole
または他のツールを使用して、いくつかのJMX操作を実行することで、手動で特定のサイトをオフラインにすることができます。これは、特に停止が計画されている場合に役立ちます。 jconsole
またはCLIを使用すると、 server1
サーバーに接続し、 site2
をオフラインにすることができます。この詳細については、 Infinispanドキュメント を参照してください。
SYNCまたはASYNCバックアップで述べた他のすべてのKeycloakキャッシュについても、通常はこれらの手順を実行する必要があります。 |
自動的作業 - 数回バックアップに失敗した後、通常は site2
が自動的にオフラインになります。これは、キャッシュ設定内の take-offline
要素の設定によって行われます。
<take-offline min-wait="60000" after-failures="3" />
この例では、少なくとも3回連続して失敗したバックアップがあり、60秒以内にバックアップが成功しなかった場合、特定のシングルキャッシュに対してサイトが自動的にオフラインになることを示しています。
自動的にサイトをオフラインにすることは、特に、サイト間の切断されたネットワークが計画外である場合に便利です。欠点は、ネットワークの停止が検出されるまで何らかのバックアップが失敗し、アプリケーション側で障害が起きてる可能性があります。たとえば、一部のユーザーのログインに失敗したり、大きなログインタイムアウトが発生したりします。 特に、値が FAIL
の failure-policy
が使用されている場合です。
サイトがオフラインであるかどうかの追跡は、キャッシュごとに個別に行われます。 |
一旦ネットワークが復旧し、 site1
と site2
がお互いに通信することができたら、サイトをオンラインにする必要があります。これは、サイトをオフラインにするのと同じように、JMXまたはCLIを使用して手動で行う必要があります。再度キャッシュをすべてチェックし、オンラインにする必要があります。
サイトをオンラインにしたら、通常は次のようにするのが良いです。
-
ステート・トランスファーを行います。
-
手動でキャッシュのクリアを行います。
ステート・トランスファー
ステート・トランスファーは、手動で行う必要があります。Infinispanサーバーはこれを自動的には行いません。たとえば、スプリット・ブレイン中は、誰がどのサイトを優先するかを管理者のみが決定することができます。したがって、ステート・トランスファーが両方のサイト間で双方向に、または site1
から site2
へのみ単方向で行われる必要がありますが、site2
から site1
への単方向は行われません。
双方向のステート・トランスファーによって、スプリット・ブレインの 後に site1
で作成されたエンティティーが site2
に確実に転送されます。これは site2
ではまだ発生していないので問題ありません。同じように、スプリット・ブレインの 後に site2
で作成されたエンティティーは site1
に転送されます。おそらく問題のある部分は、両方のサイトのスプリット・ブレインの 前に 存在し、両方のサイトのスプリット・ブレイン中に更新されたエンティティーです。これが発生すると、サイトの1つが 勝ち 、2番目のサイトがスプリット・ブレイン中に行った更新を上書きします。
残念ながら、これに対する広く一般的な解決方法はありません。スプリット・ブレインやネットワークの停止は状態に過ぎず、サイト間で100%の一貫性のあるデータで100%正確に処理することは通常不可能です。Keycloakの場合、これは特に重大な問題ではありません。最悪の場合、ユーザーがクライアントに再度ログインするか、loginFailuresの不正カウント数をブルートフォース保護のために追跡する必要があります。スプリット・ブレインに対処するためのヒントについては、Infinispan/JGroupsドキュメントを参照してください。
ステート・トランスファーは、JMXを介してInfinispanサーバー側でも行われます。操作名は pushState
です。状態をモニタリングしたり、プッシュ状態をキャンセルしたりするその他の操作はほとんどありません。ステート・トランスファーの詳細については、 Infinispan docs を参照してください。
キャッシュのクリア
スプリット・ブレイン後は、Keycloakの管理コンソールで手動でキャッシュをクリアするのが安全です。これは、 site1
のデータベースで変更されたデータがあり、イベントのために無効にする必要のあるキャッシュが、スプリット・ブレイン中に site2
へ転送されなかった可能性があるためです。したがって、 site2
のKeycloakノードでは、キャッシュ内に古いデータがまだ残っている可能性があります。
キャッシュをクリアするには、 Clearing Server Caches を参照してください。
ネットワークが復旧したら、いずれかのサイトの1つのKeycloakノードでキャッシュをクリアするだけで十分です。キャッシュの無効化イベントは、それぞれのサイトの他のKeycloakノードすべてに送られます。ただし、すべてのキャッシュ(レルム、ユーザー、鍵)に対して実行する必要があります。詳しくは、Clearing Server Cachesを参照してください。
Infinispanキャッシュ設定のチューニング
このセクションでは、JDGキャッシュを設定するためのヒントとオプションについて説明します。
デフォルトでは、Infinispanの 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 仕様では、コードは使い捨てでなければならないと言及されています。 WARN
ポリシーでは、これは厳密には保証されておらず、両方のサイトで同時に書き込まれる試みがあった場合、同じコードが2回書き込まれる可能性があります。
より長いネットワーク停止またはスプリット・ブレインが起きた場合、 FAIL
と WARN
を使用すると、サイトをオフラインおよびオンラインにするで説明したとおり、少し時間を置いて失敗した後、他のサイトはオフラインになります。デフォルトの1分のタイムアウトでは、関連するキャッシュがすべてオフラインになるまで、通常は1~3分かかります。その後、エンドユーザーの観点から、動作はすべて問題なく進みます。サイトをオフラインおよびオンラインにするで説明したとおり、オンラインに戻ったときに手動でサイトを復元する必要があります。
要約すると、サイト間で頻繁により長い停止が発生する可能性があり、データの不整合と100%正確ではない使い捨てのキャッシュについては許容されますが、エラーや長いタイムアウトがエンドユーザーに表示されないようにする場合には、 WARN
に切り替えます。
WARN
と IGNORE
の違いは、 IGNORE
では警告がInfinispanログに書き込まれていないことです。詳細については、Infinispanのドキュメントを参照してください。
デフォルト設定では、NON_DURABLE_XAモードでトランザクションを取得タイムアウト0で使用しています。これは、同じキーに対して進行中の別のトランザクションがある場合、トランザクションはすぐに失敗することを意味します。
デフォルトの10秒ではなく0に切り替えるのは、デッドロックの可能性を避けるためです。Keycloakでは、同じエンティティー(通常はセッション・エンティティーまたはloginFailure)が両方のサイトから同時に更新されることがあります。これにより、状況によってはデッドロックが発生し、トランザクションが10秒間ブロックされる可能性があります。 詳細については、 このJIRAレポート を参照してください。
タイムアウト0の場合、トランザクションは直ちに失敗し、値 FAIL
のバックアップ failure-policy
が設定されていれば、Keycloakから再試行されます。2番目の同時トランザクションが終了するまで、通常は再試行が成功し、エンティティーは両方の同時トランザクションから更新を適用します。
この設定での同時トランザクションは、非常に良い一貫性と結果が得られるため、そのまま使用することをお勧めします。
唯一の(機能しない)問題は、Infinispanサーバーログの例外です。これは、ロックがすぐに利用できなくなるたびに発生します。
SYNCまたはASYNCバックアップ
backup
要素の重要な部分は strategy
属性です。 SYNC
と ASYNC
のどちらが必要かを決める必要があります。クロスサイト・レプリケーションを認識できる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
属性に注意してください。
トラブルシューティング
以下のヒントは、トラブルシューティングが必要な場合に役立ちます。
-
まず、 クロスサイト・レプリケーションの設定 の手順を実行し、それを動作させて、どのように動作するかをある程度理解することをお勧めします。また、このドキュメント全体を読んで、仕様をある程度理解しておくことも賢明です。
-
Keycloakサーバーの場合、サーバーの起動時に次のようなメッセージが表示されます。
18:09:30,156 INFO [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (ServerService Thread Pool -- 54) Node name: node11, Site name: site1
Keycloakサーバーの起動時に、サイト名とノード名が想定どおりに表示されていることを確認してください。
-
同じデータセンターのKeycloakサーバーだけが互いにクラスターになっているなど、Keycloakサーバーが期待通りにクラスターになっていることを確認します。これは、JConsoleのGMSビューからも確認できます。
-
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サーバー側で正常に操作が成功するようにすることをお勧めします。詳細については、 クロスサイト・デプロイメントの管理 を参照してください。
-
JMXを介して利用可能なInfinispanの統計を確認してください。たとえば、ログインして、新しいセッションがInfinispanサーバーの両方に正常に書き込まれたかどうかを確認し、そこの
sessions
キャッシュで利用可能かどうかを確認します。これは、MBeanjboss.datagrid-infinispan:type=Cache,name="sessions(repl_sync)",manager="clustered",component=Statistics
とnumberOfEntries
属性のsessions
キャッシュ内の要素の数をチェックすることによって間接的に行うことができます。ログイン後、両方のサイトのそれぞれのInfinispanサーバーにnumberOfEntries
の1つ以上のエントリーが存在するはずです。 -
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:server1:4353. Lock is held by GlobalTx:server1:4352
これらの例外は必ずしも問題ではありません。両方のデータセンターで同じエンティティーの同時編集がトリガーされると、いつでも発生する可能性があります。これは、デプロイメントの多くの場合に当てはまります。たいてい、Keycloakサーバーは、失敗した操作について通知を受けて再試行するため、ユーザーの観点からは通常問題はありません。
-
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
キャッシュが無期限に増加した場合、 この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.redhat.com/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ログに類似のエラーが表示された場合は、互換性のないバージョンのHot Rodプロトコルが使用されていることを示しています。これは、Keycloakを古いバージョンのInfinispanサーバーで使用しようとした場合に発生する可能性があります。Keycloak設定ファイルの
remote-store
要素に、追加のプロパティーとしてprotocolVersion
プロパティーを追加すると役に立ちます。たとえば次のように設定します。<property name="protocolVersion">2.6</property>
サブシステム設定の管理
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>
このサブシステム内での変更はサーバーが再起動されるまで有効になりませんので、注意してください。
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 のリストはシステムからプロバイダーに渡されます。リストに値を追加するには、各リスト要素をカンマで区切ります。残念ながら、各リスト要素を囲む引用符を "
にエスケープする必要があります。
カスタム・プロバイダーとプロバイダーの設定の詳細については、Server Developer Guide の手順に従ってください。
WildFly CLIの起動
設定変更は、手作業で編集するだけでなく、 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 23 Documentationを参照してください。
CLI組み込みモード
サーバーがアクティブではない間にスタンドアローン・サーバーと同じマシン上にコマンドが発行された場合は、サーバーをCLIに組み込み、受信要求を許可しない特殊モードに変更することができます。これを行うには、まず、変更したい設定ファイルで embed-server
コマンドを実行します。
[disconnected /] embed-server --server-config=standalone.xml
[standalone@embedded /]
CLI GUIモードの使用
CLIはGUIモードでも実行できます。GUIモードでは、実行中のサーバーの管理モデル全体をグラフィカルに表示および編集できるSwingアプリケーションが起動します。GUIモードは、CLIコマンドの書式を設定したり、オプションを調べる際のヘルプとして特に便利です。GUIは、ローカルまたはリモートサーバーからサーバーログを取得することもできます。
-
GUIモードでのCLIの起動
$ .../bin/jboss-cli.sh --gui
注意: リモートサーバーに接続するには、
--connect
オプションも渡します。詳しくは、 --helpオプションを参照してください。 -
スクロールダウンして、
subsystem=keycloak-server
というノードを見つけます。 -
ノードを右クリックして、
Explore subsystem=keycloak-server
を選択します。新しいタブには、keycloak-serverサブシステムのみが表示されます。
keycloak-serverサブシステム
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
メニューに従うか、または以下のようにコマンドラインからスクリプトを実行します。
$ .../bin/jboss-cli.sh --file=turn-off-caching.cli
CLIレシピ
ここでは、設定タスクおよびそれらをCLIコマンドで実行する方法について説明します。代入すべきという意味で、またはkeycloak-serverサブシステムという意味でワイルドカード・パス **
を使用しています。その点は注意してください。
スタンドアローンの場合、これは単に以下の意味になります。
**
= /subsystem=keycloak-server
ドメインモードの場合、これは以下のような意味になります。
**
= /profile=auth-server-clustered/subsystem=keycloak-server
dblock SPIの設定
**/spi=dblock/:add(default-provider=jpa)
**/spi=dblock/provider=jpa/:add(properties={lockWaitTimeout => "900"},enabled=true)
プロファイル
Keycloakには、デフォルトでは有効とされていない機能があり、完全にはサポートされていないものがあります。さらに、デフォルトで有効とされている機能を無効にすることもできます。
有効および無効にできる機能は、以下のとおりです。
名前 | 説明 | デフォルトで有効 | サポートレベル |
---|---|---|---|
account2 |
新しいアカウント管理コンソール |
Yes |
Supported |
account_api |
アカウント管理REST API |
Yes |
Supported |
admin_fine_grained_authz |
きめ細かい管理権限 |
No |
Preview |
ciba |
OpenID Connect Client Initiated Backchannel Authentication (CIBA) |
Yes |
Supported |
client_policies |
クライアント設定ポリシーの追加 |
Yes |
Supported |
client_secret_rotation |
コンフィデンシャル・クライアントのクライアント・シークレットのローテーションの有効化 |
Yes |
Preview |
par |
OAuth 2.0 Pushed Authorization Requests(PAR) |
Yes |
Supported |
declarative_user_profile |
宣言型スタイルによるユーザー・プロファイルの設定 |
No |
Preview |
docker |
Dockerレジストリーのプロトコル |
No |
Supported |
impersonation |
管理者がユーザーに成り代わる機能 |
Yes |
Supported |
openshift_integration |
OpenShiftを保護するための拡張 |
No |
Preview |
recovery_codes |
認証のリカバリーコード |
No |
Preview |
scripts |
JavaScriptを使用したカスタム認証の記述 |
No |
Preview |
step_up_authentication |
ステップアップ認証 |
Yes |
Supported |
token_exchange |
Token Exchangサービス |
No |
Preview |
upload_scripts |
スクリプトのアップロード |
No |
非推奨 |
web_authn |
W3C Web Authentication(WebAuthn) |
Yes |
Supported |
update_email |
電子メールのワークフローの更新 |
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
リレーショナル・データベースの設定
Keycloakには、H2というJavaベースのリレーショナル・データベースが組み込まれています。これは、Keycloakがデータを保存するために使用するデフォルトのデータベースで、単に認証サーバーをそのまま実行できるように組み込まれただけのものです。そのため、プロダクション用の外部データベースに置き換えることを強くお勧めします。H2データベースは並行性の高いシチュエーションではあまり実用的ではないので、クラスター内でも使用しないでください。この章では、Keycloakをより成熟度の高いデータベースに接続する方法を説明します。
Keycloakでは、リレーショナル・データを保存するために2つの階層化技術が使用されます。最下層の技術はJDBCです。JDBCは、RDBMSへの接続に使用されるJavaAPIです。データベース・ベンダーによって提供されるデータベース・タイプ毎に、さまざまなJDBCドライバーがあります。この章では、これらのベンダー固有のドライバーのいずれかを使用するようにKeycloakを設定する方法について説明します。
データを保存するための最上層の技術は、Hibernate JPAです。これは、Javaオブジェクトをリレーショナル・データにマップするORマッピングAPIの1つです。Keycloakのデプロイメントで、Hibernateの設定に触れる必要はほとんどありませんが、そのまれなケースに遭遇した場合どうなるかを説明します。
データソースの設定については、 WildFly 23 Documentation の中のデータソース設定の章the datasource configuration chapterで詳しく説明しています。 |
データベース設定のチェックリスト
以下は、KeycloakにRDBMSを設定するために行う手順です。
-
データベース用のJDBCドライバーの検索とダウンロード
-
ドライバーのJARをモジュールにパッケージ化し、このモジュールをサーバーにインストール
-
サーバーの設定プロファイルでJDBCドライバーを宣言
-
データベースのJDBCドライバーを使用するようにデータソース設定を変更
-
データベースへの接続パラメーターを定義するようにデータソース設定を変更
この章では、すべてのサンプルにおいてPostgreSQLを使用します。他のデータベースも同じ手順でインストールできます。
JDBCドライバーのパッケージ化
RDBMS用のJDBCドライバーのJARを検索してダウンロードします。このドライバーを使用する前に、モジュールにパッケージ化してサーバーにインストールする必要があります。モジュールによって、KeycloakのクラスパスにロードされるJAR、およびこれらのJARが他のモジュールに持つ依存関係が定義されます。
-
Keycloak配布ファイルの …/modules/ ディレクトリー内に、モジュールの定義を格納するディレクトリー構造を作成してください。
ディレクトリー構造の名前には、JDBCドライバーのJavaパッケージ名を使うのが一般的です。PostgreSQLの場合は、 org/postgresql/main というディレクトリーを作成します。
-
データベース・ドライバーのJARをこのディレクトリーにコピーし、その中に空の module.xml ファイルを作成します。
モジュール・ディレクトリー -
module.xml ファイルを開き、以下のようなXMLを作成します。
モジュールXML<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.3" name="org.postgresql"> <resources> <resource-root path="postgresql-VERSION.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
-
モジュール名は、モジュールのディレクトリー構造と一致していなければなりません。たとえば、 org/postgresql は
org.postgresql
に対応します。 -
resource-root path
属性は、ドライバーのJARファイル名を指定します。 -
残りの部分は、JDBCドライバーのJARが持っている通常の依存関係です。
-
JDBCドライバーの宣言とロード
JDBCをデプロイメント・プロファイルに宣言し、サーバー起動時にロードして利用できるようにします。
JDBCドライバーをパッケージ化しました。
-
デプロイメント・モードに応じて、これらのファイルのいずれかを編集し、JDBCドライバーを宣言します。
-
スタンドアローン・モードでは、 …/standalone/configuration/standalone.xml を編集します。
-
スタンドアローン・クラスタリング・モードの場合は、 …/standalone/configuration/standalone-ha.xml を編集してください。
-
ドメインモードの場合は、 …/domain/configuration/domain.xml を編集します。
ドメインモードでは、使用しているプロファイル(
auth-server-standalone
またはauth-server-clustered
のいずれか)を編集することを確認してください。
-
-
プロファイル内で、
datasources
サブシステム内のdrivers
XMLブロックを検索します。H2 JDBCドライバーの定義済みのドライバーが宣言されているはずです。ここでは、外部データベースのJDBCドライバーを宣言します。
JDBCドライバー<subsystem xmlns="urn:jboss:domain:datasources:6.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
を付けます。 -
module
属性を指定します。この属性は、ドライバーJAR用に以前作成したmodule
パッケージを指します。 -
ドライバーのJavaクラスを指定します。
ここでは、本章の前半で定義したモジュールのサンプルに含まれるPostgreSQLドライバーをインストールする例を紹介します。
JDBCドライバーの宣言<subsystem xmlns="urn:jboss:domain:datasources:6.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>
-
Keycloakデータソースの変更
Keycloakが新しい外部データベースに接続するために使用する既存のデータソース設定を変更します。これは、JDBCドライバーを登録したのと同じ設定ファイルとXMLブロック内で行います。サンプルとして、新しいデータベースへの接続を設定すると以下のとおりになります。
<subsystem xmlns="urn:jboss:domain:datasources:6.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>
-
JDBCドライバーはすでに宣言しています。
-
KeycloakDS
のdatasource
定義を検索します。まず
connection-url
を変更する必要があります。この接続URL値の形式は、ベンダーのJDBC実装のドキュメントで指定されています。 -
次に、使用する
driver
を定義します。これは、この章の前のセクションで宣言したJDBCドライバーの論理名になります。
トランザクションを実行するたびにデータベースへの新しい接続を開くのは処理コストがかかります。これを補うために、データソース実装は開いた接続のプールを維持します。
max-pool-size
によって、プールする接続の最大数が指定されます。システムの負荷に応じて、この値を変更することができます。 -
データベースへの接続に必要なデータベースのユーザー名とパスワードを定義します。このステップは少なくともPostgreSQLでは必要です。この例では、これらのクレデンシャルが平文で表示されていることが気になるかもしれません。これらのクレデンシャルを難読化する方法がありますが、その方法はこのガイドの範囲外です。
データソース機能について、詳しくは WildFly 23 Documentation 内のthe datasource configuration chapterを参照してください。 |
データベース設定
配布物内の 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 23 Development Guideで説明します。 |
データベースのユニコードに関する考慮事項
Keycloakのデータベース・スキーマは、以下の特別なフィールドにだけユニコード文字列の使用を許可します。
-
レルム:表示名、HTML表示名、ローカライズテキスト(キーと値)
-
フェデレーション・プロバイダー:表示名
-
ユーザー:ユーザー名、氏名、属性名、値
-
グループ:名前、属性名、値
-
ロール:名前
-
オブジェクトの説明
上記以外の場合は、8ビットのデータベース・エンコーディングに含まれる文字に制限されます。ただし、データベース・システムによっては、ユニコード文字のUTF-8エンコーディングを有効にし、すべてのテキストフィールド内で完全なユニコード文字セットを使用することができます。これは8ビットエンコーディングの場合よりも文字列の最大長を短くすることによって相殺されます。
データベースによっては、ユニコード文字を処理できるようにデータベースとJDBCドライバーの両方、またはいずれかに特別な設定をする必要があります。以下のデータベースの設定を確認してください。データベースがここにリストされている場合、データベースとJDBCドライバーの両方のレベルでUTF-8エンコーディングが適切に処理されていれば、正常に動きます。この点には注意してください。
技術的には、すべてのフィールド内のユニコード・サポートの重要な基準は、データベースによって VARCHAR
フィールドと CHAR
フィールドにユニコード文字セットが設定できるかどうかになります。設定できる場合は、通常はフィールド長を犠牲にすることで、ユニコードは妥当となります。 NVARCHAR
フィールドと NCHAR
フィールド内のユニコードしかサポートされていない場合は、Keycloakスキーマは VARCHAR
フィールドと CHAR
フィールドを広範囲にわたって使用するため、すべてのテキストフィールドのユニコード・サポートはほとんどありません。
Oracleデータベース
VARCHAR
フィールドと CHAR
フィールド内でユニコード・サポートを使用してデータベースを作成した場合は、ユニコード文字は適切に処理されます(例: AL32UTF8
文字セットがデータベース文字セットとして使用された場合)。JDBCドライバーに特別な設定は必要ありません。
データベース文字セットがユニコードではない場合、ユニコード文字を特別なフィールド内で使用するために、JDBCドライバーを設定して接続プロパティー oracle.jdbc.defaultNChar
を true
に設定する必要があります。厳密には必須ではないのですが、 oracle.jdbc.convertNcharLiterals
接続プロパティーも true
にしておいた方が賢明です。これらのプロパティーは、システム・プロパティーまたは接続プロパティーとして設定することができます。しかし oracle.jdbc.defaultNChar
の設定はパフォーマンスに悪影響を与える可能性がありますので、この点は注意してください。詳しくは、Oracle JDBCドライバーの設定ドキュメントを参照してください。
MySQLデータベース
CREATE DATABASE
コマンドで、 VARCHAR
と CHAR
のフィールド内のユニコード・サポートを使用してデータベースが作成される場合は、ユニコード文字は適切に処理されます(例:MySQL 5.5でデフォルトのデータベース文字セットとして utf8
文字セットを使用する場合。 utf8
文字セットに求められるさまざまなストレージ要件により、 utf8mb4
文字セットは動作しませんので注意してください [5] )。この場合、バイト数ではなく文字数に合わせて列が作成されるため、通常のフィールドには長さ制限は適用されないことに注意が必要です。データベースのデフォルト文字セットでユニコードの保存が許可されていない場合、特別なフィールドでのみユニコード値の保存が許可されることになります。
JDBCドライバー設定については、JDBC接続設定に接続プロパティー characterEncoding=UTF-8
を追加する必要があります。
PostgreSQLデータベース
データベース文字セットが UTF8
である場合、ユニコードはサポートされます。この場合、ユニコード文字はどのフィールドでも使用することができますが、通常フィールドではフィールド長は短縮されません。JDBCドライバーの特別な設定は必要ありません。
PostgreSQL Databaseの文字セットは作成時に決定されます。PostgreSQLクラスターのデフォルトの文字セットは以下のSQLコマンドで特定できます。
show server_encoding;
デフォルトの文字セットがUTF-8でない場合は、次のように文字セットとしてUTF-8を使用してデータベースを作成することができます。
create database keycloak with encoding 'UTF8';
パブリックホスト名の使用
Keycloakは、パブリックホスト名をさまざまな用途に使用します。たとえば、トークン発行者のフィールドやパスワードリセットの電子メールで送信されたURLなどです。
Hostname SPIは、リクエストのホスト名を設定する方法を提供します。デフォルト・プロバイダーでは、フロントエンドのリクエストに固定のURLを設定でき、バックエンドのリクエストはリクエストURIに基づくことができます。ビルトイン・プロバイダーが必要な機能を提供しない場合、独自のプロバイダーを開発することもできます。
デフォルト・プロバイダー
デフォルトのHostnameプロバイダーは、設定済みの frontendUrl
をフロントエンド・リクエスト(ユーザー・エージェントからのリクエスト)をベースURLとして使用し、リクエストURLをバックエンド・リクエスト(クライアントからの直接リクエスト)のベースとして使用します。
フロントエンド・リクエストは、Keycloakサーバーと同じコンテキストパスを持つ必要はありません。これは、たとえば https://auth.example.org
または https://example.org/keycloak
でKeycloakを公開できる一方で、内部的にはURLが https://10.0.0.10:8080/auth
である可能性があることを意味します。
これにより、ユーザー・エージェント(ブラウザー)がパブリック・ドメイン名を介してKeycloakにリクエストを送信し、内部クライアントが内部ドメイン名またはIPアドレスを使用できるようになります。
これは、たとえば、 authorization_endpoint
がフロントエンドURLを使用し、 token_endpoint
がバックエンドURLを使用するOpenID Connect Discoveryエンドポイントに反映されます。ここでの注意点は、たとえば、パブリック・クライアントはパブリック・エンドポイントを介してKeycloakにアクセスし、その結果、 authorization_endpoint
と token_endpoint
のベースが同じになるということです。
KeycloakのfrontendUrlを設定するには、追加の -Dkeycloak.frontendUrl=https://auth.example.org
を起動時に渡すか、 standalone.xml
で設定します。以下の例を参照してください。
<spi name="hostname">
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="frontendUrl" value="https://auth.example.com"/>
<property name="forceBackendUrlToFrontendUrl" value="false"/>
</properties>
</provider>
</spi>
jboss-cliで frontendUrl
を更新するには、次のコマンドを使用します。
/subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.frontendUrl,value="https://auth.example.com")
すべてのリクエストがパブリック・ドメイン名を通過するようにしたい場合は、 forceBackendUrlToFrontendUrl
を true
に設定することで、バックエンド・リクエストにもフロントエンドURLを使用させることができます。
個々のレルムのデフォルトのフロントエンドURLをオーバーライドすることもできます。これは管理コンソールで実施できます。
パブリック・ドメインで管理エンドポイントとコンソールを公開したくない場合は、プロパティー adminUrl
を使用して、管理コンソールの固定URLを設定します。これは frontendUrl
とは異なります。また、外部から /auth/admin
へのアクセスをブロックする必要があります。その方法の詳細については、Server Administration Guideを参照してください。
カスタム・プロバイダー
カスタムのホスト名プロバイダーを開発するには、 org.keycloak.urls.HostnameProviderFactory
と org.keycloak.urls.HostnameProvider
を実装する必要があります。
カスタム・プロバイダーの開発方法の詳細については、 Server Developer Guide のサービス・プロバイダー・インターフェイスのセクションの指示に従ってください。
ネットワークの設定
デフォルトでインストールされているKeycloakには、いくつかのネットワーク上の制限があります。たとえば、すべてのネットワーク・エンドポイントは localhost
にバインドされるので、認証サーバーは実際には1つのローカルマシンでしか使用できません。HTTPベースの接続では、80や443といったデフォルトのポートは使用しません。HTTPS/SSLは最初から設定されておらず、設定しなければKeycloakには多くのセキュリティー上の脆弱性があります。最後に、Keycloakはしばしば外部のサーバーと安全なSSLやHTTPS接続を行う必要があるため、エンドポイントが正しく検証されるようにトラスト・ストアを設定する必要があります。本章では、これらすべてについて説明します。
バインドアドレス
デフォルトでは、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 23 Documentation 内の network interface を参照してください。
|
ソケット・ポート・バインディング
各ソケット用に開けられたポートには、コマンドラインまたは設定内で上書きできるデフォルト値があらかじめ定義されています。この設定方法を学ぶために、スタンドアローン・モードで実行していると仮定し、 …/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 23 Documentation 内の socket binding group を参照してください。
|
HTTPS/SSLの設定
Keycloakは、デフォルトではSSL/HTTPSを処理するように設定されていません。Keycloakサーバー上、またはKeycloakサーバーのフロントにあるリバース・プロキシー上のいずれかでSSLを有効にすることを強くお勧めします。 |
このデフォルトの動作は、各KeycloakレルムのSSL/HTTPSモードによって定義されています。これについて詳しくはServer Administration Guideで説明しますが、これらのモードの関連事項と簡単な概要についてはここで示します。
- external requests
-
SSLが無効でも、
localhost
、127.0.0.1
、10.x.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管理コンソール内で設定できます。
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-----
-
このCAリクエストを認証局(CA)に送信します。
CAは署名入りの証明書を発行し、あなたに送ります。
-
CAのルート証明書を入手してインポートする。
CAから証明書をダウンロードして(つまり、root.crt)、以下のようにインポートすることができます。
$ keytool -import -keystore keycloak.jks -file root.crt -alias root
-
新しいCAが生成した証明書をキーストアにインポートします。
$ 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
パラメーターを設定から削除してください(operating modeを参照してください)。 -
次のようにCLIを使用して、キーストアを設定します。
$ /subsystem=elytron/key-store=httpsKS:add(relative-to=jboss.server.config.dir,path=keycloak.jks,credential-reference={clear-text=secret},type=JKS) $ /subsystem=elytron/key-manager=httpsKM:add(key-store=httpsKS,credential-reference={clear-text=secret}) $ /subsystem=elytron/server-ssl-context=httpsSSC:add(key-manager=httpsKM,protocols=[\"TLSv1.3\"])
ドメインモードを使用している場合は、コマンドはすべてのホストで
/host=<host_name>/
プレフィックスを使用して実行します(すべてのホストでsecurity-realm
を作成するために)。次の例のように、各ホスト分繰り返します。$ /host=<host_name>/subsystem=elytron/key-store=httpsKS:add(relative-to=jboss.server.config.dir,path=keycloak.jks,credential-reference={clear-text=secret},type=JKS)
-
作成した
server-ssl-context
を使用するようにhttps-listener
を変更します。$ /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context, value=httpsSSC)
ドメインモードを使用している場合は、使用されているプロファイルをコマンドの先頭に
/profile=<profile_name>/
のように付けます。結果として得られる要素
server name="default-server"
は、これはsubsystem xmlns="urn:jboss:domain:undertow:12.0"
の子要素であり、次のような内容を含みます。<subsystem xmlns="urn:jboss:domain:undertow:12.0"> <buffer-cache name="default"/> <server name="default-server"> <https-listener name="https" socket-binding="https" ssl-context="httpsSSC"/> ... </subsystem>
TLSの設定に関する詳細については、 WildFlyドキュメント を参照してください。
外部への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
-
クライアントキー用のパスワードです。
client-keystore
が設定されている場合、これは REQUIRED です。 - proxy-mappings
-
送信するHTTPリクエストのプロキシー設定を示します。詳細については、送信HTTPリクエストのプロキシー・マッピングのセクションを参照してください。
- disable-trust-manager
-
外部へのリクエストがHTTPSを必要とし、この設定オプションを
true
に設定する場合は、トラストストアを指定する必要はありません。この設定は、SSL証明書の検証を無効とするため、開発時にのみ使用すべきで、プロダクション環境では 決して使用してはいけません 。これは OPTIONAL です。デフォルトはfalse
です。
送信HTTPリクエストのプロキシー・マッピング
Keycloakによって送信された送信HTTPリクエストは、プロキシー・マッピングのカンマで区切られたリストに基づいて、オプションでプロキシー・サーバーを使用できます。プロキシー・マッピングは、正規表現ベースのホスト名パターンと hostnamePattern;proxyUri
形式のproxy-uriの組み合わせを示します。例:
.*\.(google|googleapis)\.com;http://www-proxy.acme.com:8080
送信するHTTPリクエストのプロキシーを判別するために、ターゲットホスト名が、設定されたホスト名パターンと照合されます。最初に一致するパターンで、使用するproxy-uriが決定します。指定されたホスト名と一致する設定済みのパターンが無い場合、プロキシーは使用されません。
プロキシー・サーバーが認証を必要とする場合、プロキシーユーザのクレデンシャルを username:password@
という形式で含めてください。たとえば、以下のようになります。
.*\.(google|googleapis)\.com;http://user01:pas2w0rd@www-proxy.acme.com:8080
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>
標準的な環境変数の使用
代わりに,標準的な環境変数を使ってプロキシー・マッピングを設定することも可能です( HTTP_PROXY
、 HTTPS_PROXY
、 NO_PROXY
)。
変数 HTTP_PROXY
と HTTPS_PROXY
は、すべての送信HTTPリクエストに使用されるべきプロキシーサーバーを表しています。 Keycloakは、両者の間に違いはありません。両方が指定された場合は、プロキシーサーバーが実際に使用するスキームに関わらず、HTTPS_PROXY
が優先されます。
NO_PROXY
変数は、プロキシーを使用してはいけないホスト名のリストをカンマ区切りで定義するのに使われます。ホスト名が指定された場合、そのすべてのプレフィックス(サブドメイン)もプロキシーの使用から除外されます。
次のような例があります。
HTTPS_PROXY=https://www-proxy.acme.com:8080
NO_PROXY=google.com,login.facebook.com
この例では、たとえば login.google.com
、 google.com
、 auth.login.facebook.com
へのリクエストを除き、すべての送信HTTPリクエストが https://www-proxy.acme.com:8080
プロキシー・サーバーを使用します。ただし、たとえば groups.facebook.com
などのリクエストはプロキシーを経由します。
環境変数は、小文字でも大文字でもOKです。小文字の方が優先されます。たとえば、 HTTP_PROXY と http_proxy の両方が定義されている場合、 http_proxy が使用されます。
|
サブシステム設定を使用してプロキシー・マッピングを定義する場合 (上記のとおり)、環境変数はKeycloakでは考慮されません。このシナリオは、たとえば HTTP_PROXY
環境変数が定義されているにもかかわらず、プロキシー・サーバーを使用しない場合に適用されます。これを行うには、以下のように一般的なプロキシーのないルートを指定します。
<spi name="connectionsHttpClient">
<provider name="default" enabled="true">
<properties>
<property name="proxy-mappings" value=".*;NO_PROXY"/>
</properties>
</provider>
</spi>
発信するHTTPSリクエスト truststore
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"/>
</properties>
</provider>
</spi>
設定可能なオプションは以下のとおりです。
- file
-
Javaキーストア・ファイルへのパスです。HTTPSリクエストでは、通信を行うサーバーのホストを検証する必要があります。これはトラストストアの役割です。キーストアには、1つ以上の信頼できるホスト証明書または認証局が含まれています。このトラストストア・ファイルには、セキュリティー保護されたホストのパブリック証明書のみを含めるべきです。 これらのプロパティーのいずれかが定義されている場合、これは REQUIRED です。
- password
-
キーストアのパスワード。これらのプロパティーのいずれかが定義されている場合、これは REQUIRED です。
- hostname-verification-policy
-
デフォルトでは
WILDCARD
です。HTTPSリクエストを行うために、サーバー証明書のホスト名を検証します。ANY
はホスト名が検証されないことを意味します。WILDCARD
によって、サブドメイン名にワイルドカード(つまり *.foo.com)が使用できるようになります。STRICT
の場合、CNはホスト名と正確に一致する必要があります。
Keycloakをクラスターで実行させるための設定
Keycloakをクラスターで実行するように設定するには、以下の操作を行います。
-
ロードバランサーの設定
-
IPマルチキャストをサポートするプライベート・ネットワークの提供
動作モードの選択と共有データベースの設定については、本ガイドの前半で説明しました。本章では、ロードバランサーの設定、プライベート・ネットワークの提供、クラスター内のホストの起動について説明します。
IPマルチキャストなしでもKeycloakをクラスター構成にすることは可能ですが、このトピックについてはこのガイドの範囲を超えています。詳しくは、 WildFly 23 Documentation のJGroupsを参照してください。 |
推奨ネットワーク・アーキテクチャー
Keycloakをデプロイするための推奨ネットワーク・アーキテクチャーは、パブリックIPアドレスを持つHTTP/HTTPSロードバランサーを配置し、プライベート・ネットワーク上のKeycloakサーバーへのリクエストをルーティングさせます。これにより、クラスタリング接続はすべて分離され、サーバーを保護する優れた手段が提供されます。
デフォルトでは、許可されていないノードがクラスターに加わり、マルチキャスト・メッセージをブロードキャストするのを防ぐものは何もありません。このため、クラスター・ノードはプライベート・ネットワーク内に置かれ、ファイアウォールによって外部の攻撃から保護される必要があります。 |
クラスタリングの例
Keycloakには、ドメインモードでそのまま利用できるクラスタリングのデモが付属しています。詳しくはクラスター構成ドメインのサンプルの章を参照してください。
ロードバランサーまたはプロキシーの設定
このセクションでは、クラスター構成のKeycloakの前にリバース・プロキシーまたはロードバランサーを配置するにあたって、設定が必要な項目について説明します。また、組み込みのロードバランサーの設定についても説明します。これはクラスター構成ドメインのサンプルでも確認できます。
次の図は、ロードバランサーの使用方法を示しています。この例では、ロードバランサーは、3つのクライアントと3つのKeycloakサーバーのクラスター間のリバースプロキシーとして機能します。
クライアント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-Forwarded-For
ヘッダーがプロキシーによって設定されているか、特に注意して確認してください。プロキシーが正しく設定されていない場合、不正な クライアントがこのヘッダーを自身で設定して、クライアントが実際とは異なるIPアドレスから接続しているとKeycloakに認識させることができてしまいます。IPアドレスのブラックリストまたはホワイトリストを作成している場合、この設定は非常に重要です。
プロキシーの他にも、いくつかKeycloak側で設定する必要があります。プロキシーがHTTPプロトコル経由でリクエストを転送している場合、クライアントのIPアドレスをネットワーク・パケットからではなく X-Forwarded-For
ヘッダーから取得するように、Keycloakを設定する必要があります。これを行うには、プロファイル設定ファイル(動作モードに応じて standalone.xml 、 standalone-ha.xml または domain.xml )を開き、 urn:jboss:domain:undertow:12.0
XMLブロックを検索します。
X-Forwarded-For
HTTP設定<subsystem xmlns="urn:jboss:domain:undertow:12.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:12.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>
リバース・プロキシーでのHTTPS/SSLの有効化
リバース・プロキシーがSSL用にポート8443を使用しない場合、HTTPSトラフィックのどのポートをリダイレクトするか設定する必要があります。
<subsystem xmlns="urn:jboss:domain:undertow:12.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>
設定内容の確認
リバース・プロキシーやロードバランサーの設定を確認することができます。
-
リバース・プロキシー経由でパス
/auth/realms/master/.well-known/openid-configuration
を開きます。たとえば、リバース・プロキシーのアドレスが
https://acme.com/
であれば、https://acme.com/auth/realms/master/.well-known/openid-configuration
を開きます。そうすると、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アドレスであることを確認してください。
組み込みロードバランサーの使用
このセクションでは、クラスター構成ドメインのサンプルで説明している組み込みのロードバランサーの設定方法について説明します。
クラスター構成ドメインのサンプルは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
の定義を追加します。domain.xmlのreverse-proxy設定<subsystem xmlns="urn:jboss:domain:undertow:12.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
を追加します。この新しいバインディングは、新しいホストのホストとポートを指す必要があります。
domain.xmlの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.address.management
の値はホストスレーブのIPアドレスに関係します。 jboss.domain.master.address
の値は、マスターホストの管理アドレスであるドメイン・コントローラーのIPアドレスとする必要があります。
-
その他のソフトウェア・ベースのロードバランサーの使用方法については、 WildFly 23 Documentation 内のロードバランシングのセクションを参照してください。
スティッキー・セッション
典型的なクラスター構成は、ロードバランサー(リバース・プロキシー)とプライベート・ネットワーク上の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のドキュメントを参照してください。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サーバーのホスト名を隠す場合などに、別の経路名を使用できます。
経路の追加を無効にする
いくつかのロードバランサーは、バックエンドの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>
マルチキャストネットワークの設定
デフォルトのクラスタリング・サポートには、IPマルチキャストが必要です。マルチキャストは、ネットワークのブロードキャスト・プロトコルです。このプロトコルは、起動時にクラスターの検出と参加に使用されます。また、Keycloakが使用する分散キャッシュのレプリケーションや無効化のためのメッセージをブロードキャストするためにも使用されます。
Keycloak のクラスタリング・サブシステムはJGroupsスタックで動作しています。クラスタリング用のバインドアドレスは、デフォルトIPアドレスとして127.0.0.1を持つプライベート・ネットワーク・インターフェースにバインドされています。
-
Bind Addressの章で説明した 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 23 Documentation 内の JGroups を参照してください。
クラスター通信のセキュリティー保護
クラスター・ノードがプライベート・ネットワークで隔離されている場合は、クラスターに参加したり、クラスター内の通信を表示したりするために、プライベート・ネットワークへのアクセスが必要です。また、クラスター通信の認証と暗号化を有効にすることもできます。プライベート・ネットワークが安全である限り、認証と暗号化を有効にする必要はありません。どちらの場合も、Keycloakはクラスター上で機密情報を送信しません。
クラスタリング通信の認証と暗号化を有効にする場合は、 WildFly documentation にある’High Availability Guide’を参照してください。
シリアライズされたクラスターの起動
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>
クラスターの起動
クラスター内での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
システム・プロパティーです(スティッキー・セッションのセクションで説明しています)。
トラブルシューティング
-
クラスターを実行すると、両方のクラスターノードのログに以下のようなメッセージが表示されます。
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 23 Documentation のJGroupsを参照してください。
-
フェイルオーバーのサポート(高可用性)、エビクション、有効期限およびキャッシュ・チューニングに関心がある場合は、サーバー・キャッシュ設定を参照してください。
サーバー・キャッシュ設定
Keycloakには、2つのタイプのキャッシュがあります。1つ目のキャッシュは、データベースの前に置かれていて、DBの負荷を減らし、データをメモリーに保持することで全体の応答時間を短縮します。レルム、クライアント、ロール、およびユーザー・メタデータは、このタイプのキャッシュに保持されます。このキャッシュはローカル・キャッシュです。クラスターにより多くのKeycloakサーバーがある場合でも、ローカル・キャッシュはレプリケーションを使用しません。その代わり、ローカル・キャッシュはローカルにのみコピーを保持し、エントリーが更新された場合は無効化メッセージが残りのクラスターに送られてエントリーは追い出されます。これとは別にレプリケーションされるキャッシュ work
があります。これは、どのエントリーがローカル・キャッシュから取り除かれるかについて、クラスター全体に無効化メッセージを送信するタスクになります。これによって、ネットワーク・トラフィックが大幅に減少し、効率化され、機密なメタデータのネットワーク経由での送信が回避されます。
2つ目のキャッシュは、ユーザー・セッション、オフライン・トークン、ログイン・エラーの履歴保持の管理を担当し、サーバーがパスワード・フィッシングやその他の攻撃を検出できるようにします。これらのキャッシュ内のデータは一時的で、メモリーにのみ保持されるものですが、クラスター全体にレプリケーションされる可能性があります。
この章では、クラスター構成と非クラスター構成の両方のためのキャッシュ用設定オプションについて説明します。
これらのキャッシュのより高度な設定については、 WildFly 23 Documentation のInfinispanのセクションを参照してください。 |
退避と有効期限
Keycloakには、さまざまなキャッシュの設定があります。その一つにレルムキャッシュというものがあり、セキュリティー保護されたアプリケーション、一般的なセキュリティー・データおよび設定オプションに関する情報を保持しています。また、ユーザー・メタデータを含むユーザー・キャッシュがあります。このキャッシュのデフォルト値は最大10000エントリーで、最近最も使われなかったものを退避する戦略が使用されます。また、これらのキャッシュはそれぞれ、クラスター構成内での退避を制御するオブジェクト・リビジョン・キャッシュにも関連付けられています。このキャッシュは暗黙的に作成され、設定されたサイズの2倍のサイズがあります。認可データを保持する authorization
キャッシュについても同様です。 keys
キャッシュは外部キーに関するデータを保持し、専用のリビジョン・キャッシュを保持する必要はありません。それはむしろ明示的に expiration
が宣言されているので、キーは定期的に期限切れとなり、外部のクライアントやアイデンティティー・プロバイダーから定期的にダウンロードされます。
これらのキャッシュの退避ポリシーと最大エントリーは、動作モードに応じて standalone.xml 、 standalone-ha.xml または domain.xml 内で設定することができます。設定ファイルには、infinispanサブシステムの次のような部分があります。
<subsystem xmlns="urn:jboss:domain:infinispan:12.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
があります。デフォルトでは無制限です。ただし、このキャッシュ内のエントリーは非常に短期間であるため、このキャッシュがメモリーの問題を引き起こすことはありません。
レプリケーションとフェイルオーバー
sessions
、 authenticationSessions
、 offlineSessions
、 loginFailures
などのキャッシュがあります(詳細は退避と有効期限を参照)。クラスター化された設定を使用するときは分散キャッシュとして設定されます。エントリーはすべてのノードにひとつひとつレプリケーションされるわけではありませんが、1つ以上のノードがそのデータの所有者として選ばれます。ノードが特定のキャッシュ・エントリーの所有者ではない場合は、そのキャッシュ・エントリーを取得するためにクラスターに問い合わせをします。これがフェイルオーバーに対して何を意味するかというと、データを保持しているノードがすべてダウンした場合は、そのデータは永遠に失われてしまうということです。デフォルトでは、Keycloakが指定するデータの所有者は1つだけです。そのため、その1つのノードがダウンした場合は、そのデータは失われることになります。このことは通常、ユーザーはログアウトされ、再度ログインし直さなければならないということを意味します。
distributed-cache
の宣言で owners
属性を変更すると、データをレプリケートするノードの数を変更することができます。
<subsystem xmlns="urn:jboss:domain:infinispan:12.0">
<cache-container name="keycloak">
<distributed-cache name="sessions" owners="2"/>
...
ここで上記のとおりに変更すると、少なくとも2つのノードが1つの特定のユーザー・ログイン・セッションをレプリケーションします。
推奨される所有者数は、構成によって異なります。ノードがダウンした時にユーザーがログアウトされてもされなくても良い場合は、所有者は1つで十分であり、レプリケーションを避けることができます。 |
スティッキー・セッションでロードバランサーを使用するように環境を設定することは、一般的には賢明です。通常は、特定のリクエストが処理されるKeycloakサーバーが分散キャッシュデータの所有者であるため、ローカルでデータをルックアップできますので、パフォーマンスを向上させるために有益です。詳細はスティッキー・セッションを参照してください。 |
キャッシングの無効化
レルムキャッシュやユーザーキャッシュを無効にすることができます。
-
配布物内の
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に設定します。 -
この変更を有効にするには、サーバーを再起動してください。
Keycloak Operator
The Keycloak Operatorは、 テクノロジー・プレビュー であり、完全にはサポートされていません。 |
Openshift。このオペレーターを使用して、管理タスクを自動化するカスタムリソース(CR)を作成します。たとえば、Keycloak管理コンソールでクライアントまたはユーザーを作成する代わりに、これらのタスクを実行するカスタムリソースを作成できます。カスタムリソースは、管理タスクのパラメーターを定義するYAMLファイルです。
カスタムリソースを作成して、次のタスクを実行できます。
レルム、クライアント、ユーザーのカスタムリソースを作成したら、Keycloak管理コンソールを使用するか、 kubectl コマンドを使用してカスタムリソースとして管理できます。ただし、オペレーターは変更したカスタムリソースに対して一方向の同期を実行するため、両方の方法を使用することはできません。たとえば、レルムのカスタムリソースを変更すると、その変更が管理コンソールに表示されます。ただし、管理コンソールを使用してレルムを変更した場合、それらの変更はカスタムリソースには影響しません。
|
Keycloak Operatorのインストール でオペレーターの使用を開始します。
クラスターにKeycloak Operatorをインストールする
Keycloak Operatorをインストールするには、以下を使用できます。
Operator Lifecycle Managerを使用したインストール
Operatorは、 OpenShift または Kubernetes クラスターにインストールできます。
OpenShiftクラスターへのインストール
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
OpenShiftクラスターでこの手順を実行します。
-
OpenShift Container Platform Webコンソールを開きます。
-
左側の列で、
Operators, OperatorHub
をクリックします。 -
Keycloak Operatorを検索します。
OpenShiftのOperatorHubタブ -
Keycloakオペレーター・アイコンをクリックします。
インストール・ページが開きます。
OpenShiftのOperatorインストール・ページ -
Install
をクリックします。 -
ネームスペースを選択し、Subscribeをクリックします。
OpenShiftでのネームスペースの選択Operatorがインストールを開始します。
-
Operatorのインストールが完了すると、最初のカスタムリソースを作成する準備が整います。 Keycloak カスタムリソースを使用したインストール を参照してください。ただし、カスタムリソースを作成する前にすべてのOperatorアクティビティーの追跡を開始する場合は、 Application Monitoring Operator を参照してください。
-
OpenShiftオペレーターの詳細については、 OpenShift Operators guide を参照してください。
Kubernetesクラスターへのインストール
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
Kubernetesクラスターの場合、次の手順を実行します。
-
Install
をクリックします。 -
画面の指示に従ってください。
KubernetesのOperatorインストール・ページ
-
Operatorのインストールが完了すると、最初のカスタムリソースを作成する準備が整います。 Keycloak カスタムリソースを使用したインストール を参照してください。ただし、カスタムリソースを作成する前にすべてのOperatorアクティビティーの追跡を開始する場合は、 Application Monitoring Operator を参照してください。
-
Kubernetesのインストールの詳細については、 How to install an Operator from OperatorHub.io を参照してください。
コマンドラインからのインストール
コマンドラインからKeycloak Operatorをインストールできます。
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
次の場所からインストールするソフトウェアを入手してください。Github repo
-
必要なすべてのカスタムリソース定義をインストールします。
$ kubectl apply -f deploy/crds/
-
ネームスペース
myproject
などの新しいネームスペースを作成(または既存のネームスペースを再利用)します。$ kubectl create namespace myproject
-
Operatorのロール、ロール・バインディング、およびサービス・アカウントをデプロイします。
$ kubectl apply -f deploy/role.yaml -n myproject $ kubectl apply -f deploy/role_binding.yaml -n myproject $ kubectl apply -f deploy/service_account.yaml -n myproject
-
Operatorを配置します。
$ kubectl apply -f deploy/operator.yaml -n myproject
-
Operatorが実行されていることを確認します。
$ kubectl get deployment keycloak-operator -n myproject NAME READY UP-TO-DATE AVAILABLE AGE keycloak-operator 1/1 1 1 41s
追加のリソース-
Operatorのインストールが完了すると、最初のカスタムリソースを作成する準備が整います。 Keycloak カスタムリソースを使用したインストール を参照してください。ただし、カスタムリソースを作成する前にすべてのOperatorアクティビティーの追跡を開始する場合は、 Application Monitoring Operator を参照してください。
-
Kubernetesのインストールの詳細については、 How to install an Operator from OperatorHub.io を参照してください。
-
OpenShiftオペレーターの詳細については、 OpenShift Operators guide を参照してください。
-
プロダクション環境でのKeycloak Operatorの使用
-
プロダクション環境では、組み込みDBの使用はサポートされていません。
-
バックアップCRDは非推奨で、プロダクション環境ではサポートされていません。
-
Keycloak CRの
podDisruptionBudget
フィールドは非推奨であり、OperatorがKubernetes 1.25以降にデプロイされた場合は無視される予定です。 -
我々は、
v1alpha1
バージョンにもかかわらず、残りのCRDをプロダクション環境で使用することを完全にサポートします。このCRDのバージョンでは、破壊的な変更を行う予定はありません。
Application Monitoring Operator
Operatorを使用してKeycloakをインストールまたはコンポーネントを作成する前に、Operatorのアクティビティーを追跡するApplication Monitoring Operatorをインストールすることをお勧めします。Operatorのメトリクスを表示するには、Application Monitoring OperatorからGrafanaダッシュボードとPrometheusアラートを使用できます。たとえば、コントローラーのランタイム・リコンシリエーション・ループの数、リコンシリエーション・ループ時間、エラーなどのメトリクスを表示できます。
Keycloak OperatorとApplication Monitoring Operatorの統合に、アクションは必要ありません。クラスターにApplication Monitoring Operatorをインストールするだけです。
Application Monitoring Operatorのインストール
-
Keycloak Operatorがインストールされていること。
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
documentation を使用してApplication Monitoring Operatorをインストールします。
-
Keycloak Operatorのインストールに使用されるネームスペースに注釈を付けます。例:
kubectl label namespace <namespace> monitoring-key=middleware
-
OpenShift Webコンソールにログインします。
-
application-monitoring
ネームスペースの中のPrometheusおよびGrafanaルートを検索して、モニタリングが機能していることを確認します。OpenShift Webコンソールでのルート
Operatorメトリクスの表示
GrafanaとPrometheusはそれぞれ、Operatorアクティビティーに関するグラフィカルな情報を提供します。
-
Operatorは、次のような事前定義されたGrafanaダッシュボードをインストールします。
Grafanaダッシュボードカスタマイズを行う場合は、アップグレード中に変更が上書きされないように、Grafanaダッシュボードを複製することをお勧めします。
-
Operatorは、以下に示すように、事前定義されたPrometheusアラートのセットをインストールします。
Prometheusアラート
詳細については、 Accessing Prometheus, Alertmanager, and Grafana を参照してください。
カスタムリソースを使用したKeycloakのインストール
Operatorを使用して、Keycloakカスタムリソースを作成することにより、Keycloakのインストールを自動化できます。カスタムリソースを使用してKeycloakをインストールする場合、ここで説明し、次の図に示すコンポーネントとサービスを作成します。
-
keycloak-db-secret
- データベースのユーザー名、パスワード、外部アドレス(外部データベースに接続している場合)などのプロパティーを保存します -
credentials-<CR-Name>
- 管理コンソールにログインするための管理者ユーザー名とパスワード(<CR-Name>
はKeycloak
カスタムリソース名に基づいています) -
keycloak
- 高可用性サポートを備えたStatefulSetとして実装されるKeycloakデプロイメント仕様 -
keycloak-postgresql
- PostgreSQLデータベースのインストールを開始します -
keycloak-discovery
Service -JDBC_PING
検出を実行します -
keycloak
サービス - HTTPSを介してKeycloakに接続します(HTTPはサポートされていません) -
keycloak-postgresql
サービス - 内部と外部(使用されている場合)のデータベース・インスタンスを接続します -
keycloak
ルート - OpenShiftからKeycloak管理コンソールにアクセスするためのURL -
keycloak
Ingress - KubernetesからKeycloak管理コンソールにアクセスするためのURL
Keycloakカスタムリソース
Keycloakカスタムリソースは、インストール用のパラメーターを定義するYAMLファイルです。このファイルには3つのプロパティーが含まれています。
-
instances
- 高可用性モードで実行されているインスタンスの数を制御します。 -
externalAccess
-enabled
がTrue
の場合、OperatorはOpenShiftのルートまたはKeycloakクラスターのKubernetesのIngressを作成します。Routeに自動的に選択されたホスト名を上書きするようにhost
を設定するか、Ingressにデフォルト値のkeycloak.local
を設定できます。 -
externalDatabase
- 外部でホストされているデータベースに接続するために使用します。これについては、このガイドの 外部データベース の項で説明します。これをfalseに設定すると、組み込み式のPostgreSQLデータベースがインストールされますので、テスト目的でのみ使用してください。externalDatabase:falseは本番環境ではサポートされていないことに注意してください。
apiVersion: keycloak.org/v1alpha1
kind: Keycloak
metadata:
name: example-keycloak
labels:
app: example-keycloak
spec:
instances: 1
externalAccess:
enabled: True
YAMLファイルを更新すると、Keycloak管理コンソールに変更が表示されますが、管理コンソールで変更しても、カスタムリソースは更新されません。 |
OpenShiftでのKeycloakカスタムリソースの作成
OpenShiftでは、カスタムリソースを使用してルート(管理コンソールのURL)を作成し、(管理コンソールのユーザー名とパスワードを保持する)シークレットを見つけます。
-
このカスタムリソース用のYAMLファイルがあること。
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
ここですべてのOperatorアクティビティの追跡を開始する場合は、このカスタムリソースを作成する前に監視アプリケーションをインストールしてください。 アプリケーション監視Operator を参照してください。
-
kubectl apply -f <filename>.yaml -n <namespace>
のようにYAMLファイルを使用してルートを作成します。たとえば、$ kubectl apply -f keycloak.yaml -n keycloak keycloak.keycloak.org/example-keycloak created
OpenShiftにルートが作成されます。
-
OpenShift Webコンソールにログインします。
-
Networking
、Routes
を選択し、Keycloakを検索します。OpenShift Webコンソールのルーティング画面 -
Keycloakルートのある画面で、
Location
の下のURLをクリックします。Keycloak管理コンソールのログイン画面が表示されます。
管理コンソールのログイン画面 -
OpenShift Webコンソールで管理コンソールのユーザー名とパスワードを見つけます。
Workloads
でSecrets
をクリックし、Keycloakを検索します。OpenShift Webコンソールのシークレット画面 -
ユーザー名とパスワードを管理コンソールのログイン画面に入力します。
管理コンソールのログイン画面これで、KeycloakカスタムリソースによってインストールされたKeycloakのインスタンスにログインしました。レルム、クライアント、およびユーザー用のカスタムリソースを作成する準備が整いました。
Keycloak masterレルム -
カスタムリソースのステータスを確認します。
$ kubectl describe keycloak <CR-name>
KubernetesでKeycloakカスタムリソースを作成する
Kubernetesでは、カスタムリソースを使用して、管理コンソールのIPアドレスであるingressを作成し、そのコンソールのユーザー名とパスワードを保持するシークレットを見つけます。
-
このカスタムリソース用のYAMLファイルがあること。
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
kubectl apply -f <filename>.yaml -n <namespace>
のようにYAMLファイルを使用してingressを作成します。たとえば、$ kubectl apply -f keycloak.yaml -n keycloak keycloak.keycloak.org/example-keycloak created
-
kubectl get ingress -n <CR-name>
のようにingressを見つけます。たとえば$ kubectl get ingress -n example-keycloak NAME HOSTS ADDRESS PORTS AGE keycloak keycloak.redhat.com 192.0.2.0 80 3m
-
ADDRESS(ingress)をコピーしてWebブラウザーに貼り付けます。
Keycloak管理コンソールのログイン画面が表示されます。
管理コンソールのログイン画面 -
ユーザー名とパスワードを見つけます。
$ kubectl get secret credential-<CR-Name> -o go-template='{{range $k,$v := .data}}{{printf "%s: " $k}}{{if not $v}}{{$v}}{{else}}{{$v | base64decode}}{{end}}{{"\n"}}{{end}}'
-
ユーザー名とパスワードを管理コンソールのログイン画面に入力します。
管理コンソールのログイン画面これで、KeycloakカスタムリソースによってインストールされたKeycloakのインスタンスにログインしました。レルム、クライアント、およびユーザー用のカスタムリソースを作成する準備が整いました。
管理コンソールmasterレルム
Operatorがカスタムリソースを処理したら、次のコマンドでステータスを表示します。
$ kubectl describe keycloak <CR-name>
Name: example-keycloak
Namespace: keycloak
Labels: app=example-keycloak
Annotations: <none>
API Version: keycloak.org/v1alpha1
Kind: Keycloak
Spec:
External Access:
Enabled: true
Instances: 1
Status:
Credential Secret: credential-example-keycloak
Internal URL: https://<External URL to the deployed instance>
Message:
Phase: reconciling
Ready: true
Secondary Resources:
Deployment:
keycloak-postgresql
Persistent Volume Claim:
keycloak-postgresql-claim
Prometheus Rule:
keycloak
Route:
keycloak
Secret:
credential-example-keycloak
keycloak-db-secret
Service:
keycloak-postgresql
keycloak
keycloak-discovery
Service Monitor:
keycloak
Stateful Set:
keycloak
Version:
Events:
-
Keycloakのインストールが完了すると、 レルム・カスタムリソースを作成 する準備が整います。
-
外部データベースは、サポートされているオプションで、Keycloakのカスタムリソースで有効にする必要があります。テスト時のみこのオプションを無効にして、プロダクション環境に切り替えたときに有効にすることができます。Connecting to an external databaseを参照してください。
レルム・カスタム・リソースの作成
Operatorを使用して、カスタムリソースで定義されているようにKeycloakにレルムを作成できます。レルム・カスタム・リソースのプロパティーをYAMLファイルで定義します。
YAMLファイルの作成または削除により、レルムの作成または削除のみ可能で、Keycloak管理コンソールで確認できます。ただし、レルム作成後の管理コンソールへの変更を、CRに更新として戻すことはサポートされません。 |
Realm
カスタム・リソースのYAMLファイルの例apiVersion: keycloak.org/v1alpha1
kind: KeycloakRealm
metadata:
name: test
labels:
app: example-keycloak
spec:
realm:
id: "basic"
realm: "basic"
enabled: True
displayName: "Basic Realm"
instanceSelector:
matchLabels:
app: example-keycloak
-
このカスタムリソース用のYAMLファイルがあること。
-
YAMLファイルでは、
instanceSelector
の下のapp
はKeycloakカスタムリソースのラベルと一致します。これらの値を一致させることで、Keycloakの正しいインスタンスにレルムを確実に作成できます。 -
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
作成したYAMLファイルで
kubectl apply -f <realm-name>.yaml
のコマンドを使用します。たとえば、$ kubectl apply -f initial_realm.yaml keycloak.keycloak.org/test created
-
Keycloakの関連インスタンスの管理コンソールにログインします。
-
Select Realmをクリックして、作成したレルムを見つけます。
新規レルムが開きます。
管理コンソールmasterレルム
Operatorがカスタムリソースを処理したら、次のコマンドでステータスを表示します。
$ kubectl describe keycloak <CR-name>
Name: example-keycloakrealm
Namespace: keycloak
Labels: app=example-keycloak
Annotations: <none>
API Version: keycloak.org/v1alpha1
Kind: KeycloakRealm
Metadata:
Creation Timestamp: 2019-12-03T09:46:02Z
Finalizers:
realm.cleanup
Generation: 1
Resource Version: 804596
Self Link: /apis/keycloak.org/v1alpha1/namespaces/keycloak/keycloakrealms/example-keycloakrealm
UID: b7b2f883-15b1-11ea-91e6-02cb885627a6
Spec:
Instance Selector:
Match Labels:
App: example-keycloak
Realm:
Display Name: Basic Realm
Enabled: true
Id: basic
Realm: basic
Status:
Login URL:
Message:
Phase: reconciling
Ready: true
Events: <none>
追加のリソース
-
レルムの作成が完了すると、 クライアント・カスタム・リソースを作成する 準備が整います。
クライアント・カスタム・リソースの作成
Operatorを使用して、カスタムリソースで定義されているようにKeycloakにクライアントを作成できます。レルムのプロパティーをYAMLファイルで定義します。
YAMLファイルを更新すると、Keycloak管理コンソールに変更が表示されますが、管理コンソールで変更しても、カスタムリソースは更新されません。 |
apiVersion: keycloak.org/v1alpha1
kind: KeycloakClient
metadata:
name: example-client
labels:
app: app=example-keycloak
spec:
realmSelector:
matchLabels:
app: <matching labels for KeycloakRealm custom resource>
client:
# auto-generated if not supplied
#id: 123
clientId: client-secret
secret: client-secret
# ...
# other properties of Keycloak Client
-
このカスタムリソース用のYAMLファイルがあること。
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
作成したYAMLファイルで
kubectl apply -f <client-name>.yaml
のコマンドを使用します。たとえば、$ kubectl apply -f initial_client.yaml keycloak.keycloak.org/example-client created
-
Keycloakの関連インスタンスのKeycloak管理コンソールにログインします。
-
Clientsをクリックします。
新しいクライアントがクライアントの一覧に表示されます。
クライアントが作成された後、オペレーターは keycloak-client-secret-<custom resource name>
の命名パターンを使用して Client ID
とクライアントのシークレットを含むシークレットを作成します。次に例を示します。
apiVersion: v1
data:
CLIENT_ID: <base64 encoded Client ID>
CLIENT_SECRET: <base64 encoded Client Secret>
kind: Secret
Operatorがカスタムリソースを処理したら、次のコマンドでステータスを表示します。
$ kubectl describe keycloak <CR-name>
Name: client-secret
Namespace: keycloak
Labels: app=example-keycloak
API Version: keycloak.org/v1alpha1
Kind: KeycloakClient
Spec:
Client:
Client Authenticator Type: client-secret
Client Id: client-secret
Id: keycloak-client-secret
Realm Selector:
Match Labels:
App: keycloak
Status:
Message:
Phase: reconciling
Ready: true
Secondary Resources:
Secret:
keycloak-client-secret-client-secret
Events: <none>
-
クライアントの作成が完了すると、 ユーザーカスタムリソースの作成 の準備が整います。
ユーザー・カスタム・リソースの作成
Operatorを使用して、カスタムリソースで定義されているようにKeycloakにユーザーを作成できます。ユーザー・カスタム・リソースのプロパティーをYAMLファイルで定義します。
YAMLファイルでパスワード以外のプロパティーを更新できます。変更はKeycloak管理コンソールに表示されますが、管理コンソールを変更してもカスタムリソースは更新されません。 |
apiVersion: keycloak.org/v1alpha1
kind: KeycloakUser
metadata:
name: example-user
spec:
user:
username: "realm_user"
firstName: "John"
lastName: "Doe"
email: "user@example.com"
enabled: True
emailVerified: False
credentials:
- type: "password"
value: "12345"
realmRoles:
- "offline_access"
clientRoles:
account:
- "manage-account"
realm-management:
- "manage-users"
realmSelector:
matchLabels:
app: example-keycloak
-
このカスタムリソース用のYAMLファイルがあること。
-
realmSelector
は既存のレルム・カスタム・リソースのラベルと一致します。 -
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
作成したYAMLファイルで
kubectl apply -f 1.yaml
のコマンドを使用します。たとえば、$ kubectl apply -f initial_user.yaml keycloak.keycloak.org/example-user created
-
Keycloakの関連インスタンスの管理コンソールにログインします。
-
Usersをクリックします。
-
YAMLファイルで定義したユーザーを検索します。
ユーザーを見つけるには、別のレルムに切り替える必要があるかもしれません。
.
ユーザーが作成されると、Operatorは: credential-<realm name>-<username>-<namespace>
のネーミングパターンでシークレットを作成します。これには、ユーザー名と、CRの credential
属性で指定されている場合はパスワードを含みます。
以下は例です。
KeycloakUser
シークレットkind: Secret
apiVersion: v1
data:
password: <base64 encoded password>
username: <base64 encoded username>
type: Opaque
Operatorがカスタムリソースを処理したら、次のコマンドでステータスを表示します。
$ kubectl describe keycloak <CR-name>
Name: example-realm-user
Namespace: keycloak
Labels: app=example-keycloak
API Version: keycloak.org/v1alpha1
Kind: KeycloakUser
Spec:
Realm Selector:
Match Labels:
App: example-keycloak
User:
Email: realm_user@redhat.com
Credentials:
Type: password
Value: <user password>
Email Verified: false
Enabled: true
First Name: John
Last Name: Doe
Username: realm_user
Status:
Message:
Phase: reconciled
Events: <none>
-
外部データベースがある場合は、Keycloakカスタムリソースを変更してそれをサポートできます。 外部データベースへの接続 を参照してください。
-
カスタムリソースを使用してデータベースをバックアップするには、 データベースのバックアップをスケジュールする を参照してください。
外部データベースへの接続
Operatorを使って外部のPostgreSQLデータベースに接続するには、 keycloak-db-secret
というYAMLファイルを作成し、Keycloak CR externalDatabaseプロパティーをenabledに設定します。値はBase64エンコードされることに注意してください。
keycloak-db-secret
のYAMLファイルの例apiVersion: v1
kind: Secret
metadata:
name: keycloak-db-secret
namespace: keycloak
stringData:
POSTGRES_DATABASE: <Database Name>
POSTGRES_EXTERNAL_ADDRESS: <External Database IP or URL (resolvable by K8s)>
POSTGRES_EXTERNAL_PORT: <External Database Port>
POSTGRES_PASSWORD: <Database Password>
# Required for AWS Backup functionality
POSTGRES_SUPERUSER: "true"
POSTGRES_USERNAME: <Database Username>
SSLMODE: <TLS configuration for the Database connection>
type: Opaque
次のプロパティーには、データベースのホスト名またはIPアドレスとポートを設定します。
-
POSTGRES_EXTERNAL_ADDRESS
- 外部データベースのIPアドレスまたはホスト名。このアドレスは、Kubernetesクラスターで解決可能である必要があります。 -
POSTGRES_EXTERNAL_PORT
- (任意)データベースのポート。
他のプロパティーは、ホストされたデータベースまたは外部データベースの場合と同じように機能します。次のように設定します。
-
POSTGRES_DATABASE
- 使用するデータベース名。 -
POSTGRES_USERNAME
- データベースのユーザー名 -
POSTGRES_PASSWORD
- データベースのパスワード -
POSTGRES_SUPERUSER
- バックアップをスーパーユーザーとして実行するかどうかを示します。通常はtrue
です。 -
SSL_MODE
- 外部のPostgreSQLデータベースへの接続でTLSを使用するかどうかを示します。可能な 値 を確認してください。
SSL_MODE
を有効にすると、OperatorはPostgreSQLデータベースで使用されている root.crt
を含む keycloak-db-ssl-cert-secret
というシークレットを検索します。シークレットの作成はオプションで、データベースの証明書を検証したい場合(例: SSLMODE: verify-ca
)にのみシークレットが使用されます。以下に例を示します。
TLS Secret
のYAMLファイルの例。apiVersion: v1
kind: Secret
metadata:
name: keycloak-db-ssl-cert-secret
namespace: keycloak
type: Opaque
data:
root.crt: {root.crt base64}
Operatorは keycloak-postgresql
という名前のサービスを作成します。このサービスは、 POSTGRES_EXTERNAL_ADDRESS
の内容に基づいて外部データベースを公開するようにOperatorが設定します。Keycloakはこのサービスを使ってデータベースに接続しますが、これはデータベースに直接接続するのではなく、このサービスを介して接続することを意味します。
Keycloakカスタムリソースは、外部データベースのサポートを有効にするために更新が必要です。
Keycloak
カスタムリソースのYAMLファイルの例apiVersion: keycloak.org/v1alpha1
kind: Keycloak
metadata:
labels:
app: example-keycloak
name: example-keycloak
namespace: keycloak
spec:
externalDatabase:
enabled: true
instances: 1
-
keycloak-db-secret
のYAMLファイルがあること。 -
Keycloakカスタムリソースを変更して、
externalDatabase
をtrue
に設定しました。 -
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
kubectl get secret <secret_for_db> -o yaml
のようにPostgreSQLデータベースのシークレットを見つけます。たとえば、$ kubectl get secret keycloak-db-secret -o yaml apiVersion: v1 data POSTGRES_DATABASE: cm9vdA== POSTGRES_EXTERNAL_ADDRESS: MTcyLjE3LjAuMw== POSTGRES_EXTERNAL_PORT: NTQzMg==
POSTGRES_EXTERNAL_ADDRESS
はBase64形式です。 -
echo "<encoded_secret>" | base64 -decode
のようにシークレットの値をデコードします。たとえば、$ echo "MTcyLjE3LjAuMw==" | base64 -decode 192.0.2.3
-
デコードされた値がデータベースのIPアドレスと一致することを確認します。
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP keycloak-0 1/1 Running 0 13m 192.0.2.0 keycloak-postgresql-c8vv27m 1/1 Running 0 24m 192.0.2.3
-
実行中のサービスのリストに
keycloak-postgresql
が表示されていることを確認します。$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE keycloak ClusterIP 203.0.113.0 <none> 8443/TCP 27m keycloak-discovery ClusterIP None <none> 8080/TCP 27m keycloak-postgresql ClusterIP 203.0.113.1 <none> 5432/TCP 27m
keycloak-postgresql
サービスは、バックエンドの一連のIPアドレスにリクエストを送信します。これらのIPアドレスはエンドポイントと呼ばれます。 -
keycloak-postgresql
サービスで使用されるエンドポイントを表示して、データベースのIPアドレスを使用していることを確認します。$ kubectl get endpoints keycloak-postgresql NAME ENDPOINTS AGE keycloak-postgresql 192.0.2.3.5432 27m
-
Keycloakが外部データベースとともに実行されていることを確認します。この例は、すべてが実行中であることを示しています。
$ kubectl get pods NAME READY STATUS RESTARTS AGE IP keycloak-0 1/1 Running 0 26m 192.0.2.0 keycloak-postgresql-c8vv27m 1/1 Running 0 36m 192.0.2.3
-
カスタムリソースを使用してデータベースをバックアップするには、 データベースのバックアップをスケジュールする を参照してください。
-
Base64エンコードの詳細については、 Kubernetes Secrets manual をご覧ください。
外部Keycloakへの接続
このオペレーターは、外部のKeycloakインスタンスを部分的に管理するためにも使用できます。現在の状態では、クライアントを作成することしかできません。
そのためには、ターゲティングや設定に使用するアンマネージド版の Keycloak
と KeycloakRealm
のCRDを作成する必要があります。
external-keycloak
のYAMLファイルの例apiVersion: keycloak.org/v1alpha1
kind: Keycloak
metadata:
name: external-ref
labels:
app: external-keycloak
spec:
unmanaged: true
external:
enabled: true
url: https://some.external.url
このKeycloakに対して認証を行うために、オペレーターはCRD名の前に credential-
を付けることで、CRDからシークレット名を推測します。
credential-external-ref
のYAMLファイルの例apiVersion: v1
kind: Secret
metadata:
name: credential-external-ref
type: Opaque
data:
ADMIN_USERNAME: YWRtaW4=
ADMIN_PASSWORD: cGFzcw==
EXTERNAL-REALM
のYAMLファイルの例apiVersion: keycloak.org/v1alpha1
kind: KeycloakRealm
metadata:
name: external-realm
labels:
app: external-keycloak
spec:
unmanaged: true
realm:
id: "basic"
realm: "basic"
instanceSelector:
matchLabels:
app: external-keycloak
これで、通常通りクライアントでレルムの参照を使用することができ、外部のKeycloakインスタンスにクライアントが作成されます。
データベース・バックアップのスケジュール
バックアップCRは 非推奨 であり、将来のリリースでは削除される可能性があります。 |
Operatorを使用して、カスタムリソースで定義されているデータベースの自動バックアップをスケジュールできます。カスタムリソースはバックアップ・ジョブ(または定期バックアップの場合は CronJob
)をトリガーし、そのステータスをレポートします。
バックアップをスケジュールするには、次の2つのオプションがあります。
AWS S3ストレージがある場合は、1回限りのバックアップまたは定期的なバックアップを実行できます。AWS S3ストレージがない場合は、ローカル・ストレージにバックアップできます。
AWS S3ストレージへのバックアップ
データベースをAWS S3ストレージに1回または定期的にバックアップできます。データを定期的にバックアップするには、有効な CronJob
を schedule
に入力してください。
AWS S3ストレージの場合、バックアップ・カスタムリソース用のYAMLファイルとAWSシークレット用のYAMLファイルを作成します。バックアップ・カスタムリソースには、次の構造のYAMLファイルが必要です。
apiVersion: keycloak.org/v1alpha1
kind: KeycloakBackup
metadata:
name: <CR Name>
spec:
aws:
# Optional - used only for Periodic Backups.
# Follows usual crond syntax (for example, use "0 1 * * *" to perform the backup every day at 1 AM.)
schedule: <Cron Job Schedule>
# Required - the name of the secret containing the credentials to access the S3 storage
credentialsSecretName: <A Secret containing S3 credentials>
AWSシークレットには、次の構造のYAMLファイルが必要です。
Secret
apiVersion: v1
kind: Secret
metadata:
name: <Secret Name>
type: Opaque
stringData:
AWS_S3_BUCKET_NAME: <S3 Bucket Name>
AWS_ACCESS_KEY_ID: <AWS Access Key ID>
AWS_SECRET_ACCESS_KEY: <AWS Secret Key>
-
BackupカスタムリソースYAMLファイルには、AWS S3の認証情報を含む
Secret
を参照するcredentialsSecretName
が含まれています。 -
KeycloakBackup
カスタムリソースにはaws
サブプロパティーがあります。 -
AWS S3シークレットのYAMLファイルがあり、バックアップ・カスタムリソースで識別されたものと一致する
<Secret Name>
が含まれています。 -
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
kubectl apply -f <secret_for_aws>.yaml
のようにクレデンシャルを使用してシークレットを作成します。たとえば、$ kubectl apply -f secret.yaml keycloak.keycloak.org/aws_s3_secret created
-
kubectl apply -f <secret_for_aws>.yaml
のようにバックアップジョブを作成します。たとえば、$ kubectl apply -f aws_one-time-backup.yaml keycloak.keycloak.org/aws_s3_backup created
-
次のようにバックアップジョブの一覧を表示します。
$ kubectl get jobs NAME COMPLETIONS DURATION AGE aws_s3_backup 0/1 6s 6s
-
実行されたバックアップ・ジョブの一覧を表示します。
$ kubectl get pods NAME READY STATUS RESTARTS AGE aws_s3_backup-5b4rfdd 0/1 Completed 0 24s keycloak-0 1/1 Running 0 52m keycloak-postgresql-c824c6-vv27m 1/1 Running 0 71m
-
次のように完了したバックアップ・ジョブのログを表示します。
$ kubectl logs aws_s3_backup-5b4rf ==> Component data dump completed . . . . [source,bash,subs=+attributes]
バックアップ・ジョブのステータスは、AWSコンソールにも表示されます。
ローカル・ストレージへのバックアップ
Operatorを使用して、ローカルのPersistent Volumeへの1回限りのバックアップを実行するバックアップ・ジョブを作成できます。
apiVersion: keycloak.org/v1alpha1
kind: KeycloakBackup
metadata:
name: test-backup
-
このカスタムリソース用のYAMLファイルがあること。このファイルから
aws
サブプロパティーを省略するようにしてください。 -
Keycloak Operatorによって作成された
PersistentVolumeClaim
に対してのみ予約するために、claimRef
とともにPersistentVolume
があります。
-
kubectl apply -f <backup_crname>
のようにバックアップジョブを作成します。たとえば、$ kubectl apply -f one-time-backup.yaml keycloak.keycloak.org/test-backup
Operatorは
Keycloak-backup-<CR-name>
の命名スキームでPersistentVolumeClaim
を作成します。 -
ボリュームの一覧を表示します。
$ kubectl get pvc NAME STATUS VOLUME keycloak-backup-test-backup Bound pvc-e242-ew022d5-093q-3134n-41-adff keycloak-postresql-claim Bound pvc-e242-vs29202-9bcd7-093q-31-zadj
-
次のようにバックアップジョブの一覧を表示します。
$ kubectl get jobs NAME COMPLETIONS DURATION AGE test-backup 0/1 6s 6s
-
実行されたバックアップ・ジョブの一覧を表示します。
$ kubectl get pods NAME READY STATUS RESTARTS AGE test-backup-5b4rf 0/1 Completed 0 24s keycloak-0 1/1 Running 0 52m keycloak-postgresql-c824c6-vv27m 1/1 Running 0 71m
-
次のように完了したバックアップ・ジョブのログを表示します。
$ kubectl logs test-backup-5b4rf ==> Component data dump completed . . . .
-
永続ボリュームの詳細については、 永続ストレージについて理解する を参照してください。
拡張機能とテーマのインストール
Operatorを使用して、会社または組織に必要な拡張機能とテーマをインストールできます。拡張機能またはテーマは、Keycloakが使用できるものであれば何でもかまいません。たとえば、メトリクス拡張を追加できます。Keycloakカスタムリソースに拡張機能またはテーマを追加します。
apiVersion: keycloak.org/v1alpha1
kind: Keycloak
metadata:
name: example-keycloak
labels:
app: keycloak
spec:
instances: 1
extensions:
- <url_for_extension_or_theme>
externalAccess:
enabled: True
他の拡張機能と同じ方法でテーマをパッケージ化してデプロイできます。詳細については、テーマのデプロイのマニュアル・エントリーを参照してください。
-
Keycloakカスタムリソース用のYAMLファイルがあること。
-
cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。
-
kubectl edit <CR-name>
のようにKeycloakカスタムリソースのYAMLファイルを編集します。 -
extensions:
という行をinstances
行の後に追加します。 -
カスタム拡張機能またはテーマのJARファイルにURLを追加します。
-
ファイルを保存します。
Operatorは拡張機能またはテーマをダウンロードしてインストールします。
カスタムリソースを管理するためのコマンド・オプション
カスタム・リクエストを作成したら、 kubectl
コマンドを使用して、それを編集または削除できます。
-
カスタム・リクエストを編集するには、次のコマンドを使用します。
kubectl edit <CR-name>
-
カスタム・リクエストを削除するには、次のコマンドを使用します。
kubectl delete <CR-name>
たとえば、 test-realm
という名前のレルム・カスタム・リクエストを編集するには、次のコマンドを使用します。
$ kubectl edit test-realm
変更を加えることができるウィンドウが開きます。
Keycloak CRのYAMLファイルを更新すれば、変更がデプロイメントに適用されます。 その他のリソースの更新には次の制限があります。 Keycloak Realm CRは、同期オプションのない基本的な作成と削除のみをサポートします。Keycloak User CRとClient CRは、一方向の更新をサポートします(CRへの変更はKeycloakに反映されますが、Keycloakで行われた変更はCRには反映されません)。 |
アップグレード戦略
オペレーターがKeycloakのアップグレードを実行する方法を設定できます。次のアップグレード戦略から選択できます。
-
recreate
: これがデフォルトの戦略です。オペレーターはすべてのKeycloakのレプリカを削除し、オプションでバックアップを作成してから、新しいKeycloakイメージに基づいてレプリカを作成します。この戦略は、単一のKeycloakのバージョンが基盤となるデータベースにアクセスしているため、メジャー・アップグレードに適しています。欠点は、アップグレード中にKeycloakをシャットダウンする必要があることです。 -
rolling
: オペレーターは一度に1つのレプリカを削除し、新しいKeycloakのイメージに基づいてレプリカを再作成します。これにより、ゼロ・ダウンタイムのアップグレードが保証されますが、データベースは複数のKeycloakのバージョンによって同時にアクセスされるため、データベースの移行を必要としないマイナー・バージョンのアップグレードに適しています。この戦略では、自動バックアップはサポートされていません。
apiVersion: keycloak.org/v1alpha1
kind: Keycloak
metadata:
name: example-keycloak
labels:
app: keycloak
spec:
instances: 2
migration:
strategy: recreate
backups:
enabled: True
externalAccess:
enabled: True
-
ローリング・アップデートの詳細については、 Updating StatefulSets manual を参照してください。