「これだけ見ればAWS上でKeycloak本番が作れる」を目指した旗艦リファレンスです。状態はAuroraに集約しコンテナはステートレス、クラスタ形成はJDBC_PING2、LBはNLB——実構築の勘所を構成図と手順で示します。

01この構成が解く問題 — 「ログインが不安定」の正体

Keycloakを冗長化してAWSに載せたのに「たまにログインし直しになる」「二要素の途中でセッションが切れる」——こうした相談の大半は、複数ノードの間でセッションキャッシュが共有できていないことが原因です。本記事は、Fargate(ECS)+ Aurora PostgreSQL + NLB という、私たちが本番で実際に組んできた構成をリファレンスとして提示します。要点さえ押さえれば、SIerや情シスの担当者が「この通り作れば本番相当が動く」と確信できるレベルまで落とし込むことが狙いです。

設計の背骨はシンプルです。状態はAuroraだけに集約し、Fargateのコンテナは完全にステートレスにする。そのうえで、ステートレスなノード同士が「同じクラスタの仲間」だと認識し合えるように、Infinispanのクラスタ形成をAWSの制約に合わせて正しく設定する。この2点が崩れなければ、コンテナは何度落として入れ替えても、利用者から見た認証は安定し続けます。

現場のコツ:「守るのはDB、コンテナは捨てても平気」を最初にチーム内で合意しておくと、以降の設計判断(バックアップ、スケール、デプロイ方式)がぶれません。逆にここが曖昧だと、コンテナ側に状態を持たせる誘惑に負けて構成が壊れます。

02全体アーキテクチャ

まず全体像です。クライアントからのHTTPSはpublicサブネットのNLBで受け、privateサブネットに置いた2AZ分のFargateタスクへ流します。永続状態はprivateサブネットのAurora PostgreSQL(Multi-AZ)に集約。イメージ配布(ECR)、認証情報(Secrets Manager)、ログ・メトリクス(CloudWatch)、構成バックアップ(S3)は周辺サービスとして配置し、NATコストを抑えるためにVPCエンドポイントを併用します。

Client / Internet HTTPS 443 VPC 10.0.0.0/16 public subnet (2AZ) NLB (L4) TLS 443 ACM TLS 証明書 8443 private subnet — Fargate (ECS) Keycloak task (AZ-a) Quarkus optimized Infinispan 内蔵 health :9000 Keycloak task (AZ-c) Quarkus optimized Infinispan 内蔵 health :9000 7800 5432 / JDBC_PING2 private subnet — Aurora PostgreSQL (Multi-AZ) Aurora primary writer (AZ-a) realm / user / JGROUPSPING Aurora standby reader (AZ-c) 同期レプリカ ECR 最適化イメージ Secrets Manager DB / admin 認証情報 CloudWatch Logs / メトリクス S3 (backup) realm export PITR / snapshot VPC Endpoints ECR / Secrets CloudWatch / S3 NAT 代を圧縮 private のまま外部接続
図:Fargate+Aurora PostgreSQL+NLBの全体構成。青がリクエスト、金がバックアップの流れ。

ポイントは、リクエストの流れ(青)とバックアップの流れ(金)が明確に分かれていることです。利用者トラフィックはNLB→Fargate→Auroraと一直線に下り、バックアップはAuroraのPITR/スナップショットとrealmエクスポートのS3保管という別系統で守られます。ECS上でのHA設計の考え方はKeycloak HA構成 on AWSでも整理しています。

03Fargate(ECS)— ステートレスなKeycloakをどう載せるか

コンテナイメージは、Quarkusベースの最適化イメージを使います。Dockerビルド時にkc.sh buildを済ませ、起動はstart --optimizedで行うと、毎回の起動時にビルド工程が走らず立ち上がりが速くなります。ビルド済みイメージはECRに置き、Fargateから引きます。

NLB(L4)はX-Forwarded系ヘッダを付与しないため、NLBでTLS終端する構成ではKC_PROXY_HEADERS=xforwardedは実効性がなく、正しいURL生成は公開URLを指定するKC_HOSTNAMEで担保します。xforwardedヘッダを信頼させたい場合は、ヘッダを付与・サニタイズするL7要素(ALB等)を経路に置く必要があります。なお旧proxyオプション(KC_PROXY)はKeycloak 24で非推奨化され、Keycloak 26.0.0で削除されました。代替はproxy-headers(KC_PROXY_HEADERS)です。詳細はKeycloak公式のhostname(v2)ガイドを確認します。WildFly版からの移行を含む土台づくりはQuarkus版への移行にまとめています。

04イメージのビルドとpush — Fargateではビルドしない

「では、その最適化イメージはどこでビルドするのか」を明確にしておきます。答えはFargateではありません。Fargateは実行時にECRからイメージをpullするだけで、ビルド環境ではありません。ビルドはCI/CDパイプライン側で行い、ECRへpushします。

鍵になるのがマルチステージDockerfileです。builderステージでkc.sh buildを実行してプロバイダ・DB・機能フラグを焼き込み、最終ステージではstart --optimizedで起動する形にします。骨子は次のとおりです。

docker buildを回す場所は、CI/CDの選択で決まります。

現場のコツ:kc.sh buildイメージビルド時に一度だけ走らせ、Fargateではstart --optimizedで起動します。これを守らないと、起動のたびに裏でauto buildが走り「起動が遅い」の原因になります(Quarkus版への移行で詳述)。ビルドは必ずCI側(またはローカル)、Fargateでは走らせない、が鉄則です。

この「build→push」パイプラインは、Terraformのstateロック(S3+DynamoDB)と同じデプロイ基盤(CI/CD側)のレイヤーに属します。実行時のFargate/Aurora/NLBとは層が違う、と整理すると全体像がすっきりします。

05【最重要】Infinispanのクラスタ形成 — JDBC_PINGで組む

ここが本構成で最も陥りやすい箇所です。KeycloakのセッションキャッシュはInfinispanで分散共有されますが、その前提としてノード同士がお互いを発見(ディスカバリ)できる必要があります。ところがFargateはマルチキャストが使えず、コンテナのIPも起動のたびに変わるため、デフォルトのマルチキャスト前提のディスカバリは機能しません。ここを外すと、片方のノードで作られたセッションがもう片方から見えず、「ログインが不安定」という症状になります。

定番の解決策がJDBC_PING(現行はJDBC_PING2)です。追加インフラを立てず、既存のPostgresのテーブルをノードの"名簿"として使う方式で、各ノードが自分のIP/ポートをテーブルに登録し、そこから他ノードを発見します。発見後は直接ユニキャスト(既定TCP 7800)でキャッシュを同期します。

Infinispan クラスタ形成 — JDBC_PING2 でノードを相互発見 Fargate task A (AZ-a) Keycloak (Quarkus) Infinispan (embedded) IP: 10.0.1.x 動的 Fargate task B (AZ-c) Keycloak (Quarkus) Infinispan (embedded) IP: 10.0.2.x 動的 Aurora PostgreSQL JGROUPSPING テーブル 各ノードが自IP/ポートを 登録・他ノードを発見 register / discover register / discover セッション複製 TCP 7800 発見後は直接ユニキャストで同期 multicast 不可 + IP 動的 の Fargate でも、DB を"名簿"にすれば追加インフラなしでクラスタが組める
図:Fargateでもマルチキャストなしで、共有DBを"名簿"にすればJDBC_PING2でクラスタが組める。

朗報として、Keycloak 26系ではこのjdbc-pingスタックが分散キャッシュ有効時のデフォルトになり、公式ドキュメント上もJDBC_PING2によるDB登録が既定と明記されています。つまり近年のバージョンでは、以前のようにカスタムのキャッシュ設定XMLを持ち込まなくても、KC_CACHE_STACK=jdbc-pingを指定するだけでこの構成に乗れます。設定の詳細はKeycloak公式の分散キャッシュ設定で確認してください。

現場のコツ:クラスタが組めない時の切り分けは、(1)DBへ届いているか、(2)ノード間のTCP 7800がSecurity Groupで相互に開いているか、の2点をまず見ます。JGROUPSPING相当のテーブルに全ノードのIPが並んでいるのに同期しない場合は、ほぼ7800の疎通です。

DNS_PING(ECS Service Connect / Cloud Map)も選択肢ですが、追加のサービスディスカバリ設定が要ります。「Postgresが既にそこにある」以上、まずはJDBC_PING2が最も部品が少なく堅い、というのが私たちの実務判断です。

06なぜALBではなくNLBか

ロードバランサをNLB(L4)にする理由は、TCPパススルーの素直さと、ACMによるTLS終端の扱いやすさです。

TLS証明書の置き場所は明確です。ACMで発行/取り込んだ証明書をNLBのTLSリスナー(443)に載せてTLS終端します。ACM証明書はNLBのTLSリスナーで直接利用でき、自動更新も効きます。要件次第でコンテナまでTLSパススルーする構成も取れますが、運用の素直さからはNLB終端が基本です。詳細はNLBのサーバー証明書(ACM)公式を参照してください。AD/LDAP連携やKerberosを使う場合も、要点はSPNと公開ホスト名の整合で、NLBのTCP素通しはその設計をシンプルに保ちやすい、というのが実利です(Kerberos自体はALB(L7)でも動作します)。

07認証情報の注入 — Secrets Manager

DBのユーザー/パスワードや管理者パスワードは、タスク定義から環境変数に平文で書かないのが鉄則です。Secrets Managerに置き、ECSタスク定義のsecrets参照で注入します。こうすればイメージにもタスク定義のプレーンな値にも機密が残らず、ローテーションも回せます。Aurora作成時にSecrets Managerでの認証情報管理を有効にしておくと、DB側との整合も取りやすくなります。セキュリティ全般の締め方はKeycloakセキュリティ堅牢化にまとめています。

08観測性 — ログ・メトリクス・ヘルスチェック

コンテナログはFireLens(Fluent Bit)経由でCloudWatch Logsへ送ります。メトリクスはCloudWatch(Container Insights等)で取得。Keycloak側は管理用のポート9000にヘルスエンドポイント(/health/ready/health/live)を公開でき、NLBのヘルスチェックは9000の/health/readyに向けます。ヘルスチェックは既定で無効なので、KC_HEALTH_ENABLED=trueで有効化するのを忘れないでください。詳細はKeycloak公式のヘルスチェックを参照。ログ収集エージェントの選定や監視・アラートの閾値設計は、認証基盤の重要度に応じて別途詰めることをおすすめします。

現場のコツ:ヘルスチェックを本サービスの8443ではなく管理ポート9000に向けるのが肝です。9000は起動完了・DB接続・キャッシュ状態まで見た"本当に受けられるか"を返すため、まだ温まっていないノードへNLBがトラフィックを流すのを防げます。

09バックアップ — 守るのはDBだけ

状態がAuroraに集約されているので、バックアップ戦略も明快です。

コンテナは捨てても平気、守るのはDB——この原則があるからこそ、復旧手順は「Auroraを戻す/エクスポートを取り込む」に集約でき、Fargate側は最新イメージから作り直すだけになります。DBのチューニングや復旧の勘所はKeycloakのデータベースチューニングを参照してください。より広いDR設計(RPO/RTO)は要件次第で別途詰めます。エクスポート/インポートの正確な手順はKeycloak公式のimport/exportで確認します。

10ネットワークとコスト、そしてDynamoDBの扱い

ネットワークはprivateサブネット主体、Security Groupは最小構成にします。

privateサブネットから各AWSサービスへ出る通信は、VPCエンドポイント(ECR / Secrets Manager / CloudWatch / S3)を使うとNAT Gateway経由の通信量を減らせ、コストと閉域性の両方で有利です。イメージのpullやログ送信の量が読めない初期ほど、この設計差がNAT代に効いてきます。

最後にDynamoDBの位置づけを正確に。Keycloak本体は実行時構成でDynamoDBを使いません(状態はAuroraのみ)。DynamoDBが登場するのは、この構成をコードで作る側——Terraformのstateロック(S3+DynamoDB)というデプロイ基盤の部品としてだけです。IaCのstate管理はIaCのstate管理にまとめています。

11用意するものチェックリスト

まとめ

本構成の勘所は3つに集約されます。(1)状態はAuroraに集約しコンテナはステートレスにする。(2)クラスタ形成はJDBC_PING2で、既存Postgresをノードの名簿として使う(Keycloak 26系では既定)。(3)統合認証を活かすためLBはNLB(L4)、TLS証明書はACMをNLBに載せる。ここさえ外さなければ、コンテナは自由に入れ替えられ、守るべきはDBだけ、という運用に収束します。バージョン依存の設定値は必ず公式ドキュメントで最終確認してください。

参考(一次情報)

自社要件に合わせたKeycloak本番構成の設計・構築でお困りなら、実構築の経験を持つEMWへお問い合わせください。

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