バージョン 18.0.2 最新はこちらをクリック

このガイドは、KeycloakのレガシーなWildFlyディストリビューション用です。

Quarkusによる新しいディストリビューションについては、新しい Server Guides をチェックしてください。

ガイドの概要

このガイドの目的は、Keycloakサーバーの初回起動の前に完了する必要があるいくつかの手順について説明することです。Keycloakをテストしたいだけの場合は、組み込みのローカル専用のデータベースでそのまま実行する方がよいでしょう。実際にプロダクション環境にデプロイしたい場合は、まずどのようにランタイム(スタンドアローン・モードまたはドメインモード)でサーバー設定を管理するか決定して、Keycloakの共有データベースを設定し、暗号化とHTTPSの設定を行い、最後にKeycloakをセットアップしてクラスター内で起動する必要があります。このガイドは、Keycloakサーバーをデプロイする前に、起動に先んじて定義と設定が必要なすべての手順を、ひとつひとつ説明していきます。

ただし、KeycloakはWildFly Application Serverに基づいていて、Keycloakの設定はWildFlyの設定項目と密接に関わっています。そのためこのガイドでは、詳細な説明について、このチュートリアルとは別の外部ドキュメントを紹介することがあります。その点は留意ください。

KeycloakはWildFlyアプリケーション・サーバーに追加構築されたもので、Infinispan(キャッシュのため)およびHibernate(永続化のため)のようなサブプロジェクトのひとつです。このガイドでは、基本的なインフラ構築レベルの設定のみ説明します。したがって、是非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-18.0.2.[zip|tar.gz]

    このファイルは、サーバーのみの配布物です。Keycloakサーバーを実行するためのスクリプトとバイナリー以外は何も含まれていません。

  • keycloak-overlay-18.0.2.[zip|tar.gz]

    このファイルは、既存のWildFlyディストリビューションの上にKeycloakサーバーをインストールするために使用できるWildFlyアドオンです。 アプリケーションとKeycloakを同じサーバー・インスタンスで動作させたいというユーザーには対応していません。

手順
  1. Keycloakサーバーをインストールするには、お使いのOSの unzip または gunziptar ユーティリティーを keycloak-18.0.2.[zip|tar.gz] ファイル上で実行します。

  2. Keycloak Service Packをインストールするには、別のサーバー・インスタンスにインストールする必要があります。

    1. あなたのWildFlyディストリビューションのルート・ディレクトリーに移動します。

    2. keycloak-overlay-18.0.2.[zip|tar.gz] ファイルを解凍してください。

    3. シェルでbinディレクトリーを開きます。

    4. ./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/ ディレクトリーにあります。

スタンドアローン起動スクリプト

standalone boot files

サーバーを起動するには下記を実行します。

Linux/Unix
$ .../bin/standalone.sh
Windows
> ...\bin\standalone.bat

スタンドアローン・モード構成

このガイドの大半は、Keycloakの基盤レベルの設定について説明します。このレベルの設定は、Keycloakが構築されたアプリケーション・サーバーに特化した設定ファイル内に定義されます。スタンドアローン動作モードでは、このファイルは …​/standalone/configuration/standalone.xml にあります。また、このファイルはKeycloakのコンポーネントに特化した非基盤レベルの設定にも使用されます。

スタンドアローン設定ファイル

standalone config file

サーバーの実行中にこのファイルに変更を加えても、反映されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 23 Documentationを参照してください。

スタンドアローン・クラスター・モードの使用

スタンドアローン・クラスター動作モードは、クラスター内でKeycloakを実行するときに適用します。このモードでは、サーバー・インスタンスを実行する各マシンにKeycloakの配布物のコピーが保存されている必要があります。このモードは、最初は非常に簡単にデプロイできますが、後でかなり煩雑になる可能性があります。設定を変更するには、各マシンの配布物を修正します。大規模なクラスターの場合、時間がかかり、エラーも発生しやすくなります。

スタンドアローン・クラスター設定

この配布物には、クラスター内で実行するためのアプリケーション・サーバーの設定ファイルが含まれており、その大半は設定が済んでいます。ネットワーク、データベース、キャッシュ、およびディスカバリーのための基盤設定がすべて含まれています。このファイルは …​/standalone/configuration/standalone-ha.xml にあります。しかし、この設定だけでは足りません。共有データベース接続を設定せずに、クラスター内でKeycloakを実行することはできません。また、クラスターのフロントに何らかのロードバランサーを配備する必要があります。このガイドのクラスタリングデータベースのセクションでは、これらのことを説明します。

スタンドアローンHA設定

standalone ha config file

サーバーの実行中にこのファイルに変更を加えても、反映されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 23 Documentationを参照してください。

スタンドアローン・クラスター・モードでの起動

Keycloakを起動するには、スタンドアローン・モードで実行したのと同じ起動スクリプトを使用します。スタンドアローン・モードとの違いは、HA設定ファイルを指し示す追加フラグを渡すという点になります。

スタンドアローン・クラスター起動スクリプト

standalone boot files

サーバーを起動するには下記を実行します。

Linux/Unix
$ .../bin/standalone.sh --server-config=standalone-ha.xml
Windows
> ...\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サーバーのドメイン・プロファイルとサーバーグループは、以下で定義されます。

domain.xml

domain file

ドメイン・コントローラーの実行中にこのファイルに変更を加えても、変更されず、サーバーに上書きされる可能性があります。その場合は、代わりにWildFlyのwebコンソールまたはコマンドライン・スクリプトを使用します。詳しくは、WildFly 23 Documentationを参照してください。

この domain.xml ファイルの特徴を確認していきましょう。 auth-server-standaloneauth-server-clusteredprofile の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-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.xmlhost-slave.xml の2つのホスト・コントローラー設定ファイルが付属しています。 host-master.xml はドメイン・コントローラー、ロードバランサー、および1つのKeycloakサーバー・インスタンスを起動するように設定されています。一方、 host-slave.xml はドメイン・コントローラーと通信し、1つのKeycloakサーバー・インスタンスを起動するように設定されています。

ロードバランサーは必須サービスではありません。これは、開発マシン上でクラスタリングを簡単にテストできるようにするものです。プロダクション環境で使用可能ですが、使いたい別のハードウェアまたはソフトウェア・ベースのロードバランサーがあるなら、置き換えるかどうかを選択できます。
ホスト・コントローラー設定

host files

ロードバランサー・サーバー・インスタンスを無効にするには、 host-master.xml を編集し、 "load-balancer" エントリーをコメントアウトまたは削除します。

    <servers>
        <!-- remove or comment out next line -->
        <server name="load-balancer" group="loadbalancer-group"/>
        ...
    </servers>

このファイルのもう一つの興味深い点は、認証サーバー・インスタンスの宣言です。これには、 port-offset という設定があります。 domain.xmlsocket-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ブートサーバーと同じようなものになります。

ワーキング・ディレクトリー

domain server dir

ドメイン・クラスター・モードでの起動

ドメインモードでサーバーを実行する場合、オペレーティング・システム固有の起動スクリプトを実行する必要があります。これらのスクリプトは、サーバー配布物の bin/ ディレクトリーにあります。

ドメイン起動スクリプト

domain boot files

サーバーを起動するには下記を実行します。

Linux/Unix
$ .../bin/domain.sh --host-config=host-master.xml
Windows
> ...\bin\domain.bat --host-config=host-master.xml

起動スクリプトを実行する場合、 --host-config スイッチ経由で、使用するホスト制御設定ファイルを渡す必要があります。

クラスター化されたドメインのサンプルを使ったテスト

サンプルの domain.xml 設定を使用してクラスタリングをテストできます。このサンプルドメインは、1台のマシンで実行され、以下を起動します。

  • ドメイン・コントローラー

  • HTTPロードバランサー

  • 2つのKeycloakサーバー・インスタンス

手順
  1. 2つのホスト・コントローラーを起動するために、domain.sh スクリプトを2回実行します。

    1つ目はマスター・ホスト・コントローラーで、ドメイン・コントローラー、HTTPロードバランサー、1つのKeycloak認証サーバー・インスタンスを起動します。2つ目はスレーブ・ホスト・コントローラーで、認証サーバーのインスタンスのみを起動します。

  2. スレーブ・ホスト・コントローラーがドメイン・コントローラーと安全に通信できるように設定します。以下の手順を実行してください。

    これらの手順を省略すると、スレーブホストはドメイン・コントローラーから集中管理された設定を取得できません。

    1. マスターとスレーブの間で共有されるサーバー管理者のユーザーとシークレットを作成し、安全な接続を設定します。

      …​/bin/add-user.sh スクリプトを実行してください。

    2. スクリプトで追加するユーザーの種類を尋ねられたら、 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に追加します。このスクリプトで使用および生成されるクレデンシャルは、デモ目的でのみ使用されます。お使いのシステムで生成されたものを使用してください。
  3. …​/domain/configuration/host-slave.xml ファイルにシークレットの値をカット・アンド・ペーストすると、以下のようになります。

         <management>
             <security-realms>
                 <security-realm name="ManagementRealm">
                     <server-identities>
                         <secret value="bWdtdDEyMyE="/>
                     </server-identities>
  4. 作成したユーザーの username…​/domain/configuration/host-slave.xml ファイルに追加します。

         <remote security-realm="ManagementRealm" username="admin">
  5. ブートスクリプトを2回実行して、1台の開発マシンで2つのノードクラスターをシミュレートします。

    マスターの起動
    $ domain.sh --host-config=host-master.xml
    スレーブの起動
    $ domain.sh --host-config=host-slave.xml
  6. ブラウザーを開いてhttp://localhost:8080/authにアクセスし、試してみてください。

クロスサイト・レプリケーション・モードの使用

cross-site replication modeは、 テクノロジー・プレビュー であり、完全にはサポートされていません。

クロスサイト・レプリケーション・モードを使用して、複数のデータセンターにまたがるクラスターでKeycloakを実行します。一般的には、異なる地域にあるデータセンターのサイトを使用します。このモードを使用すると、各データセンターはKeycloakサーバーの独自のクラスターを持つことになります。

このドキュメントでは、以下のアーキテクチャー図の例を参照して、シンプルなクロスサイト・レプリケーションのユースケースを説明します。

アーキテクチャー図の例

cross dc architecture

前提条件

これは高度なトピックのため、最初に以下を読み、背景にある重要な知識を身につけておくことをお勧めします。

  • Keycloakによるクラスタリング クロスデータセンター・レプリケーションを設定する場合、より独立したKeycloakクラスターを使用するため、クラスターの仕組みや、ロード・バランシング、共有データベース、マルチキャストなどの基本的な概念と要件を理解する必要があります。

  • Infinispan Cross-Site Replication は、地理的に離れた場所にあるクラスター間でデータをレプリケーションします。

技術的な詳細

このセクションでは、Keycloakクロスサイト・レプリケーションの仕組みについて概念と詳細について説明します。

Data

Keycloakはステートフルなアプリケーションです。データソースとして以下のものを使用します。

  • データベースは、ユーザー情報などの永続的なデータを保持するために使用されます。

  • Infinispanキャッシュは、永続化データをデータベースからキャッシュし、短期間で頻繁に変化するメタデータ(ユーザー・セッションなど)を節約するためにも使用されます。Infinispanは通常、データベースよりもはるかに高速ですが、Infinispanを使用して保存されたデータは永続的ではなく、クラスターを再起動後も維持できるとは限りません。

このアーキテクチャーの例では、 site1site2 と呼ばれる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は、 realmsusers 、および authorization と呼ばれるローカルInfinispanキャッシュを使用して、永続化データをキャッシュします。

すべてのデータセンターでレプリケートされる、別のキャッシュ work を使用します。workキャッシュ自体は実際のデータをキャッシュしません。クラスターノードとデータセンター間で無効化メッセージを送信する場合にのみ使用されます。つまり、データ(ユーザー john のようなデータ)が更新されると、Keycloakノードは、同じデータセンター内の他のすべてのクラスターノード、および他のすべてのデータセンターに無効化メッセージを送信します。すべてのノードは、無効通知を受信した後、ローカル・キャッシュから適切なデータを無効にします。

ユーザー・セッション

sessionsclientSessionsofflineSessions 、および 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 11.0.8のクロスサイト・レプリケーションの基本的な設定を行います。

Infinispan 11.0.8のこの例には、 site1site2 の2つのデータセンターが含まれます。各データセンターは、1つのInfinispanサーバーと2つのKeycloakサーバーで構成されています。合計すると、2つのInfinispanサーバーと4つのKeycloakサーバーになります。

  • Site1 は、Infinispanサーバーの server1 と2つのKeycloakサーバーの node11 および node12 で構成されています。

  • Site2 は、Infinispanサーバーの server2 と2つのKeycloakサーバーの node21 および node22 で構成されています。

  • Infinispanサーバーである server1server2 は、 Infinispan のドキュメント で記載されているのと同様の方法で、RELAY2プロトコルと backup ベースのInfinispanキャッシュを介して相互に接続されています。

  • Keycloakサーバーである node11node12 は、お互いにクラスターを形成しますが、 site2 内のサーバーとは直接通信はしません。それらはHot Rodプロトコル (リモート・キャッシュ)を使用して、Infinispanサーバー server1 と通信します。詳細については、コミュニケーションの詳細を参照してください。

  • 同じ説明が node21node22 にも当てはまります。それらはお互いにクラスター化し、Hot Rodプロトコルを使用して、 server2 サーバーとのみ通信します。

この設定の例では、4つのKeycloakサーバーすべてが同じデータベースと通信することを前提としています。プロダクション環境では、データベースで説明されているとおり、データセンター間で別々の同期レプリケートされたデータベースを使用することをお勧めします。

Infinispanサーバーのセットアップ

クロスサイト・レプリケーションの場合、KeycloakのデータをバックアップできるリモートInfinispanクラスターを作成することから始めます。

前提条件
  • Infinispanサーバー11.0.8をダウンロードしてインストールします。

Infinispanサーバー11.0.8にはJava 11が必要です。

手順
  1. Infinispanからのクライアント接続を認証するユーザーを作成します。次に例を示します。

    $ bin/cli.sh user create myuser -p "qwer1234!"

    Keycloakにリモートキャッシュを作成するときに、HotRodクライアントの設定でこれらのクレデンシャルを指定します。

  2. InfinispanとKeycloakの間の接続を保護するために、SSLキーストアとトラストストアを作成します。次に例を示します。

    1. キーストアを作成して、InfinispanクラスターにSSLのIDを提供します

      keytool -genkey -alias server -keyalg RSA -keystore server.jks -keysize 2048
    2. キーストアからSSL証明書をエクスポートします。

      keytool -exportcert -keystore server.jks -alias server -file server.crt
    3. KeycloakがInfinispanのSSLのIDを確認するために使用できるトラストストアに、SSL証明書をインポートします。

      keytool -importcert -keystore truststore.jks -alias server -file server.crt
    4. server.crt を削除します。

      rm server.crt
Infinispanクラスターの設定

データセンター間でKeycloakデータを複製するようにInfinispanクラスターを設定します。

前提条件
  • Infinispanサーバーをインストールしてセットアップします。

手順
  1. 編集のために infinispan.xml を開きます。

    デフォルトでは、Infinispanサーバーはクラスター・トランスポートやセキュリティー機構などの静的設定に server/conf/infinispan.xml を使用します。

  2. クラスター検出プロトコルとして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 server1server2 のホスト名を一覧表示します。
  3. Infinispanのクラスター・トランスポートを設定して、クロスサイト・レプリケーションを実行します。

    1. 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スタックを使用します。
    2. スタックを使用するようにInfinispanクラスター・トランスポートを設定します。

      <cache-container name="default" statistics="true">
            <transport cluster="${infinispan.cluster.name:cluster}"
                       stack="xsite"/> (1)
      </cache-container>
      1 クラスターに xsite スタックを使用します。
  4. サーバー・セキュリティー・レルムでキーストアを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 キーストア内の証明書のエイリアスに名前を付けます。
  5. 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クライアントの設定で指定します。
  6. キャッシュ・テンプレートを作成します。

    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クラスターのバックアップ・サイトに名前を付けます。
  7. Infinispanのserver1を起動します。

    ./server.sh -c infinispan.xml -b PUBLIC_IP_ADDRESS -k PUBLIC_IP_ADDRESS -Djgroups.mcast_addr=228.6.7.10
  8. Infinispanのserver2を起動します。

    ./server.sh -c infinispan.xml -b PUBLIC_IP_ADDRESS -k PUBLIC_IP_ADDRESS -Djgroups.mcast_addr=228.6.7.11
  9. 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クラスターを設定します。

手順
  1. たとえば、次にようにキャッシュを含むバッチファイルを作成します。

    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
  2. CLIを使用してキャッシュを作成します。

    $ bin/cli.sh -c https://server1:11222 --trustall -f /tmp/caches.batch
    引数 --trustall の代わりに、引数 -t でトラストストアを指定し、 -s 引数でトラストストア・パスワードを指定できます。
  3. 他のサイトにキャッシュを作成します。

Keycloakでのリモート・キャッシュ・ストアの設定

リモートのInfinispanクラスターをセットアップした後、KeycloakでInfinispanサブシステムを設定して、リモートストアを介してそれらのクラスターにデータを外部化します。

前提条件
  • クロスサイト設定用にリモートInfinispanクラスターをセットアップします。

  • InfinispanServerのIDを持つSSL証明書を含むトラストストアを作成します。

手順
  1. トラストストアをKeycloakの配備に追加します。

  2. 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 のポートを定義します。
  3. 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"/>
  4. 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 ドキュメント を参照してください。

  5. 次の各キャッシュに対する分散キャッシュを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 ソケット・バインディングを指定します。
  6. NODE11 を後述する NODE12NODE21NODE22 という3つのディレクトリーにコピーしてください。

  7. 次のように、 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!
  8. 次のように、 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]
    ログにあるチャネル名とは異なっている可能性があります。
  9. 次のように、 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

    NODE11NODE12 を使用してクラスターに接続するのではなく、別のクラスターに接続する必要があります。

    Received new cluster view for channel keycloak: [node21|0] (1) [node21]
  10. 次のように、 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]
    ログにあるチャネル名とは異なっている可能性があります。
  11. 次のように、テストを行ってください。

    1. http://node11:8080/auth/ に移動し、最初の管理者ユーザーを作成します。

    2. http://node11:8080/auth/admin に移動し、管理者として管理コンソールにログインします。

    3. 2つ目のブラウザーを開き、 http://node12:8080/auth/admin または http://node21:8080/auth/admin もしくは http://node22:8080/auth/admin のいずれかのノードに移動します。ログイン後、4つのすべてのサーバー上の特定のユーザー、クライアントまたはレルムの Sessions タブで同じセッションを表示できます。

    4. Keycloakの管理コンソールで変更を行った後、ユーザーやレルムの変更などを行います。管理者コンソールでユーザーやレルムの変更を行った後、その変更は4つのノードのいずれかですぐに表示されるはずです。キャッシュはすべての場所で適切に無効化されているはずです。

    5. 必要に応じて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'

Infinispan 9.4.19でのクロスサイト・レプリケーションの設定

Infinispan 9.4.19のこの例には、 site1site2 の2つのデータセンターが含まれます。各データセンターは、1つのInfinispanサーバーと2つのKeycloakサーバーで構成されています。合計すると、2つのInfinispanサーバーと4つのKeycloakサーバーになります。

  • Site1 は、Infinispanサーバーの server1 と2つのKeycloakサーバーの node11 および node12 で構成されています。

  • Site2 は、Infinispanサーバーの server2 と2つのKeycloakサーバーの node21 および node22 で構成されています。

  • Infinispanサーバーである server1server2 は、 Infinispan のドキュメント で記載されているのと同様の方法で、RELAY2プロトコルと backup ベースのInfinispanキャッシュを介して相互に接続されています。

  • Keycloakサーバーである node11node12 は、お互いにクラスターを形成しますが、 site2 内のサーバーとは直接通信はしません。それらはHot Rodプロトコル (リモート・キャッシュ)を使用して、Infinispanサーバー server1 と通信します。詳細については、コミュニケーションの詳細を参照してください。

  • 同じ説明が node21node22 にも当てはまります。それらはお互いにクラスター化し、Hot Rodプロトコルを使用して、 server2 サーバーとのみ通信します。

この設定の例では、4つのKeycloakサーバーすべてが同じデータベースと通信することを前提としています。プロダクション環境では、データベースで説明されているとおり、データセンター間で別々の同期レプリケートされたデータベースを使用することをお勧めします。

Infinispanサーバーのセットアップ

Infinispanサーバーの設定は、以下の手順に沿って行います。

  1. Infinispan 9.4.19サーバーをダウンロードし、選択したディレクトリーに解凍します。このロケーションは、 SERVER1_HOME として後ほど参照することになります。

  2. JGroupsサブシステムの設定で、 SERVER1_HOME/server/conf/infinispan-xsite.xml 内にあるこれらを変更します。

    1. xsite チャネルを追加して、 channels 要素の下にある tcp スタックを使用します。

      <channels default="cluster">
          <channel name="cluster"/>
          <channel name="xsite" stack="tcp"/>
      </channels>
    2. relay 要素を udp スタックの最後尾に追加します。自身のサイトは site1 で、バックアップする他のサイトは site2 というように設定します。

      <stack name="udp">
          ...
          <relay site="site1">
              <remote-site name="site2" channel="xsite"/>
              <property name="relay_multicasts">false</property>
          </relay>
      </stack>
    3. MPING の代わりに、 tcp スタックを設定して TCPPING プロトコルを使用します。 MPING 要素を削除して TCPPING に置き換えます。 initial_hosts 要素は、ホスト server1server2 を指します。

      <stack name="tcp">
          <transport type="TCP" socket-binding="jgroups-tcp"/>
          <protocol type="TCPPING">
              <property name="initial_hosts">server1[7600],server2[7600]</property>
              <property name="ergonomics">false</property>
          </protocol>
          <protocol type="MERGE3"/>
          ...
      </stack>
      これは、単にすばやく実行するための設定例です。プロダクション環境では、JGroups RELAY2tcp スタックを使用する必要はなく、他のどのスタックを設定しても構いません。たとえば、データセンター間のネットワークがマルチキャストをサポートできる場合は、デフォルトのudpスタックを使用することができます。InfinispanとKeycloakクラスターがお互いを見つけることはできないという点だけは確認してください。同じように、 TCPPING を検出プロトコルとして使用する必要はありません。また、 TCPPING は静的な性質であるため、使用することはないでしょう。最後に、サイト名も設定することができます。この設定のより詳細な内容については、Keycloakドキュメントの範囲外になります。詳細については、InfinispanのドキュメントおよびJGroupsのドキュメントを参照してください。
  3. SERVER1_HOME/standalone/configuration/clustered.xmlclustered という名前のcache-containerの下に次の設定を追加します。

    <cache-container name="clustered" default-cache="default" statistics="true">
            ...
            <replicated-cache-configuration name="sessions-cfg" mode="SYNC" start="EAGER" batching="false">
                <locking acquire-timeout="0" />
                <backups>
                    <backup site="site2" failure-policy="FAIL" strategy="SYNC" enabled="true">
                        <take-offline min-wait="60000" after-failures="3" />
                    </backup>
                </backups>
            </replicated-cache-configuration>
    
            <replicated-cache name="work" configuration="sessions-cfg"/>
            <replicated-cache name="sessions" configuration="sessions-cfg"/>
            <replicated-cache name="clientSessions" configuration="sessions-cfg"/>
            <replicated-cache name="offlineSessions" configuration="sessions-cfg"/>
            <replicated-cache name="offlineClientSessions" configuration="sessions-cfg"/>
            <replicated-cache name="actionTokens" configuration="sessions-cfg"/>
            <replicated-cache name="loginFailures" configuration="sessions-cfg"/>
    
    </cache-container>
    replicated-cache-configuration 内の設定オプションについての詳細は、Infinispanキャッシュ設定のチューニングで説明しています。これには、これらのオプションのいくつかを調整するための情報が含まれています。
    以前のバージョンとは異なり、Infinispanサーバーの replicated-cache-configurationtransaction 要素なしで設定する必要があります。詳細はトラブルシューティングを参照してください。
  4. 一部のInfinispanサーバーリリースでは、ネットワーク経由で保護されたキャッシュにアクセスする前に認可が必要です。

    推奨されたInfinispan 9.4.19サーバーを使用している場合は、何も問題はありません。この手順は無視しても構いません(無視すべきです)。認可に関連する問題は、他のバージョンのInfinispanサーバーにのみ存在する可能性があります。

    Keycloakはスクリプトを含む ___script_cache キャッシュへの更新が必要です。このキャッシュにアクセスする際にエラーが発生した場合、下記のように clustered.xml 設定で認可を設定する必要があります。

    1. <management> のセクションの中で、次のようにセキュリティー・レルムを追加します。

      <management>
          <security-realms>
              ...
              <security-realm name="AllowScriptManager">
                  <authentication>
                      <users>
                          <user username="___script_manager">
                              <password>not-so-secret-password</password>
                          </user>
                      </users>
                  </authentication>
              </security-realm>
          </security-realms>
    2. サーバー・コア・サブシステムで、以下のように <security> を追加します。

      <subsystem xmlns="urn:infinispan:server:core:8.4">
          <cache-container name="clustered" default-cache="default" statistics="true">
              <security>
                  <authorization>
                      <identity-role-mapper/>
                      <role name="___script_manager" permissions="ALL"/>
                  </authorization>
              </security>
              ...
    3. エンドポイント・サブシステムで、Hot Rodコネクターに認証設定を追加します。

      <subsystem xmlns="urn:infinispan:server:endpoint:8.1">
          <hotrod-connector cache-container="clustered" socket-binding="hotrod">
              ...
              <authentication security-realm="AllowScriptManager">
                  <sasl mechanisms="DIGEST-MD5" qop="auth" server-name="keycloak-jdg-server">
                      <policy>
                          <no-anonymous value="false" />
                      </policy>
                  </sasl>
              </authentication>
  5. 2つ目のロケーションにサーバーをコピーします。これは、 SERVER2_HOME として後ほど参照することになります。

  6. SERVER2_HOME/standalone/configuration/clustered.xml では、 site1site2 に置き換えると、JGroupsサブシステム内の relay の設定とcache-subsystem内の backups の設定の両方において、逆の動作をします。次に例を示します。

    1. relay 要素は、以下のように表示されます。

      <relay site="site2">
          <remote-site name="site1" channel="xsite"/>
          <property name="relay_multicasts">false</property>
      </relay>
    2. backups 要素は、以下のように表示されます。

      <backups>
        <backup site="site1" ....
        ...
      以下の PUBLIC_IP_ADDRESS には、サーバーがバインドするために使用できるIPアドレスまたはホスト名を指します。すべてのInfinispanサーバーとKeycloakサーバーは異なるアドレスを使用する必要があることに注意してください。すべてのサーバーが同じ管理インターフェースを使用する必要があるため、すべてのサーバーが同じホストで実行されているセットアップ例では、オプション -Djboss.bind.address.management=PUBLIC_IP_ADDRESS を追加する必要がある場合があります。ただし、サーバーへのリモートアクセスを回避するために、このオプションは通常、プロダクション環境では外してください。詳細については、 WildFly 23 Documentation を参照してください。
  7. server1 サーバーを起動します。

    cd SERVER1_HOME/bin
    ./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true \
      -Djboss.default.multicast.address=234.56.78.99 \
      -Djboss.node.name=server1 -b PUBLIC_IP_ADDRESS
  8. server2 サーバーを起動します。異なるマルチキャスト・アドレスがあるため、 server1server2 サーバーは互いに直接クラスター化されません。むしろ、それらはRELAY2プロトコルを介して接続されており、TCP JGroupsスタックはそれらの間の通信に使用されます。起動コマンドは次のようになります。

    cd SERVER2_HOME/bin
    ./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true \
      -Djboss.default.multicast.address=234.56.78.100 \
      -Djboss.node.name=server2 -b PUBLIC_IP_ADDRESS
  9. この時点でチャネルが動作していることを検証するには、JConsoleを使用し、実行中の SERVER1 または SERVER2 サーバーに接続する必要があります。MBean jgroups:type=protocol,cluster="cluster",protocol=RELAY2 および printRoutes オペレーションを使用すると、以下のような出力が表示されます。

    site1 --> _server1:site1
    site2 --> _server2:site2

    MBean jgroups:type=protocol,cluster="cluster",protocol=GMS を使用すると、属性メンバーには単一のメンバーしか含まれていないということがわかります。

    1. SERVER1 では、以下のように表示されます。

      (1) server1
    2. SERVER2 では、以下のように表示されます。

      (1) server2
      プロダクション環境では、すべてのデータセンターにさらに多くのInfinispanサーバーを持つことができます。同じデータセンター内のInfinispanサーバーが同じマルチキャスト・アドレスを使用していること(つまり、起動中に同じ jboss.default.multicast.address を使用していること)を確認するだけです。そうすると、 GMS プロトコルビューのjconsoleに、現在のクラスターのメンバーがすべて表示されます。
Keycloakサーバーのセットアップ
  1. Keycloakサーバー配布物を選択した場所に解凍します。これは NODE11 として後ほど参照することになります。

  2. KeycloakDSデータソースの共有データベースを設定します。テストを目的とする場合は、MySQLまたはMariaDBの使用をお勧めします。詳細はデータベースを参照してください。

    プロダクション環境では、すべてのデータセンターにおいて別々のデータベース・サーバーを用意する必要があり、両方のデータベース・サーバーを互いに同期してレプリケートする必要があります。設定例では、単一のデータベースを使用し、4つのKeycloakサーバーすべてに接続します。

  3. NODE11/standalone/configuration/standalone-ha.xml を以下のように編集してください。

    1. site 属性をJGroups UDPプロトコルに追加します。

      <stack name="udp">
        <transport type="UDP" socket-binding="jgroups-udp" site="${jboss.site.name}"/>
    2. work キャッシュの下に remote-store を追加します。

      <replicated-cache name="work">
          <remote-store cache="work" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true">
              <property name="rawValues">true</property>
              <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
              <property name="protocolVersion">2.9</property>
          </remote-store>
      </replicated-cache>
    3. session キャッシュの下に remote-store を追加します。

      <distributed-cache name="sessions" owners="1">
          <remote-store cache="sessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true">
              <property name="rawValues">true</property>
              <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
              <property name="protocolVersion">2.9</property>
          </remote-store>
      </distributed-cache>
    4. offlineSessionsclientSessionsofflineClientSessionsloginFailuresactionTokens キャッシュでも同じことをします( sessions キャッシュとの唯一の違いは、 cache プロパティー値が異なることです)。

      <distributed-cache name="offlineSessions" owners="1">
          <remote-store cache="offlineSessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true">
              <property name="rawValues">true</property>
              <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
              <property name="protocolVersion">2.9</property>
          </remote-store>
      </distributed-cache>
      
      <distributed-cache name="clientSessions" owners="1">
          <remote-store cache="clientSessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true">
              <property name="rawValues">true</property>
              <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
              <property name="protocolVersion">2.9</property>
          </remote-store>
      </distributed-cache>
      
      <distributed-cache name="offlineClientSessions" owners="1">
          <remote-store cache="offlineClientSessions" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true">
              <property name="rawValues">true</property>
              <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
              <property name="protocolVersion">2.9</property>
          </remote-store>
      </distributed-cache>
      
      <distributed-cache name="loginFailures" owners="1">
          <remote-store cache="loginFailures" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="false" shared="true">
              <property name="rawValues">true</property>
              <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
              <property name="protocolVersion">2.9</property>
          </remote-store>
      </distributed-cache>
      
      <distributed-cache name="actionTokens" owners="2">
          <object-memory size="-1"/>
          <expiration max-idle="-1" interval="300000"/>
          <remote-store cache="actionTokens" remote-servers="remote-cache" passivation="false" fetch-state="false" purge="false" preload="true" shared="true">
              <property name="rawValues">true</property>
              <property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
              <property name="protocolVersion">2.9</property>
          </remote-store>
      </distributed-cache>
    5. リモートストアのアウトバウンド・ソケット・バインディングを socket-binding-group 要素の設定に追加します。

      <outbound-socket-binding name="remote-cache">
          <remote-destination host="${remote.cache.host:localhost}" port="${remote.cache.port:11222}"/>
      </outbound-socket-binding>
    6. 分散キャッシュ設定の authenticationSessions と他のキャッシュは変更されません。

    7. remoteStoreSecurityEnabled プロパティーを false (または上記のようにInfinispanサーバーのセキュリティを有効にした場合は true )の値で、 次のように keycloak-server サブシステムの connectionsInfinispan SPIに追加することをお勧めします

      <spi name="connectionsInfinispan">
          ...
          <provider ...>
              <properties>
                  ...
                  <property name="remoteStoreSecurityEnabled" value="false"/>
              </properties>
          ...
    8. オプションで、 logging サブシステムの下でDEBUGログを有効にします。

      <logger category="org.keycloak.cluster.infinispan">
          <level name="DEBUG"/>
      </logger>
      <logger category="org.keycloak.connections.infinispan">
          <level name="DEBUG"/>
      </logger>
      <logger category="org.keycloak.models.cache.infinispan">
          <level name="DEBUG"/>
      </logger>
      <logger category="org.keycloak.models.sessions.infinispan">
          <level name="DEBUG"/>
      </logger>
  4. NODE11 を後述する NODE12NODE21NODE22 という3つのディレクトリーにコピーしてください。

  5. 次のように、 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
  6. 次のように、 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]
    ログにあるチャネル名とは異なっている可能性があります。
  7. 次のように、 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

    NODE11NODE12 を使用してクラスターに接続するのではなく、クラスターを分離する必要があります。

    Received new cluster view for channel keycloak: [node21|0] (1) [node21]
  8. 次のように、 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]
    ログにあるチャネル名とは異なっている可能性があります。
  9. 次のように、テストを行ってください。

    1. http://node11:8080/auth/ に移動し、最初の管理者ユーザーを作成します。

    2. http://node11:8080/auth/admin に移動し、管理者として管理コンソールにログインします。

    3. 2つ目のブラウザーを開き、 http://node12:8080/auth/admin または http://node21:8080/auth/admin もしくは http://node22:8080/auth/admin のいずれかのノードに移動します。ログイン後、4つのすべてのサーバー上の特定のユーザー、クライアントまたはレルムの Sessions タブで同じセッションを表示できます。

    4. Keycloakの管理コンソールで変更(たとえば、ユーザーやレルムの更新など)を加えた後、その変更は、すぐに4つのノードのいずれかで表示され、キャッシュがどこでも適切に無効化される必要があります。

    5. 必要に応じて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サーバーの前に、 server1server2 の両方を最初に起動します。Keycloakサーバーをそれでも実行する必要があり、バックアップ・サイトがオフラインである場合は、サイトをオフラインおよびオンラインにするでの説明のとおり、サイトのInfinispanサーバー上のバックアップ・サイトを手動でオフラインに切り替えることをお勧めします。使用できない状態のサイトをオフラインに手動で切り替えることができない場合、初回起動に失敗するか、起動時にいくつか例外が発生する可能性があります。これは、失敗した操作の設定数によってバックアップ・サイトが自動的にオフラインになるまでです。

サイトをオフラインおよびオンラインにする

たとえば、以下のようなシナリオを想定します。

  1. サイト site1 から見たサイト site2 は、完全にオフラインです。これは、site2 のすべてのInfinispanサーバーがオフである、 またはsite1site2 の間のネットワークが切断されていることを意味します。

  2. サイト site1 でKeycloakサーバーとInfinispanサーバー server1 を実行します。

  3. いずれかのユーザーが site1 のKeycloakサーバーにログインします。

  4. site1 のKeycloakサーバーは、site2server2 サーバーにデータをバックアップすることを想定し、 server1 サーバー上のリモート・キャッシュにセッションを書き込もうとします。詳細については、コミュニケーションの詳細を参照してください。

  5. server2 サーバーがオフラインであるか、 server1 から到達できない状態なので、 server1 から server2 へのバックアップは失敗します。

  6. 例外は server1 のログにスローされます。デフォルトの FAIL バックアップ失敗ポリシーが設定されているため、その失敗は server1 サーバーからKeycloakサーバーにも伝播されます。バックアップ・ポリシーの詳細については、バックアップ失敗ポリシーを参照してください。

  7. このエラーはKeycloak側でも発生し、ユーザーはログインを完了できない可能性もあります。

使用している環境に応じて、サイト間のネットワークが利用できないか、一時的に壊れている(スプリット・ブレイン)可能性があります。これが起こった場合、 site1 のInfinispanサーバーは、 site2 のInfinispanサーバーが利用できないことに気付き、 server2 サイトのサーバーへアクセスしようとするのを止めるため、バックアップの失敗は発生しません。これは サイトをオフラインにする と呼ばれています。

サイトをオフラインにする

サイトをオフラインにするには2つの方法があります。

管理者による手作業 - 管理者は jconsole または他のツールを使用して、いくつかのJMX操作を実行することで、手動で特定のサイトをオフラインにすることができます。これは、特に停止が計画されている場合に役立ちます。 jconsole またはCLIを使用すると、 server1 サーバーに接続し、 site2 をオフラインにすることができます。この詳細については、 Infinispanドキュメント を参照してください。

SYNCまたはASYNCバックアップで述べた他のすべてのKeycloakキャッシュについても、通常はこれらの手順を実行する必要があります。

自動的作業 - バックアップに失敗した後、通常は site2 が自動的にオフラインになります。これは、Infinispanサーバーのセットアップで設定されたキャッシュ設定内の take-offline 要素の設定によって行われます。

<take-offline min-wait="60000" after-failures="3" />

この例では、少なくとも3回連続して失敗したバックアップがあり、60秒以内にバックアップが成功しなかった場合、特定のシングルキャッシュに対してサイトが自動的にオフラインになることを示しています。

自動的にサイトをオフラインにすることは、特に、サイト間の切断されたネットワークが計画外である場合に便利です。欠点は、ネットワークの停止が検出されるまで何らかのバックアップが失敗し、アプリケーション側で障害が起きてる可能性があります。たとえば、一部のユーザーのログインに失敗したり、大きなログインタイムアウトが発生したりします。 特に、値が FAILfailure-policy が使用されている場合です。

サイトがオフラインであるかどうかの追跡は、キャッシュごとに個別に行われます。
サイトをオンラインにする

一旦ネットワークが復旧し、 site1site2 がお互いに通信することができたら、サイトをオンラインにする必要があります。これは、サイトをオフラインにするのと同じように、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-policyFAIL に設定されています。必要に応じて WARN または IGNORE に変更できます。

FAILWARN の違いは、 FAIL が使用され、Infinispanサーバーが別のサイトにデータのバックアップを試みたときに、バックアップが失敗すると、その失敗が呼び出し側(Keycloakサーバー)に伝播されるという点です。2番目のサイトが一時的に到達不能になったり、同じエンティティーの更新を試みる同時トランザクションが発生した場合は、バックアップが失敗する可能性があります。この場合、Keycloakサーバーは複数回再試行します。ただし、その再試行が失敗した場合、より長いタイムアウト後、ユーザーにはエラーが表示されます。

WARN を使用すると、失敗したバックアップは、InfinispanサーバーからKeycloakサーバーに伝播されません。失敗したバックアップは無視され、ユーザーにはエラーが表示されません。バックアップのデフォルトのタイムアウトは10秒間であるため短いです。これは、 backup 要素の timeout 属性によって変更することができます。タイムアウトにおける再試行はありません。タイムアウト時は、InfinispanサーバーのログにWARNINGメッセージが表示されます。

潜在的な課題としては、いくつかのケースで、再試行( FAIL ポリシーの使用)が役に立つサイト間で短いネットワーク停止が発生する可能性があるため、 WARN (再試行なし)では、サイト間でデータの不整合が発生します。これは、両方のサイトで同時に同じエンティティーを更新しようとする際にも発生します。

これらの不整合はどれほど悪いことなのでしょうか。通常は、ユーザーが再認証する必要があることだけを意味します。

WARN ポリシーを使用すると、 actionTokens キャッシュにより提供され、その特定のキーを処理する、使い捨てのキャッシュが実際に1回使用されますが、同じキーが2回"正常に"書き込まれる可能性があります。しかし、たとえば、OAuth2 仕様では、コードは使い捨てでなければならないと言及されています。 WARN ポリシーでは、これは厳密には保証されておらず、両方のサイトで同時に書き込まれる試みがあった場合、同じコードが2回書き込まれる可能性があります。

より長いネットワーク停止またはスプリット・ブレインが起きた場合、 FAILWARN を使用すると、サイトをオフラインおよびオンラインにするで説明したとおり、少し時間を置いて失敗した後、他のサイトはオフラインになります。デフォルトの1分のタイムアウトでは、関連するキャッシュがすべてオフラインになるまで、通常は1~3分かかります。その後、エンドユーザーの観点から、動作はすべて問題なく進みます。サイトをオフラインおよびオンラインにするで説明したとおり、オンラインに戻ったときに手動でサイトを復元する必要があります。

要約すると、サイト間で頻繁により長い停止が発生する可能性があり、データの不整合と100%正確ではない使い捨てのキャッシュについては許容されますが、エラーや長いタイムアウトがエンドユーザーに表示されないようにする場合には、 WARN に切り替えます。

WARNIGNORE の違いは、 IGNORE では警告がInfinispanログに書き込まれていないことです。詳細については、Infinispanのドキュメントを参照してください。

ロックの取得タイムアウト

デフォルト設定では、NON_DURABLE_XAモードでトランザクションを取得タイムアウト0で使用しています。これは、同じキーに対して進行中の別のトランザクションがある場合、トランザクションはすぐに失敗することを意味します。

デフォルトの10秒ではなく0に切り替えるのは、デッドロックの可能性を避けるためです。Keycloakでは、同じエンティティー(通常はセッション・エンティティーまたはloginFailure)が両方のサイトから同時に更新されることがあります。これにより、状況によってはデッドロックが発生し、トランザクションが10秒間ブロックされる可能性があります。 詳細については、 このJIRAレポート を参照してください。

タイムアウト0の場合、トランザクションは直ちに失敗し、値 FAIL のバックアップ failure-policy が設定されていれば、Keycloakから再試行されます。2番目の同時トランザクションが終了するまで、通常は再試行が成功し、エンティティーは両方の同時トランザクションから更新を適用します。

この設定での同時トランザクションは、非常に良い一貫性と結果が得られるため、そのまま使用することをお勧めします。

唯一の(機能しない)問題は、Infinispanサーバーログの例外です。これは、ロックがすぐに利用できなくなるたびに発生します。

SYNCまたはASYNCバックアップ

backup 要素の重要な部分は strategy 属性です。 SYNCASYNC のどちらが必要かを決める必要があります。クロスサイト・レプリケーションを認識できる7つのキャッシュがあり、これらは、クロスサイトに対する次の3つの異なるモードで設定できます。

  1. SYNCバックアップ

  2. ASYNCバックアップ

  3. バックアップを全くしない

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 キャッシュをまったくバックアップしないことが推奨されます。

  • sessionsclientSessions キャッシュを SYNC で保持しておくことをお勧めします。ユーザーのリクエストとバックチャネル・リクエスト(リクエスト処理で説明したクライアント・アプリケーションからKeycloakへのリクエスト)が常に同じサイトで処理されることが確かな場合にのみ、それらを ASYNC へ切り替えることが可能になります。たとえば、次のような場合はこれが当てはまります。

    • モードで説明した通り、アクティブ/パッシブモードを使用しています。

    • クライアント・アプリケーションはすべて Keycloak JavaScriptアダプター.を使用しています。JavaScriptアダプターは、ブラウザー内でバックチャネル・リクエストを送信するため、それらはブラウザーのスティッキー・セッションに参加し、このユーザーの別のブラウザー・リクエストと同じクラスターノード(したがって同じサイト)で終了します。

    • ロードバランサーは、クライアントIPアドレス(ロケーション)に基づいてリクエストを処理でき、クライアント・アプリケーションは両方のサイトにデプロイされています。

      たとえば、ロンドンとニューヨークの2つのサイトがあります。 アプリケーションがロンドンサイトとニューヨークサイトの両方に配備されている場合は、ロンドンユーザーからのすべてのユーザー・リクエストがロンドンサイトのアプリケーションとロンドンサイトのKeycloakサーバーにリダイレクトされるようにすることができます。 ロンドンサイトのクライアント・デプロイメントからのバックチャネル・リクエストは、ロンドンサイトのKeycloakサーバーでも終了します。 一方、米国のユーザーの場合、すべてのKeycloakリクエスト、アプリケーション・リクエスト、バックチャネル・リクエストはニューヨークサイトで処理されます。

  • offlineSessionsofflineClientSessions に対して、それは類似していますが、クライアント・アプリケーションのいずれに対してもオフライン・トークンを使用する予定ががない場合、それらをバックアップする必要はまったくありません。

一般的に、懸念があり、パフォーマンスがブロッカーではない場合は、キャッシュを SYNC 方式に保持する方が安全です。

SYNC/ASYNCバックアップへの切り替えに関しては、 backup 要素の strategy 属性を編集してください。たとえば、次のようになります。
<backup site="site2" failure-policy="FAIL" strategy="ASYNC" enabled="true">

cache-configuration要素の mode 属性に注意してください。

トラブルシューティング

以下のヒントは、トラブルシューティングが必要な場合に役立ちます。

  • Infinispan 9.4.19でのクロスサイト・レプリケーションの設定を行い、最初にこの機能を有効にして、どのように動作するかを理解することをお勧めします。物事を理解するためにこの文書全体を読むことも賢明です。

  • Infinispanサーバーのセットアップで説明されているように、jconsoleクラスターのステータス(GMS)とInfinispanのJGroupsのステータス(RELAY)をチェックインします。状況が期待どおりに見えない場合、問題はInfinispanサーバーの設定にある可能性があります。

  • Keycloakサーバーの場合、サーバーの起動時に次のようなメッセージが表示されます。

    18:09:30,156 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (ServerService Thread Pool -- 54)
    Node name: node11, Site name: site1

    Keycloakサーバーの起動時に、サイト名とノード名が想定どおりに表示されていることを確認してください。

  • 同じデータセンターのKeycloakサーバーだけが互いにクラスター化されていることを含め、Keycloakサーバーが期待どおりにクラスター内にあることを確認してください。これは、GMSビューを介してJConsoleでチェックすることもできます。詳細については、クラスターのトラブルシューティングを参照してください。

  • Keycloakサーバーの起動時に次のような例外が発生した場合、

    17:33:58,605 ERROR [org.infinispan.client.hotrod.impl.operations.RetryOnFailureOperation] (ServerService Thread Pool -- 59) ISPN004007: Exception encountered. Retry 10 out of 10: org.infinispan.client.hotrod.exceptions.TransportException:: Could not fetch transport
    ...
    Caused by: org.infinispan.client.hotrod.exceptions.TransportException:: Could not connect to server: 127.0.0.1:12232
            at org.infinispan.client.hotrod.impl.transport.tcp.TcpTransport.<init>(TcpTransport.java:82)

    これは通常、Keycloakサーバーが自身のデータセンター内のInfinispanサーバーにアクセスできないことを意味します。ファイアウォールが期待どおりに設定され、Infinispanサーバーが接続可能であることを確認してください。

  • Keycloakサーバーの起動時に次のような例外が発生した場合、

    16:44:18,321 WARN  [org.infinispan.client.hotrod.impl.protocol.Codec21] (ServerService Thread Pool -- 57) ISPN004005: Error received from the server: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction.
     ...

    サイトの該当するInfinispanサーバーのログをチェックし、他のサイトへのバックアップに失敗したかどうかを確認します。バックアップ・サイトが利用できない場合は、Infinispanサーバーがオフラインサイトにバックアップしようとしないようにオフラインに切り替えて、Keycloakサーバー側で正常に操作が成功するようにすることをお勧めします。詳細については、 クロスサイト・デプロイメントの管理 を参照してください。

  • JMXを介して利用可能なInfinispanの統計を確認してください。たとえば、ログインして、新しいセッションがInfinispanサーバーの両方に正常に書き込まれたかどうかを確認し、そこの sessions キャッシュで利用可能かどうかを確認します。これは、MBean jboss.datagrid-infinispan:type=Cache,name="sessions(repl_sync)",manager="clustered",component=StatisticsnumberOfEntries 属性の sessions キャッシュ内の要素の数をチェックすることによって間接的に行うことができます。ログイン後、両方のサイトのそれぞれのInfinispanサーバーに numberOfEntries の1つ以上のエントリーが存在するはずです。

  • Keycloakサーバーのセットアップの説明に従って、DEBUGロギングを有効にします。たとえば、ログインして2番目のサイトで新しいセッションが利用できないと思われる場合は、Keycloakサーバーログをチェックし、Keycloakサーバーのセットアップで説明したようにリスナーがトリガーされていることを確認してください。keycloak-userメーリングリストに質問したい場合は、電子メール内の両方のデータセンターのKeycloakサーバーからログファイルを送信すると便利です。ログスニペットをメールに追加するか、ログをどこかに置いて電子メールで参照してください。

  • site1 のKeycloakサーバーで user などのエンティティーを更新しても、 site2 のKeycloakサーバーで更新したエンティティーが表示されない場合は、同期したデータベース自体のレプリケーションか、Keycloakキャッシュが適切に無効化されなかったかのどちらかに問題があります。問題がデータベースのレプリケーション・レベルにある場合は、ここで説明するように一時的にKeycloakキャッシュを無効化してください。また、データベースに手動で接続し、データが期待どおりに更新されるかどうかを確認するのに役立ちます。これはすべてのデータベースに固有のものなので、データベースのドキュメントを参照する必要があります。

  • 場合によっては、Infinispanサーバーログに次のようなロックに関する例外が表示されることがあります。

    (HotRodServerHandler-6-35) ISPN000136: Error executing command ReplaceCommand,
    writing keys [[B0x033E243034396234..[39]]: org.infinispan.util.concurrent.TimeoutException: ISPN000299: Unable to acquire lock after
    0 milliseconds for key [B0x033E243034396234..[39] and requestor GlobalTx:server1:4353. Lock is held by GlobalTx:server1:4352

    これらの例外は必ずしも問題ではありません。両方のデータセンターで同じエンティティーの同時編集がトリガーされると、いつでも発生する可能性があります。これは、デプロイメントの多くの場合に当てはまります。たいてい、Keycloakサーバーは、失敗した操作について通知を受けて再試行するため、ユーザーの観点からは通常問題はありません。

  • Keycloakサーバーの起動時に次のような例外が発生した場合。

    16:44:18,321 WARN  [org.infinispan.client.hotrod.impl.protocol.Codec21] (ServerService Thread Pool -- 55) ISPN004005: Error received from the server: java.lang.SecurityException: ISPN000287: Unauthorized access: subject 'Subject with principal(s): []' lacks 'READ' permission
     ...

    これらのログエントリーはKeycloakの結果で、Infinispanで認証が必要かどうかを自動的に検出し、認証が必要であることを意味します。この時点で、サーバーが正常に起動され、これらを無視しても問題ないか、またはサーバーの起動に失敗していることに気づきます。サーバーの起動に失敗した場合は、Infinispanが Infinispanサーバーのセットアップ で説明されているように認証のために正しく設定されていることを確認してください。このログエントリーが含まれないように、 spi=connectionsInfinispan/provider=default の設定で remoteStoreSecurityEnabled プロパティーを true に設定して認証を強制できます。

    <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
        ...
        <spi name="connectionsInfinispan">
            ...
            <provider name="default" enabled="true">
                <properties>
                    ...
                    <property name="remoteStoreSecurityEnabled" value="true"/>
                </properties>
            </provider>
        </spi>
  • Keycloakでアプリケーションに認証しようとすると、ブラウザーの無限のリダイレクトで認証に失敗し、Keycloakサーバーログに次のようなエラーが表示されます。

    2017-11-27 14:50:31,587 WARN  [org.keycloak.events] (default task-17) type=LOGIN_ERROR, realmId=master, clientId=null, userId=null, ipAddress=aa.bb.cc.dd, error=expired_code, restart_after_timeout=true

    おそらく、スティッキー・セッションをサポートするようにロードバランサーを設定する必要があることを意味します。Keycloakサーバー起動中に使用される指定されたルート名(プロパティー jboss.node.name )に、 ロードバランサー・サーバーが現在のサーバーを識別するために使用する正しい名前が含まれていることを確認してください。

  • Infinispanの work キャッシュが無期限に増加した場合、 この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.xmlstandalone-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-providermyprovider と表示されています。しかし、この設定をどのように処理するかはSPIが決定します。SPIによって複数のプロバイダーを許可するものもあれば、そうでないものもあります。そのため、 default-provider はSPIの選択の手助けになります。

また、各プロバイダーが独自の設定プロパティーを定義することについても注意してください。上記の両方のプロバイダーが foo というプロパティーを持っている点は単なる偶然です。

プロパティー値のタイプはそれぞれプロバイダーによって解釈されます。ただし、1つ例外があります。 eventsStore のSPIの jpa プロバイダーについて確認してみましょう。

<spi name="eventsStore">
    <provider name="jpa" enabled="true">
        <properties>
            <property name="exclude-events" value="[&quot;EVENT1&quot;,
                                                    &quot;EVENT2&quot;]"/>
        </properties>
    </provider>
</spi>

この値は角括弧で始まり、角括弧で終わることが分かります。これは、値がリストとしてプロバイダーに渡されることを意味します。このサンプルでは、2つの要素値 EVENT1EVENT2 のリストはシステムからプロバイダーに渡されます。リストに値を追加するには、各リスト要素をカンマで区切ります。残念ながら、各リスト要素を囲む引用符を &quot; にエスケープする必要があります。

カスタム・プロバイダーとプロバイダーの設定の詳細については、Server Developer Guide の手順に従ってください。

WildFly CLIの起動

設定変更は、手作業で編集するだけでなく、 jboss-cli ツールでコマンドを発行して行うこともできます。CLIを使用すると、サーバーをローカルでもリモートでも設定することができます。スクリプティングと組み合わせると特に便利です。

WildFlyCLIを起動するには、 jboss-cli を実行する必要があります。

Linux/Unix
$ .../bin/jboss-cli.sh
Windows
> ...\bin\jboss-cli.bat

これを実行すると、以下のようにプロンプトが表示されます。

Prompt
[disconnected /]

実行中のサーバーでコマンドを実行する場合、まず connect コマンドを実行します。

接続
[disconnected /] connect
connect
[standalone@localhost:9990 /]

ここでユーザー名もパスワードも入力していないと思うかもしれませんが、 jboss-cli を実行中のスタンドアローン・サーバーまたはドメイン・コントローラーと同じマシンで実行し、アカウントに適切なファイル・アクセス権限がある場合は、管理者のユーザー名とパスワードを設定または入力する必要はありません。この設定では心配で、よりセキュアにしたい場合の詳細は、WildFly 23 Documentationを参照してください。

CLI組み込みモード

サーバーがアクティブではない間にスタンドアローン・サーバーと同じマシン上にコマンドが発行された場合は、サーバーをCLIに組み込み、受信要求を許可しない特殊モードに変更することができます。これを行うには、まず、変更したい設定ファイルで embed-server コマンドを実行します。

embed-server
[disconnected /] embed-server --server-config=standalone.xml
[standalone@embedded /]

CLI GUIモードの使用

CLIはGUIモードでも実行できます。GUIモードでは、実行中のサーバーの管理モデル全体をグラフィカルに表示および編集できるSwingアプリケーションが起動します。GUIモードは、CLIコマンドの書式を設定したり、オプションを調べる際のヘルプとして特に便利です。GUIは、ローカルまたはリモートサーバーからサーバーログを取得することもできます。

手順
  1. GUIモードでのCLIの起動

    $ .../bin/jboss-cli.sh --gui

    注意: リモートサーバーに接続するには、 --connect オプションも渡します。詳しくは、 --helpオプションを参照してください。

  2. スクロールダウンして、 subsystem=keycloak-server というノードを見つけます。

  3. ノードを右クリックして、 Explore subsystem=keycloak-server を選択します。

    新しいタブには、keycloak-serverサブシステムのみが表示されます。

    keycloak-serverサブシステム

    keycloak-server subsystem

CLIスクリプティング

CLIには、さまざまなスクリプト機能があります。スクリプトはCLIコマンドを含む単なるテキストファイルです。テーマとテンプレートのキャッシュをオフにする簡単なスクリプトを見ていきましょう。

turn-off-caching.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

サーバーのwebコンテキストの変更

/subsystem=keycloak-server/:write-attribute(name=web-context,value=myContext)

グローバルなデフォルトテーマの設定

**/theme=defaults/:write-attribute(name=default,value=myTheme)

新しいSPIとプロバイダーの追加

**/spi=mySPI/:add
**/spi=mySPI/provider=myProvider/:add(enabled=true)

プロバイダーの無効化

**/spi=mySPI/provider=myProvider/:write-attribute(name=enabled,value=false)

SPIのデフォルトプロバイダーの変更

**/spi=mySPI/:write-attribute(name=default-provider,value=myProvider)

dblock SPIの設定

**/spi=dblock/:add(default-provider=jpa)
**/spi=dblock/provider=jpa/:add(properties={lockWaitTimeout => "900"},enabled=true)

プロバイダーのシングル・プロパティー値の追加または変更

**/spi=dblock/provider=jpa/:map-put(name=properties,key=lockWaitTimeout,value=3)

プロバイダーからのシングル・プロパティーの削除

**/spi=dblock/provider=jpa/:map-remove(name=properties,key=lockRecheckTime)

List 型のプロバイダー・プロパティー値の設定

**/spi=eventsStore/provider=jpa/:map-put(name=properties,key=exclude-events,value=[EVENT1,EVENT2])

プロファイル

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

すべてのプレビュー機能を有効にするには、次のようにサーバーを起動します。

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を設定するために行う手順です。

  1. データベース用のJDBCドライバーの検索とダウンロード

  2. ドライバーのJARをモジュールにパッケージ化し、このモジュールをサーバーにインストール

  3. サーバーの設定プロファイルでJDBCドライバーを宣言

  4. データベースのJDBCドライバーを使用するようにデータソース設定を変更

  5. データベースへの接続パラメーターを定義するようにデータソース設定を変更

この章では、すべてのサンプルにおいてPostgreSQLを使用します。他のデータベースも同じ手順でインストールできます。

JDBCドライバーのパッケージ化

RDBMS用のJDBCドライバーのJARを検索してダウンロードします。このドライバーを使用する前に、モジュールにパッケージ化してサーバーにインストールする必要があります。モジュールによって、KeycloakのクラスパスにロードされるJAR、およびこれらのJARが他のモジュールに持つ依存関係が定義されます。

手順
  1. Keycloak配布ファイルの …​/modules/ ディレクトリー内に、モジュールの定義を格納するディレクトリー構造を作成してください。

    ディレクトリー構造の名前には、JDBCドライバーのJavaパッケージ名を使うのが一般的です。PostgreSQLの場合は、 org/postgresql/main というディレクトリーを作成します。

  2. データベース・ドライバーのJARをこのディレクトリーにコピーし、その中に空の module.xml ファイルを作成します。

    モジュール・ディレクトリー

    Module Directory

  3. 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/postgresqlorg.postgresql に対応します。

    • resource-root path 属性は、ドライバーのJARファイル名を指定します。

    • 残りの部分は、JDBCドライバーのJARが持っている通常の依存関係です。

JDBCドライバーの宣言とロード

JDBCをデプロイメント・プロファイルに宣言し、サーバー起動時にロードして利用できるようにします。

前提条件

JDBCドライバーをパッケージ化しました。

手順
  1. デプロイメント・モードに応じて、これらのファイルのいずれかを編集し、JDBCドライバーを宣言します。

    • スタンドアローン・モードでは、 …​/standalone/configuration/standalone.xml を編集します。

    • スタンドアローン・クラスタリング・モードの場合は、 …​/standalone/configuration/standalone-ha.xml を編集してください。

    • ドメインモードの場合は、 …​/domain/configuration/domain.xml を編集します。

      ドメインモードでは、使用しているプロファイル( auth-server-standalone または auth-server-clustered のいずれか)を編集することを確認してください。

  2. プロファイル内で、 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>
  3. 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ブロック内で行います。サンプルとして、新しいデータベースへの接続を設定すると以下のとおりになります。

JDBCドライバーの宣言
  <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ドライバーはすでに宣言しています。

手順
  1. KeycloakDSdatasource 定義を検索します。

    まず connection-url を変更する必要があります。この接続URL値の形式は、ベンダーのJDBC実装のドキュメントで指定されています。

  2. 次に、使用する driver を定義します。

    これは、この章の前のセクションで宣言したJDBCドライバーの論理名になります。

    トランザクションを実行するたびにデータベースへの新しい接続を開くのは処理コストがかかります。これを補うために、データソース実装は開いた接続のプールを維持します。 max-pool-size によって、プールする接続の最大数が指定されます。システムの負荷に応じて、この値を変更することができます。

  3. データベースへの接続に必要なデータベースのユーザー名とパスワードを定義します。このステップは少なくともPostgreSQLでは必要です。この例では、これらのクレデンシャルが平文で表示されていることが気になるかもしれません。これらのクレデンシャルを難読化する方法がありますが、その方法はこのガイドの範囲外です。

データソース機能について、詳しくは WildFly 23 Documentation 内のthe datasource configuration chapterを参照してください。

データベース設定

配布物内の standalone.xmlstandalone-ha.xmldomain.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

データベースの移行に使用する戦略。有効な値は updatemanualvalidate です。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.defaultNChartrue に設定する必要があります。厳密には必須ではないのですが、 oracle.jdbc.convertNcharLiterals 接続プロパティーも true にしておいた方が賢明です。これらのプロパティーは、システム・プロパティーまたは接続プロパティーとして設定することができます。しかし oracle.jdbc.defaultNChar の設定はパフォーマンスに悪影響を与える可能性がありますので、この点は注意してください。詳しくは、Oracle JDBCドライバーの設定ドキュメントを参照してください。

Microsoft SQL Serverデータベース

ユニコード文字は、特別なフィールドに対してのみ適切に処理されます。JDBCドライバーやデータベースの特別な設定は必要ありません。

MySQLデータベース

CREATE DATABASE コマンドで、 VARCHARCHAR のフィールド内のユニコード・サポートを使用してデータベースが作成される場合は、ユニコード文字は適切に処理されます(例: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_endpointtoken_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")

すべてのリクエストがパブリック・ドメイン名を通過するようにしたい場合は、 forceBackendUrlToFrontendUrltrue に設定することで、バックエンド・リクエストにもフロントエンドURLを使用させることができます。

個々のレルムのデフォルトのフロントエンドURLをオーバーライドすることもできます。これは管理コンソールで実施できます。

パブリック・ドメインで管理エンドポイントとコンソールを公開したくない場合は、プロパティー adminUrl を使用して、管理コンソールの固定URLを設定します。これは frontendUrl とは異なります。また、外部から /auth/admin へのアクセスをブロックする必要があります。その方法の詳細については、Server Administration Guideを参照してください。

カスタム・プロバイダー

カスタムのホスト名プロバイダーを開発するには、 org.keycloak.urls.HostnameProviderFactoryorg.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が無効でも、 localhost127.0.0.110.x.x.x192.168.x.x172.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を有効にする必要があります。これには下記が含まれます。

  1. SSL/HTTPトラフィック用の秘密鍵と証明書を含むキーストアの取得または生成

  2. このキーペアと証明書を使用するための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 から無料で取得することができます。ただし、その前に以下の手順が必要となります。

手順
  1. 証明書要求の生成

    $ 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-----
  2. このCAリクエストを認証局(CA)に送信します。

    CAは署名入りの証明書を発行し、あなたに送ります。

  3. CAのルート証明書を入手してインポートする。

    CAから証明書をダウンロードして(つまり、root.crt)、以下のようにインポートすることができます。

    $ keytool -import -keystore keycloak.jks -file root.crt -alias root
  4. 新しいCAが生成した証明書をキーストアにインポートします。

    $ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer
キーストアを使用するためのKeycloak設定

適切な証明書を含むJavaキーストアができたので、それを使用するためにKeycloakのインストール環境を設定する必要があります。

手順
  1. キーストアを使用し、HTTPSを有効にするために、standalone.xmlstandalone-ha.xmlhost.xml のいずれかのファイルを編集します。

  2. キーストアファイルをデプロイメントの configuration/ ディレクトリーに移動するか、またはファイルを任意の場所に移動し、そこへの絶対パスを指定してください。

    絶対パスを使用する場合は、オプションの relative-to パラメーターを設定から削除してください(operating modeを参照してください)。

  3. 次のように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)
  4. 作成した 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.xmlstandalone-ha.xml または domain.xml 内で少し設定する必要があります。このファイルの場所は、動作モードによって異なります。

HTTPクライアント設定のサンプル
<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 コマンドの結果、以下のサブシステム設定になります。 &quot;" 文字をエンコードする必要があることに注意してください。

<spi name="connectionsHttpClient">
    <provider name="default" enabled="true">
        <properties>
            <property
            name="proxy-mappings"
            value="[&quot;.*\\.(google|googleapis)\\.com;http://www-proxy.acme.com:8080&quot;,&quot;.*\\.acme\\.com;NO_PROXY&quot;,&quot;.*;http://fallback:8080&quot;]"/>
        </properties>
    </provider>
</spi>

標準的な環境変数の使用

代わりに,標準的な環境変数を使ってプロキシー・マッピングを設定することも可能です( HTTP_PROXYHTTPS_PROXYNO_PROXY )。

変数 HTTP_PROXYHTTPS_PROXY は、すべての送信HTTPリクエストに使用されるべきプロキシーサーバーを表しています。 Keycloakは、両者の間に違いはありません。両方が指定された場合は、プロキシーサーバーが実際に使用するスキームに関わらず、HTTPS_PROXY が優先されます。

NO_PROXY 変数は、プロキシーを使用してはいけないホスト名のリストをカンマ区切りで定義するのに使われます。ホスト名が指定された場合、そのすべてのプレフィックス(サブドメイン)もプロキシーの使用から除外されます。

次のような例があります。

HTTPS_PROXY=https://www-proxy.acme.com:8080
NO_PROXY=google.com,login.facebook.com

この例では、たとえば login.google.comgoogle.comauth.login.facebook.com へのリクエストを除き、すべての送信HTTPリクエストが https://www-proxy.acme.com:8080 プロキシー・サーバーを使用します。ただし、たとえば groups.facebook.com などのリクエストはプロキシーを経由します。

環境変数は、小文字でも大文字でもOKです。小文字の方が優先されます。たとえば、 HTTP_PROXYhttp_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.xmlstandalone-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マルチキャストなしでもKeycloakをクラスター構成にすることは可能ですが、このトピックについてはこのガイドの範囲を超えています。詳しくは、 WildFly 23 DocumentationJGroupsを参照してください。

Keycloakをデプロイするための推奨ネットワーク・アーキテクチャーは、パブリックIPアドレスを持つHTTP/HTTPSロードバランサーを配置し、プライベート・ネットワーク上のKeycloakサーバーへのリクエストをルーティングさせます。これにより、クラスタリング接続はすべて分離され、サーバーを保護する優れた手段が提供されます。

デフォルトでは、許可されていないノードがクラスターに加わり、マルチキャスト・メッセージをブロードキャストするのを防ぐものは何もありません。このため、クラスター・ノードはプライベート・ネットワーク内に置かれ、ファイアウォールによって外部の攻撃から保護される必要があります。

クラスタリングの例

Keycloakには、ドメインモードでそのまま利用できるクラスタリングのデモが付属しています。詳しくはクラスター構成ドメインのサンプルの章を参照してください。

ロードバランサーまたはプロキシーの設定

このセクションでは、クラスター構成のKeycloakの前にリバース・プロキシーまたはロードバランサーを配置するにあたって、設定が必要な項目について説明します。また、組み込みのロードバランサーの設定についても説明します。これはクラスター構成ドメインのサンプルでも確認できます。

次の図は、ロードバランサーの使用方法を示しています。この例では、ロードバランサーは、3つのクライアントと3つのKeycloakサーバーのクラスター間のリバースプロキシーとして機能します。

ロードバランサーの例の図

load balancer

クライアントIPアドレスの特定

Keycloakのいくつかの機能は、認証サーバーに接続するHTTPクライアントのリモート・アドレスがクライアント・マシンの実際のIPアドレスであることを前提としています。例は、以下のとおりです。

  • イベントログ - 間違ったソースIPアドレスでログインエラーが記録されます

  • SSLの要求 - SSLの要求がexternal(デフォルト)に設定されている場合、すべての外部リクエストに対してSSLを要求します

  • 認証フロー - IPアドレスを使用して、たとえば外部リクエストに対してのみOTPを表示するようなカスタム認証フロー

  • 動的クライアント登録

Keycloak認証サーバーの前にリバース・プロキシーまたはロードバランサーが置いてある場合、問題になる可能性があります。通常の設定では、パブリック・ネットワーク上にフロントエンドのプロキシーを置いています。このプロキシーはプライベート・ネットワーク内のバックエンドのKeycloakサーバー・インスタンスに負荷を分散してリクエストを転送するものです。実際のクライアントIPアドレスが転送され、Keycloakサーバー・インスタンスによって処理されるように、追加設定する必要があります。具体的には以下のとおりです。

  • X-Forwarded-ForX-Forwarded-Proto HTTPヘッダーを適切にセットするように、リバース・プロキシーまたはロードバランサーを設定します。

  • オリジナルの 'Host' HTTPヘッダーを保持するように、リバース・プロキシーまたはロードバランサーを設定します。

  • X-Forwarded-For ヘッダーからクライアントのIPアドレスを読み取るように、認証サーバーを設定します。

X-Forwarded-ForX-Forwarded-Proto HTTPヘッダーを生成するためにプロキシーを設定し、オリジナルの Host HTTPヘッダーを保持する方法については、このガイドの説明範囲を超えています。 X-Forwarded-For ヘッダーがプロキシーによって設定されているか、特に注意して確認してください。プロキシーが正しく設定されていない場合、不正な クライアントがこのヘッダーを自身で設定して、クライアントが実際とは異なるIPアドレスから接続しているとKeycloakに認識させることができてしまいます。IPアドレスのブラックリストまたはホワイトリストを作成している場合、この設定は非常に重要です。

プロキシーの他にも、いくつかKeycloak側で設定する必要があります。プロキシーがHTTPプロトコル経由でリクエストを転送している場合、クライアントのIPアドレスをネットワーク・パケットからではなく X-Forwarded-For ヘッダーから取得するように、Keycloakを設定する必要があります。これを行うには、プロファイル設定ファイル(動作モードに応じて standalone.xmlstandalone-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>
手順
  1. http-listener 要素に redirect-socket 属性を追加します。値には proxy-https を設定しますが、これは定義が必要なソケット・バインディングを指しています。

  2. 新しい 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>

設定内容の確認

リバース・プロキシーやロードバランサーの設定を確認することができます。

手順
  1. リバース・プロキシー経由でパス /auth/realms/master/.well-known/openid-configuration を開きます。

    たとえば、リバース・プロキシーのアドレスが https://acme.com/ であれば、 https://acme.com/auth/realms/master/.well-known/openid-configuration を開きます。そうすると、KeycloakのエンドポイントをいくつかリストアップしたJSONドキュメントが表示されます。

  2. エンドポイントが、リバース・プロキシーやロードバランサーのアドレス(スキーム、ドメイン、ポート)で始まっていることを確認してください。これにより、Keycloak が正しいエンドポイントを使用していることが確認できます。

  3. 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
  4. ipAddress の値が、リバース・プロキシーやロードバランサーのIPアドレスではなく、ログインしようとしたマシンのIPアドレスであることを確認してください。

組み込みロードバランサーの使用

このセクションでは、クラスター構成ドメインのサンプルで説明している組み込みのロードバランサーの設定方法について説明します。

クラスター構成ドメインのサンプルは1台のマシンで実行するためにのみ作られています。他のホストでスレーブを起動するには、次の操作が必要です。

  1. 新しいホスト・スレーブを指し示すように、 domain.xml ファイルを編集します。

  2. サーバー配布物をコピーします。 domain.xmlhost.xml または host-master.xml は必要ありません。 standalone/ ディレクトリーも必要ありません。

  3. 使用しているバインドアドレスを変更、またはコマンドラインでそのアドレスを上書きするように、 host-slave.xml ファイルを編集します。

手順
  1. domain.xml を開き、新しいホストスレーブをロードバランサーの設定に登録できるようにします。

  2. 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-bindingdomain.xml 内で後ほど設定する socket-binding を指す論理名です。 instance-id 属性の値は、負荷を分散する時にスティッキー・セッションを有効にできるようにCookieで使用されるため、新しいホスト固有のものでなければなりません。

  3. load-balancer-sockets socket-binding-group に進み、 remote-host3outbound-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>
マスターバインドアドレス

次に、マスターホスト用の publicmanagement バインドアドレスを変更する必要があります。バインドアドレス内で説明した domain.xml ファイルを編集するか、以下のとおりコマンドライン上でこれらのバインドアドレスを指定します。

$ domain.sh --host-config=host-master.xml -Djboss.bind.address=192.168.0.2 -Djboss.bind.address.management=192.168.0.2
ホスト・スレーブ・バインドアドレス

次は、 publicmanagement 、ドメイン・コントローラー・バインドアドレス( 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.addressjboss.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> のような形式のCookie AUTH_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を持つプライベート・ネットワーク・インターフェースにバインドされています。

手順
  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>
  2. クラスタリングスタック上のサービスのポートと同様に、 jboss.bind.address.privatejboss.default.multicast.address を設定します。

    IPマルチキャストなしでKeycloakをクラスタリングすることは可能ですが、このトピックはこのガイドの説明範囲を超えています。詳しくは、 WildFly 23 Documentation 内の JGroups を参照してください。

クラスター通信のセキュリティー保護

クラスター・ノードがプライベート・ネットワークで隔離されている場合は、クラスターに参加したり、クラスター内の通信を表示したりするために、プライベート・ネットワークへのアクセスが必要です。また、クラスター通信の認証と暗号化を有効にすることもできます。プライベート・ネットワークが安全である限り、認証と暗号化を有効にする必要はありません。どちらの場合も、Keycloakはクラスター上で機密情報を送信しません。

クラスタリング通信の認証と暗号化を有効にする場合は、 WildFly documentation にある’High Availability Guide’を参照してください。

シリアライズされたクラスターの起動

Keycloakクラスター・ノードは並行して起動することができます。Keycloakサーバー・インスタンスが起動すると、データベースの移行、インポート、初回の初期化を行います。DBロックは、クラスター・ノードが同時に起動した場合、起動アクションが競合するのを防ぐために使用されます。

デフォルトでは、このロックの最大タイムアウトは900秒です。ノードがこのタイムアウト時間を超えてロック状態のままだった場合、起動は失敗します。通常は、デフォルト値を増減する必要はありません。しかし、配布物内の standalone.xmlstandalone-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 DocumentationJGroupsを参照してください。

  • フェイルオーバーのサポート(高可用性)、エビクション、有効期限およびキャッシュ・チューニングに関心がある場合は、サーバー・キャッシュ設定を参照してください。

サーバー・キャッシュ設定

Keycloakには、2つのタイプのキャッシュがあります。1つ目のキャッシュは、データベースの前に置かれていて、DBの負荷を減らし、データをメモリーに保持することで全体の応答時間を短縮します。レルム、クライアント、ロール、およびユーザー・メタデータは、このタイプのキャッシュに保持されます。このキャッシュはローカル・キャッシュです。クラスターにより多くのKeycloakサーバーがある場合でも、ローカル・キャッシュはレプリケーションを使用しません。その代わり、ローカル・キャッシュはローカルにのみコピーを保持し、エントリーが更新された場合は無効化メッセージが残りのクラスターに送られてエントリーは追い出されます。これとは別にレプリケーションされるキャッシュ work があります。これは、どのエントリーがローカル・キャッシュから取り除かれるかについて、クラスター全体に無効化メッセージを送信するタスクになります。これによって、ネットワーク・トラフィックが大幅に減少し、効率化され、機密なメタデータのネットワーク経由での送信が回避されます。

2つ目のキャッシュは、ユーザー・セッション、オフライン・トークン、ログイン・エラーの履歴保持の管理を担当し、サーバーがパスワード・フィッシングやその他の攻撃を検出できるようにします。これらのキャッシュ内のデータは一時的で、メモリーにのみ保持されるものですが、クラスター全体にレプリケーションされる可能性があります。

この章では、クラスター構成と非クラスター構成の両方のためのキャッシュ用設定オプションについて説明します。

これらのキャッシュのより高度な設定については、 WildFly 23 DocumentationInfinispanのセクションを参照してください。

退避と有効期限

Keycloakには、さまざまなキャッシュの設定があります。その一つにレルムキャッシュというものがあり、セキュリティー保護されたアプリケーション、一般的なセキュリティー・データおよび設定オプションに関する情報を保持しています。また、ユーザー・メタデータを含むユーザー・キャッシュがあります。このキャッシュのデフォルト値は最大10000エントリーで、最近最も使われなかったものを退避する戦略が使用されます。また、これらのキャッシュはそれぞれ、クラスター構成内での退避を制御するオブジェクト・リビジョン・キャッシュにも関連付けられています。このキャッシュは暗黙的に作成され、設定されたサイズの2倍のサイズがあります。認可データを保持する authorization キャッシュについても同様です。 keys キャッシュは外部キーに関するデータを保持し、専用のリビジョン・キャッシュを保持する必要はありません。それはむしろ明示的に expiration が宣言されているので、キーは定期的に期限切れとなり、外部のクライアントやアイデンティティー・プロバイダーから定期的にダウンロードされます。

これらのキャッシュの退避ポリシーと最大エントリーは、動作モードに応じて standalone.xmlstandalone-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 要素を追加または編集するだけでできます。

さらに、 sessionsclientSessionsofflineSessionsofflineClientSessionsloginFailuresactionTokens といったキャッシュもあります。これらのキャッシュはクラスター環境で分散され、デフォルトではサイズが制限されていません。制限がある場合、一部のセッションが失われる可能性があります。制限なしにこれらのキャッシュサイズが増大することを避けるために、期限切れのセッションはKeycloak自身によって内部的にクリアされます。多数のセッションが原因でメモリーの問題が発生した場合は、次の操作を試すことができます。

  • クラスターのサイズを大きくします(クラスター内のノードが多いほど、セッションはノード間でより均等に分散されます)

  • Keycloakサーバープロセスのメモリーを増やします

  • キャッシュが1つの場所に保存されるように、所有者の数を減らします。詳細はレプリケーションとフェイルオーバーを参照してください

  • 分散キャッシュのl1-lifespanを無効にします。詳細については、Infinispanのマニュアルを参照してください。

  • セッション・タイムアウトを減らします。これはKeycloak管理コンソールの各レルムで個別に実行できます。しかし、これはエンドユーザーのユーザビリティーに影響する可能性があります。詳細については、 Timeouts を参照してください。

クラスターノード間でメッセージを送信するために主に使用される追加のレプリケーション・キャッシュ work があります。デフォルトでは無制限です。ただし、このキャッシュ内のエントリーは非常に短期間であるため、このキャッシュがメモリーの問題を引き起こすことはありません。

レプリケーションとフェイルオーバー

sessionsauthenticationSessionsofflineSessionsloginFailures などのキャッシュがあります(詳細は退避と有効期限を参照)。クラスター化された設定を使用するときは分散キャッシュとして設定されます。エントリーはすべてのノードにひとつひとつレプリケーションされるわけではありませんが、1つ以上のノードがそのデータの所有者として選ばれます。ノードが特定のキャッシュ・エントリーの所有者ではない場合は、そのキャッシュ・エントリーを取得するためにクラスターに問い合わせをします。これがフェイルオーバーに対して何を意味するかというと、データを保持しているノードがすべてダウンした場合は、そのデータは永遠に失われてしまうということです。デフォルトでは、Keycloakが指定するデータの所有者は1つだけです。そのため、その1つのノードがダウンした場合は、そのデータは失われることになります。このことは通常、ユーザーはログアウトされ、再度ログインし直さなければならないということを意味します。

distributed-cache の宣言で owners 属性を変更すると、データをレプリケートするノードの数を変更することができます。

owners
<subsystem xmlns="urn:jboss:domain:infinispan:12.0">
   <cache-container name="keycloak">
       <distributed-cache name="sessions" owners="2"/>
...

ここで上記のとおりに変更すると、少なくとも2つのノードが1つの特定のユーザー・ログイン・セッションをレプリケーションします。

推奨される所有者数は、構成によって異なります。ノードがダウンした時にユーザーがログアウトされてもされなくても良い場合は、所有者は1つで十分であり、レプリケーションを避けることができます。
スティッキー・セッションでロードバランサーを使用するように環境を設定することは、一般的には賢明です。通常は、特定のリクエストが処理されるKeycloakサーバーが分散キャッシュデータの所有者であるため、ローカルでデータをルックアップできますので、パフォーマンスを向上させるために有益です。詳細はスティッキー・セッションを参照してください。

キャッシングの無効化

レルムキャッシュやユーザーキャッシュを無効にすることができます。

手順
  1. 配布物内の standalone.xmlstandalone-ha.xmldomain.xml ファイルを編集します。

    このファイルの場所は、動作モードに依存します。以下に設定ファイルのサンプルを示します。

        <spi name="userCache">
            <provider name="default" enabled="true"/>
        </spi>
    
        <spi name="realmCache">
            <provider name="default" enabled="true"/>
        </spi>
  2. 無効にしたいキャッシュの enabled 属性をfalseに設定します。

  3. この変更を有効にするには、サーバーを再起動してください。

実行時のキャッシュクリア

レルムキャッシュ、ユーザーキャッシュ、外部の公開鍵のいずれかをクリアすることができます。

手順
  1. 管理コンソールにログインします。

  2. Realm Settings をクリックします。

  3. Cache タブをクリックします。

  4. レルムキャッシュ、ユーザーキャッシュ、外部の公開鍵のキャッシュをクリアします。

すべてのレルムのキャッシュがクリアされます。

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クラスターでこの手順を実行します。

  1. OpenShift Container Platform Webコンソールを開きます。

  2. 左側の列で、 Operators, OperatorHub をクリックします。

  3. Keycloak Operatorを検索します。

    OpenShiftのOperatorHubタブ

    operator openshift operatorhub

  4. Keycloakオペレーター・アイコンをクリックします。

    インストール・ページが開きます。

    OpenShiftのOperatorインストール・ページ

    operator olm installation

  5. Install をクリックします。

  6. ネームスペースを選択し、Subscribeをクリックします。

    OpenShiftでのネームスペースの選択

    installed namespace

    Operatorがインストールを開始します。

追加のリソース
Kubernetesクラスターへのインストール
前提条件
  • cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順

Kubernetesクラスターの場合、次の手順を実行します。

  1. Keycloak Operator on OperatorHub.io に移動します。

  2. Install をクリックします。

  3. 画面の指示に従ってください。

    KubernetesのOperatorインストール・ページ

    operator operatorhub install

追加のリソース

コマンドラインからのインストール

コマンドラインからKeycloak Operatorをインストールできます。

前提条件
  • cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. 次の場所からインストールするソフトウェアを入手してください。Github repo

  2. 必要なすべてのカスタムリソース定義をインストールします。

    $ kubectl apply -f deploy/crds/
  3. ネームスペース myproject などの新しいネームスペースを作成(または既存のネームスペースを再利用)します。

    $ kubectl create namespace myproject
  4. 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
  5. Operatorを配置します。

    $ kubectl apply -f deploy/operator.yaml -n myproject
  6. Operatorが実行されていることを確認します。

    $ kubectl get deployment keycloak-operator -n myproject
    NAME                READY   UP-TO-DATE   AVAILABLE   AGE
    keycloak-operator   1/1     1            1           41s
    追加のリソース

プロダクション環境でのKeycloak Operatorの使用

  • プロダクション環境では、組み込みDBの使用はサポートされていません。

  • バックアップCRDは非推奨で、プロダクション環境ではサポートされていません。

  • 我々は、 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パーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. documentation を使用してApplication Monitoring Operatorをインストールします。

  2. Keycloak Operatorのインストールに使用されるネームスペースに注釈を付けます。例:

    kubectl label namespace <namespace> monitoring-key=middleware
  3. OpenShift Webコンソールにログインします。

  4. application-monitoring ネームスペースの中のPrometheusおよびGrafanaルートを検索して、モニタリングが機能していることを確認します。

    OpenShift Webコンソールでのルート

    operator application monitoring routes

Operatorメトリクスの表示

GrafanaとPrometheusはそれぞれ、Operatorアクティビティーに関するグラフィカルな情報を提供します。

  • Operatorは、次のような事前定義されたGrafanaダッシュボードをインストールします。

    Grafanaダッシュボード

    operator graphana dashboard

    カスタマイズを行う場合は、アップグレード中に変更が上書きされないように、Grafanaダッシュボードを複製することをお勧めします。

  • Operatorは、以下に示すように、事前定義されたPrometheusアラートのセットをインストールします。

    Prometheusアラート

    operator prometheus alerts

追加のリソース

詳細については、 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

Operatorコンポーネントとサービスの相互作用

operator components

Keycloakカスタムリソース

Keycloakカスタムリソースは、インストール用のパラメーターを定義するYAMLファイルです。このファイルには3つのプロパティーが含まれています。

  • instances - 高可用性モードで実行されているインスタンスの数を制御します。

  • externalAccess - enabledTrue の場合、OperatorはOpenShiftのルートまたはKeycloakクラスターのKubernetesのIngressを作成します。Routeに自動的に選択されたホスト名を上書きするように host を設定するか、Ingressにデフォルト値の keycloak.local を設定できます。

  • externalDatabase - 外部でホストされているデータベースに接続するために使用します。これについては、このガイドの 外部データベース の項で説明します。これをfalseに設定すると、組み込み式のPostgreSQLデータベースがインストールされますので、テスト目的でのみ使用してください。externalDatabase:falseは本番環境ではサポートされていないことに注意してください。

Keycloakカスタム・リソースのYAMLファイルの例
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 を参照してください。

手順
  1. kubectl apply -f <filename>.yaml -n <namespace> のようにYAMLファイルを使用してルートを作成します。たとえば、

    $ kubectl apply -f keycloak.yaml -n keycloak
    keycloak.keycloak.org/example-keycloak created

    OpenShiftにルートが作成されます。

  2. OpenShift Webコンソールにログインします。

  3. NetworkingRoutes を選択し、Keycloakを検索します。

    OpenShift Webコンソールのルーティング画面

    route ocp

  4. Keycloakルートのある画面で、 Location の下のURLをクリックします。

    Keycloak管理コンソールのログイン画面が表示されます。

    管理コンソールのログイン画面

    login empty

  5. OpenShift Webコンソールで管理コンソールのユーザー名とパスワードを見つけます。 WorkloadsSecrets をクリックし、Keycloakを検索します。

    OpenShift Webコンソールのシークレット画面

    secrets ocp

  6. ユーザー名とパスワードを管理コンソールのログイン画面に入力します。

    管理コンソールのログイン画面

    login complete

    これで、KeycloakカスタムリソースによってインストールされたKeycloakのインスタンスにログインしました。レルム、クライアント、およびユーザー用のカスタムリソースを作成する準備が整いました。

    Keycloak masterレルム

    new install cr

  7. カスタムリソースのステータスを確認します。

    $ kubectl describe keycloak <CR-name>

KubernetesでKeycloakカスタムリソースを作成する

Kubernetesでは、カスタムリソースを使用して、管理コンソールのIPアドレスであるingressを作成し、そのコンソールのユーザー名とパスワードを保持するシークレットを見つけます。

前提条件
  • このカスタムリソース用のYAMLファイルがあること。

  • cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. kubectl apply -f <filename>.yaml -n <namespace> のようにYAMLファイルを使用してingressを作成します。たとえば、

    $ kubectl apply -f keycloak.yaml -n keycloak
    keycloak.keycloak.org/example-keycloak created
  2. 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
  3. ADDRESS(ingress)をコピーしてWebブラウザーに貼り付けます。

    Keycloak管理コンソールのログイン画面が表示されます。

    管理コンソールのログイン画面

    login empty

  4. ユーザー名とパスワードを見つけます。

    $ 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}}'
  5. ユーザー名とパスワードを管理コンソールのログイン画面に入力します。

    管理コンソールのログイン画面

    login complete

    これで、KeycloakカスタムリソースによってインストールされたKeycloakのインスタンスにログインしました。レルム、クライアント、およびユーザー用のカスタムリソースを作成する準備が整いました。

    管理コンソールmasterレルム

    new install cr

結果

Operatorがカスタムリソースを処理したら、次のコマンドでステータスを表示します。

$ kubectl describe keycloak <CR-name>
Keycloakカスタムリソースのステータス
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パーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. 作成したYAMLファイルで kubectl apply -f <realm-name>.yaml のコマンドを使用します。たとえば、

    $ kubectl apply -f initial_realm.yaml
    keycloak.keycloak.org/test created
  2. Keycloakの関連インスタンスの管理コンソールにログインします。

  3. Select Realmをクリックして、作成したレルムを見つけます。

    新規レルムが開きます。

    管理コンソールmasterレルム

    test realm cr

結果

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管理コンソールに変更が表示されますが、管理コンソールで変更しても、カスタムリソースは更新されません。

クライアント・カスタム・リソースのYAMLファイルの例
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パーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. 作成したYAMLファイルで kubectl apply -f <client-name>.yaml のコマンドを使用します。たとえば、

    $ kubectl apply -f initial_client.yaml
    keycloak.keycloak.org/example-client created
  2. Keycloakの関連インスタンスのKeycloak管理コンソールにログインします。

  3. Clientsをクリックします。

    新しいクライアントがクライアントの一覧に表示されます。

    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管理コンソールに表示されますが、管理コンソールを変更してもカスタムリソースは更新されません。

ユーザー・カスタム・リソースのYAMLファイルの例
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パーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. 作成したYAMLファイルで kubectl apply -f 1.yaml のコマンドを使用します。たとえば、

    $ kubectl apply -f initial_user.yaml
    keycloak.keycloak.org/example-user created
  2. Keycloakの関連インスタンスの管理コンソールにログインします。

  3. Usersをクリックします。

  4. YAMLファイルで定義したユーザーを検索します。

    ユーザーを見つけるには、別のレルムに切り替える必要があるかもしれません。

    realm user.

結果

ユーザーが作成されると、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>
追加のリソース

外部データベースへの接続

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カスタムリソースを変更して、 externalDatabasetrue に設定しました。

  • cluster-adminパーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. 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形式です。

  2. echo "<encoded_secret>" | base64 -decode のようにシークレットの値をデコードします。たとえば、

    $ echo "MTcyLjE3LjAuMw==" | base64 -decode
    192.0.2.3
  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
  4. 実行中のサービスのリストに 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アドレスはエンドポイントと呼ばれます。

  5. keycloak-postgresql サービスで使用されるエンドポイントを表示して、データベースのIPアドレスを使用していることを確認します。

    $ kubectl get endpoints keycloak-postgresql
    NAME                  ENDPOINTS         AGE
    keycloak-postgresql   192.0.2.3.5432    27m
  6. 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
追加のリソース

外部Keycloakへの接続

このオペレーターは、外部のKeycloakインスタンスを部分的に管理するためにも使用できます。現在の状態では、クライアントを作成することしかできません。

そのためには、ターゲティングや設定に使用するアンマネージド版の KeycloakKeycloakRealm の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回または定期的にバックアップできます。データを定期的にバックアップするには、有効な CronJobschedule に入力してください。

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ファイルが必要です。

AWS S3 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パーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. kubectl apply -f <secret_for_aws>.yaml のようにクレデンシャルを使用してシークレットを作成します。たとえば、

    $ kubectl apply -f secret.yaml
    keycloak.keycloak.org/aws_s3_secret created
  2. kubectl apply -f <secret_for_aws>.yaml のようにバックアップジョブを作成します。たとえば、

    $ kubectl apply -f aws_one-time-backup.yaml
    keycloak.keycloak.org/aws_s3_backup created
  3. 次のようにバックアップジョブの一覧を表示します。

    $ kubectl get jobs
    NAME                   COMPLETIONS     DURATION     AGE
    aws_s3_backup    0/1             6s           6s
  4. 実行されたバックアップ・ジョブの一覧を表示します。

    $ 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
  5. 次のように完了したバックアップ・ジョブのログを表示します。

    $ kubectl logs aws_s3_backup-5b4rf
    ==> Component data dump completed
    .
    .
    .
    .
    [source,bash,subs=+attributes]

バックアップ・ジョブのステータスは、AWSコンソールにも表示されます。

ローカル・ストレージへのバックアップ

Operatorを使用して、ローカルのPersistent Volumeへの1回限りのバックアップを実行するバックアップ・ジョブを作成できます。

Backupカスタム・リソースのYAMLファイルの例
apiVersion: keycloak.org/v1alpha1
kind: KeycloakBackup
metadata:
  name: test-backup
前提条件
  • このカスタムリソース用のYAMLファイルがあること。このファイルから aws サブプロパティーを省略するようにしてください。

  • Keycloak Operatorによって作成された PersistentVolumeClaim に対してのみ予約するために、 claimRef とともに PersistentVolume があります。

手順
  1. kubectl apply -f <backup_crname> のようにバックアップジョブを作成します。たとえば、

    $ kubectl apply -f one-time-backup.yaml
    keycloak.keycloak.org/test-backup

    Operatorは Keycloak-backup-<CR-name> の命名スキームで PersistentVolumeClaim を作成します。

  2. ボリュームの一覧を表示します。

    $ 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
  3. 次のようにバックアップジョブの一覧を表示します。

    $ kubectl get jobs
    NAME           COMPLETIONS     DURATION     AGE
    test-backup    0/1             6s           6s
  4. 実行されたバックアップ・ジョブの一覧を表示します。

    $ 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
  5. 次のように完了したバックアップ・ジョブのログを表示します。

    $ kubectl logs test-backup-5b4rf
    ==> Component data dump completed
    .
    .
    .
    .
追加のリソース

拡張機能とテーマのインストール

Operatorを使用して、会社または組織に必要な拡張機能とテーマをインストールできます。拡張機能またはテーマは、Keycloakが使用できるものであれば何でもかまいません。たとえば、メトリクス拡張を追加できます。Keycloakカスタムリソースに拡張機能またはテーマを追加します。

Keycloakカスタム・リソースのYAMLファイルの例
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パーミッションまたは同等のレベルのパーミッションが管理者によって付与されていること。

手順
  1. kubectl edit <CR-name> のようにKeycloakカスタムリソースのYAMLファイルを編集します。

  2. extensions: という行を instances 行の後に追加します。

  3. カスタム拡張機能またはテーマのJARファイルにURLを追加します。

  4. ファイルを保存します。

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のバージョンによって同時にアクセスされるため、データベースの移行を必要としないマイナー・バージョンのアップグレードに適しています。この戦略では、自動バックアップはサポートされていません。

Keycloakカスタム・リソースのYAMLファイルの例
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
追加のリソース

1. Tracked as https://issues.redhat.com/browse/KEYCLOAK-3873
2. Tracked as https://issues.redhat.com/browse/KEYCLOAK-3873
3. Tracked as https://issues.redhat.com/browse/KEYCLOAK-3873
4. Tracked as https://issues.redhat.com/browse/KEYCLOAK-3873
5. https://issues.redhat.com/browse/KEYCLOAK-3873として追跡