AWS上でKeycloakを冗長化するとき、詰まるのはALBの前段ではなく、その裏側のInfinispanクラスタ形成とセッションキャッシュの挙動です。本稿ではQuarkus版を基準に、ノード発見・sticky session・AZ分散・ヘルスチェックの現実を整理します。

Keycloakを1台で立てるのは簡単です。難しいのは「落ちても止まらない」構成にした瞬間、裏側のInfinispanクラスタとセッションキャッシュの挙動を正しく理解していないと、フェイルオーバー時にユーザーが再ログインを強いられたり、ノードが互いを見つけられずクラスタが形成されなかったりする点です。本稿はAWS上でKeycloak(現行のQuarkusベース、いわゆるKeycloak.X系)をHA構成にする際の実務的な勘所を、公式ドキュメントの一次情報を引きながら整理します。バージョン依存の挙動は新しめのバージョン(26系前後)を基準にしていますが、採用時は必ず自環境のバージョンの公式ドキュメントで確認してください。

01全体像 — ALB配下に複数ノードを並べる

基本形はシンプルです。ALB(Application Load Balancer)を前段に置き、その配下に複数のKeycloakノード(EC2、ECS、EKSいずれでも)を並べ、バックエンドにRDS/Auroraを共有DBとして置きます。Keycloakノード同士はInfinispanで分散キャッシュを組み、セッションやトークン失効情報を共有します。ここでのポイントは、Keycloakは「ステートレスなWebアプリ+ステートフルな分散キャッシュ」という二層構造を1プロセス内に抱えていることです。HTTPトラフィックはALBが捌きますが、ノード間のキャッシュ同期は別の経路(JGroups)で流れます。この二経路を両方とも設計対象にする、というのが最初の認識合わせです。

ALB (HTTPS) AZ-a AZ-c Keycloak node 1 Keycloak node 2 JGroups 7800 共有DB RDS / Aurora (Multi-AZ)
図:ALB配下に2AZ分散でKeycloakノードを並べ、JDBC_PING経由でJGroupsクラスタを形成、共有DBをMulti-AZで置く基本形。

02ALBの前段 — TLS終端とプロキシヘッダ

ALBでTLSを終端し、バックエンドにはHTTP(あるいは内部TLS)で流す構成が一般的です。このとき必ず設定するのが、Keycloakにプロキシ経由であることを伝えるヘッダ処理です。Keycloakは自分が生成するリダイレクトURL(認可エンドポイントやトークンエンドポイントのissuer)を、受け取ったリクエストのホスト情報から組み立てます。プロキシ配下だと元のホスト・スキームが失われるため、ALBが付与するX-Forwarded-*ヘッダを信頼するよう明示する必要があります。

現場のコツ:「ログイン画面は出るがリダイレクトでコケる」「issuerが内部IPになっている」系のトラブルは、ほぼ100%このプロキシヘッダ設定かホスト名設定の漏れです。ALB→Keycloak間で X-Forwarded-Proto: https が確実に伝わっているかを最初に疑ってください。
補足(KerberosとSPN整合の正確な話):ここまではOIDC/SAML前提でALBを使う話です。SPNEGO/Kerberosのブラウザ統合認証を併用する場合も、純粋なKerberos/SPNEGOはステートレス(チケットを毎リクエストの Authorization: Negotiate ヘッダで提示)なのでALB(L7)でも成立します。接続に紐づき、接続の張り替え・多重化で壊れるのはNTLMの方です。なお、クライアントがKDC(88番)からチケットを取得するのは社内ネットワーク側の通信で、Keycloak前段のロードバランサ(HTTPのみを扱う)は通りません。Kerberosで本当に効くのはSPN(サービスプリンシパル名)とKeycloakの公開ホスト名(KC_HOSTNAME)の一致で、ここがずれると検証に失敗します。TLS終端やホスト名整合を単純化したい理由でNLBを選ぶことはありますが、「ALBだからKerberosが壊れる」わけではありません。

03sticky sessionは必須か — 答えは「推奨だが必須ではない」

もっとも誤解が多い論点です。結論から言うと、Infinispanで分散キャッシュを組んでいればsticky sessionは必須ではありません。性能最適化のための推奨事項です。公式のリバースプロキシ設定ドキュメントもそう述べています。

仕組みを理解すると腹落ちします。Keycloakは認証セッションをランダムIDでInfinispanに保存しますが、分散キャッシュはエントリごとに「所有者(owner)」ノードを持ちます。あるノードが自分の持たないセッションを扱うと、所有者ノードへリモート参照が発生します。この往復を減らすため、Keycloakは AUTH_SESSION_ID クッキーを <session-id>.<owner-node-id> の形式(例: 123.node2)で発行し、ALB/プロキシが同じノードへ振れるようにしています。sticky sessionが効けばリモート参照が減り、レイテンシとクラスタ内トラフィックが下がる、という理屈です。

現場のコツ:sticky sessionを切っても「動く」ので、検証環境では問題が顕在化しません。しかし本番でノード数が増え負荷が上がると、リモート参照のオーバーヘッドがじわじわ効いてきます。特別な理由がなければ有効にしておくのが無難です。逆に、後述のセッションキャッシュのowner数を上げる設計なら、stickyへの依存度は下げられます。

04embedded Infinispanのクラスタ形成 — AWSではJDBC_PINGが本命

ここがAWSでのHA構成の心臓部です。Keycloakは各ノード内にInfinispanを埋め込み(embedded)、ノード同士はJGroupsでクラスタを形成します。問題は「ノードが互いをどう発見するか(discovery)」です。オンプレのデフォルトはUDPマルチキャストですが、AWSのVPCはマルチキャストを許可していないため、そのままでは絶対にクラスタが組めません。ここで手が止まる方が非常に多いです。

現行のKeycloakでは、分散キャッシュ設定ドキュメントにある通り、分散キャッシュ有効時のデフォルトスタックが jdbc-ping(JGroupsの JDBC_PING2 プロトコル)になっています。これはノードの参加情報を共有DBのテーブルに書き込んで互いを発見する方式で、AWSと相性が良いのが決定的です。

現場のコツ:「ノードは起動するがセッションが共有されない」ときの切り分けは、(1)DBのJGroupsレジストリテーブルに全ノードが登録されているか、(2)SGで7800/57800がノード間で開いているか、の2点をこの順で確認します。EKSならPodネットワーク、ECS/EC2ならSGインバウンドが典型的な落とし穴です。

05キャッシュのowner数とフェイルオーバーの現実

分散キャッシュは各エントリの複製数を「owner数」で制御します。ここにHAとメモリ・性能のトレードオフが凝縮されています。公式ドキュメントの記述では、ユーザ/クライアントセッションのキャッシュはメモリ節約のため所有者を絞る設計になっており、その分ノード障害時の挙動に影響します。

「単一ノード障害でもユーザを再ログインさせない」ことを要件にするなら、セッション系キャッシュのowner数を2以上にするのが定石です。ただしこれはキャッシュ設定XML(cache-ispn.xml相当)の調整領域で、公式には高度な用途と位置づけられるため、バージョンごとの推奨とサポート範囲を確認したうえで行ってください。owner数・キャッシュ調整の詳細は姉妹記事のInfinispanキャッシュチューニングで掘り下げています。

06AZ分散と、単一クラスタ/マルチサイトの線引き

AWSでの可用性はAZ分散から始めます。KeycloakのHA導入ドキュメントは、「透過的なネットワークを持つ単一クラスタ(1つのVPC/K8sクラスタ)を複数AZにまたがって配置する」構成が、AZ障害に耐える基本形だとしています。ノード間がL2的に素直に通信でき、JGroupsクラスタが1つにまとまるためです。実務ではこの「1リージョン・複数AZ・単一Infinispanクラスタ」で十分なケースが大半です。

一方、リージョン障害まで耐えたい、あるいは地理的に離れた2拠点に分けたい場合は、話が変わります。Keycloak 26.0.0のリリース告知は「両サイトで同時にユーザーリクエストを処理できるようになった」と明記しており、26系の公式HAガイドは2サイトのアクティブ-アクティブなマルチクラスタ構成を推奨構成としています(ロードバランサのblueprintもAWS Global Acceleratorベースに更新)。ただし、以下の制約は現行でも有効です。

現場のコツ:26系では「マルチサイト=アクティブ-アクティブで両拠点にログイン負荷を分散」という使い方自体が公式の推奨構成に含まれます。ただし各サイトに外部Infinispanとグローバルな振り分けを別途構築する必要があり、コストと運用負荷は相応に上がります。まず「AZ分散の単一クラスタで足りないRTO/RPO要件が本当にあるのか」を詰めるのが先です。DR全体の目標値の置き方はマルチリージョンDRのRPO/RTOもあわせて検討してください。

07ヘルスチェック — ALBが見るべきは9000番のヘルスエンドポイント

ALBのターゲットグループのヘルスチェックを、Keycloakの実アプリ(8080/8443)のトップに向けてしまう設計をよく見かけますが、現行のKeycloakは専用のヘルスエンドポイントを持っています。デフォルトでは管理ポート9000上に公開されます。

ヘルス/メトリクスの公開はデフォルトで無効なため、KC_HEALTH_ENABLED=true(および必要に応じ管理インターフェイス設定)で有効化します。ALBのヘルスチェックポートを9000、パスを/health/readyに設定するのが素直です。アプリのトラフィックは8080/8443、ヘルスは9000、と経路が分かれる点に注意してください。クラスタ全体の疎通確認にはロードバランサ経由の /lb-check の考え方も公式ガイドで示されています。

現場のコツ:/health/readyはDB接続なども含めた準備状態を見ます。DBが一時的に不調だと全ノードが同時にunhealthy判定され、ALBが全ターゲットを切り離して完全停止する、という連鎖が起き得ます。DBのMulti-AZフェイルオーバー時間とヘルスチェックの閾値(間隔・回数)のバランスを、意図的に設計しておくと事故を防げます。

08まとめ — どこまでやるかを要件から逆算する

AWS上のKeycloak HAは、「ALBの前段」よりも「Infinispanクラスタ形成とセッションキャッシュ」の理解で成否が決まります。実務的な優先順位はこうです。

EMWではKeycloakによるエンタープライズ認証基盤の実構築を通じ、これらの構成判断を要件から逆算して行ってきました。具体的な事例は導入事例もご覧ください。

参考(一次情報)

AWS上でのKeycloak冗長化構成の設計・実装でお困りの際は、実構築の実績を踏まえてお問い合わせください。

相談する
← ブログ一覧へ戻る