長年動いてきた独自認証や既存ユーザDBを、いきなり捨てるわけにはいきません。User Storage SPIは、そのレガシーをKeycloakの背後に「繋いだまま」認証を統合し、時間をかけて安全に移行するための正攻法です。実装の勘所とキャッシュ・パスワード取り込みの落とし穴を、現場目線で整理します。

Keycloakは標準でLDAP/Active Directoryの連携機能を持ちますが、エンタープライズの現場で本当に困るのは「LDAPでもADでもない、独自の認証テーブルやレガシーAPI」です。合併で引き継いだ会員DB、10年もののパスワードハッシュ、社内独自のユーザ管理API — これらをどうKeycloakに繋ぐか。その答えがUser Storage SPIです。本稿では、既存DB/独自認証をKeycloakの背後に接続し、段階的に移行するための実装の勘所を、実務目線で整理します。

01User Storage SPIとは何を解決するのか

User Storage SPI(Service Provider Interface)は、Keycloakの内部データベース以外の場所にあるユーザ情報を、あたかもKeycloakのローカルユーザであるかのように扱うための拡張ポイントです。認証時にKeycloakは自前のユーザテーブルだけでなく、登録されたUser Storage Providerにも問い合わせます。既存システムを一切改修せず、参照元として繋ぐことができるのが最大の価値です。

公式のServer Developer Guideでは、この仕組みが「LDAP/ADはサポートするが、任意のカスタムユーザDBに対しても拡張を書ける」ものとして位置づけられています。設計の基本は2つのインターフェースです。

02Capabilityインターフェース — 必要な分だけ実装する

User Storage SPIの設計思想は「できることだけを宣言する」です。基底のUserStorageProviderに対して、以下のcapabilityインターフェースを必要な分だけ足していきます。

現場のコツ:最初のフェーズは「読み取り専用」で割り切るのが安全です。UserLookupProviderとCredentialInputValidatorだけで認証は成立します。書き込み(UserRegistrationProvider)を実装すると、Keycloak側とレガシー側のどちらが正となるかの整合設計が一気に重くなります。移行初期はレガシーを正としてread-onlyで繋ぎ、段階的に権限を移すのが定石です。

03Storage IDと federated(非import)モード

User Storage SPIには2つの動作モードがあります。1つはfederated(フェデレーション)モードで、ユーザをKeycloakのDBに取り込まず、参照のたびに外部ストレージへ問い合わせます。この場合、ユーザは「Storage ID」と呼ばれる合成IDで識別されます。形式は f:<プロバイダのコンポーネントID>:<外部システムでのユーザID> で、これによりKeycloakはどのProviderのどのユーザかを一意に解決します。

federatedモードの利点は、外部システムが常に正であること。取り込みによるデータ二重化が起きません。一方で、認証やトークン発行のたびに外部への問い合わせが走るため、外部システムのレイテンシと可用性がそのままKeycloakの応答性能に響きます。ここがキャッシュ設計(後述)の重要性に直結します。

クライアント (OIDC/SAML) Keycloak 認証フロー ローカルDB (Keycloakユーザ) User Storage Provider (SPI) レガシーDB / 独自API まずローカルを確認、 無ければSPIへ委譲
図:認証時、Keycloakはローカルユーザを確認し、見つからなければUser Storage Provider経由でレガシーDBを参照します。

04on-demand import — 段階移行の本命

もう1つのモードがon-demand import(オンデマンド取り込み)です。外部ストレージで見つかったユーザを、参照時にKeycloakのローカルDBへコピーして「ローカルユーザ化」します。以降そのユーザはKeycloakネイティブのユーザとして扱われ、属性やロールをKeycloak側で管理できるようになります。レガシーからの脱却を狙う移行案件では、こちらが本命です。

importモードで押さえるべきインターフェースは2つです。

現場のコツ:importモードでは「Keycloak側が正になった属性を、後続のsyncで外部の古い値に上書きされる」事故が起きがちです。ImportedUserValidationの実装で、どのフィールドを外部起点で更新し、どのフィールドをKeycloak側で凍結するかを明示的に決めてください。移行途中は「ID・ユーザ名は外部起点、ロールと同意情報はKeycloak起点」といった線引きが実務的です。

05パスワードの段階取り込み — 移行の核心

レガシー移行で最も神経を使うのがパスワードです。ハッシュ方式が古い(独自salt付きMD5、bcryptの古いコスト等)場合、そのままKeycloakに移せません。ここでUser Storage SPIの真価が出ます。

戦略はこうです。CredentialInputValidatorでレガシー側のハッシュ検証ロジックをそのまま実装し、ユーザがログインに成功した瞬間、Keycloakネイティブのパスワードクレデンシャルとしてその平文を再ハッシュして保存します。ログイン成功時には平文パスワードが一時的にメモリ上に存在するため、これをKeycloak標準のPasswordCredentialModel(現行の推奨アルゴリズム)で保存し直すわけです。以降そのユーザはレガシー検証を経由せず、Keycloakネイティブで認証されます。

なお、パスワードの検証・更新まで扱う場合はCredentialInputUpdater等の関連インターフェースも視野に入りますが、バージョンによって扱いが変わるため、実装前に現行版のJavadocで最終確認してください。

06キャッシュ制御 — 性能と一貫性の綱引き

Keycloakは外部への往復を避けるため、User Storage Provider経由で取得したユーザをローカルにキャッシュします。federatedモードでは、このキャッシュが外部システムへの負荷とレイテンシを左右する生命線です。関連する要素は次の通りです。

現場のコツ:移行初期はNO_CACHEで正しさを担保し、動作が固まってからEVICT_DAILY等に緩めるのが安全です。逆に、外部システムの負荷試験を省いてキャッシュ前提で本番投入すると、キャッシュ失効の谷でレガシーDBに突き刺さる負荷ピークを見落とします。Infinispanのキャッシュチューニングは別記事で扱っています(Infinispanキャッシュチューニング)。

ユーザ ログイン SPIでレガシー ハッシュ検証 平文を再ハッシュ Keycloakへ保存 検証失敗 拒否 以降ネイティブ 認証 成功 失敗
図:ログイン成功時に平文をKeycloak標準アルゴリズムで再ハッシュ保存し、アクティブユーザから段階的にネイティブ認証へ移す。

07パッケージングとデプロイ(Quarkus版基準)

現行のKeycloakはQuarkusベースが標準で、旧WildFly版は非推奨です。旧版のEARやjboss-cliを前提にした古い記事のデプロイ手順は使えないため注意してください。現行のConfiguring providersドキュメントに従うと、手順はシンプルです。

現場のコツ:公式は「信頼できないProvider JARを入れるな」と明記しています。ProviderはサーバのクラスローダでDB・設定・資格情報にアクセスできるため、ビルド成果物の管理とサプライチェーンは厳格に。ビルド最適化の詳細はbuildとruntime設定の分離、Quarkus移行全般はQuarkus版への移行を参照してください。

まとめ

User Storage SPIは、レガシー認証を「捨てずに繋ぐ」ための正攻法です。要点を整理します。

EMWではKeycloakによるエンタープライズ認証基盤の実構築実績があります。具体的な移行設計は導入事例もご覧ください。バージョン依存の挙動は必ず現行版の公式ドキュメントで最終確認することをおすすめします。

参考(一次情報)

レガシー認証基盤のKeycloak移行、User Storage SPIの実装やパスワード段階移行の設計でお困りの際は、お問い合わせください。

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