Keycloakの realm 設定を画面でポチポチ作ると、いつの間にか本番と検証がズレます。Admin REST API、realm export/import、Terraform provider を使って「realm as code」を成立させ、ドリフトを検知しながらCI/CDに載せるまでの実務的な勘所を整理します。
Keycloakは管理コンソールが優秀なので、最初はGUIで realm・client・role を組んでしまいがちです。ところが本番・ステージング・検証と環境が増え、監査で「この設定はいつ誰が入れたのか」を問われる頃には、GUIで作った設定は必ずと言っていいほど環境間でズレています。ここでは、Keycloakの設定を「コード」として扱い、再現性とドリフト管理を効かせるための実装手段を、Admin REST APIを土台に整理していきます。バージョンは現行のQuarkus版(WildFly版は非推奨)を前提にしますが、細部はお使いのバージョンの公式ドキュメントで必ず確認してください。
01まず前提 — Admin REST APIがすべての土台
管理コンソールも、後述するTerraform providerも、内部的には同じAdmin REST APIを叩いています。つまり「設定の自動化」の実体は、このREST APIをどう安全に・再現可能に呼ぶか、という問題に還元されます。まずは認証です。Admin APIはBearerトークンで保護され、トークンはOIDCのtoken endpointから取得します。自動化では管理者のパスワードを使うのではなく、専用の管理用clientにservice account(client credentials grant)を持たせ、必要最小限のrealm管理ロールだけを付与するのが基本です。
- ベースパスはQuarkus版で
/admin/realms(WildFly版までの/authプレフィックスは既定で外れています)。 - トークン取得は
POST /realms/{realm}/protocol/openid-connect/token。管理用clientは通常masterrealm か、対象realm内に閉じて配置します。 - 権限は
realm-managementのロール(manage-realm、manage-clients等)で絞る。全能のadminを自動化に使わないのが監査対応の分かれ目です。
02realm export/import — 塊で運ぶ手段の限界を知る
設定をまるごと運ぶ古典的な手段が、kc.sh export / kc.sh import と、realmのJSON表現(RealmRepresentation)です。公式のImport/Exportドキュメントによれば、--dir でrealmごとにファイルを分けて出力する方式(大規模データ向け推奨)と、--file で単一ファイルにまとめる方式(5万ユーザー超でメモリ問題が起きうる)があります。ユーザーは既定で別ファイルに分割され、skip で除外も選べます。
重要なのは、この機構を「バックアップ」と誤解しないことです。公式は明確に、全ノードを停止せずに取ったexportは整合性を保証しない、そしてexportにはユーザー/管理イベント、永続化セッション、失効トークンなどは含まれないと述べています。つまりrealm export/importは、あくまで「設定定義を環境間で運ぶ」ためのもので、災害復旧の代替にはなりません。DR設計そのものはDRのRPO/RTO設計のような枠組みで別立てにすべきです。
- full exportはrealm設定・client・role・groupは含むが、その手段では原則ユーザーは扱いが別(ファイル分割・除外の指定次第)。
- 管理コンソールからのexportは機微情報が落ちるため、公式もバックアップ用途には不適切と明記。CLIを使う。
- ファイル名規約(
<realm>-realm.json等)を外すとimportに失敗します。
03partial import/export — 全realmを壊さず一部だけ差し込む
full import はrealmを丸ごと作り直す発想なので、既存realmに「clientを1個だけ足す」「roleを追加する」といった部分適用には向きません。ここで効くのがAdmin REST APIの部分操作です。
- partial export:
POST /admin/realms/{realm}/partial-export。クエリexportClients、exportGroupsAndRolesで対象を選び、既存realmの一部だけをJSONに落とせます。 - partial import:
POST /admin/realms/{realm}/partialImport。既存realmに対して、client・role・group・identity provider などを部分的に投入します。既存要素との衝突時の挙動(SKIP/OVERWRITE/FAIL)をポリシーとして指定できます。
partial importは「realmの土台はGUIやTerraformで作り、頻繁に増減するclient群だけをJSONで流し込む」といった、現場でありがちな運用分業に噛み合います。ただしJSONの人手管理はドリフトの温床になりがちなので、恒久的な統制を狙うなら次のTerraformへ寄せていくのが定石です。
04Terraform provider — realm as codeの本命
設定を継続的にコードで統制するなら、Terraform provider(keycloak/keycloak)が本命です。もともとMichael Parker氏が個人で開発していた mrparkers/keycloak provider が、現在はKeycloakプロジェクト公式の管理下(keycloak/terraform-provider-keycloak)に移り、source address も keycloak/keycloak になっています。既存の mrparkers/keycloak を使っている現場は、移行を計画に入れておくべきタイミングです。
providerの認証はservice accountのclient credentialsを推奨します(password grantも設定可能ですが、CIでは避ける)。realm・client・client scope・protocol mapper・role・group・identity provider・authentication flow まで、GUIで触る主要オブジェクトはほぼリソース化されています。
terraform {
required_providers {
keycloak = { source = "keycloak/keycloak" }
}
}
provider "keycloak" {
client_id = "terraform" # service accountを持つ管理用client
url = "https://id.example.jp"
# client_secret はTF_VAR/環境変数で注入(コードに書かない)
}
resource "keycloak_realm" "corp" {
realm = "corp"
enabled = true
}
05ドリフト管理 — 「GUIで直された」を検知する
realm as codeの最大の敵は、障害対応や運用の都合で誰かが管理コンソールから直接設定を変えてしまう「ドリフト」です。Terraformを使う本質的な利点は、リソースを宣言できることよりも、terraform plan で「宣言と実態の差分」を機械的に検出できることにあります。
- CIで定期的に
terraform plan -detailed-exitcodeを回し、差分(exit code 2)が出たら通知する。これが実質的なドリフト監視になります。監視・通知の設計思想は監視・アラート設計と地続きです。 - 緊急変更を許容する運用なら、「GUIで直したら72時間以内にコードへ反映」といったルールを決め、planの差分で反映漏れを炙り出します。
- import済みでないrealmをTerraform管理に載せるときは
terraform importで既存リソースを取り込みます。いきなりapplyすると既存realmを壊しかねないので、必ず先にimport→planで無差分を確認します。
すべてをTerraform管理下に置くのが理想ですが、頻繁に増えるclient登録などは、あえてpartial importやアプリ側の動的登録に委ね、realm・flow・IdPなど「変わっては困る土台」だけをTerraformで固める、という割り切りも現場では有効です。統制の粒度はマルチアカウント統制の設計思想と同じく、「守るべき境界」から逆算して決めます。
06CI/CDに載せる — 環境昇格とレビューの型
コード化ができたら、変更をパイプラインに載せます。認証基盤の設定変更は、そのままログイン不能に直結しうる高リスク操作なので、アプリのデプロイ以上に慎重なゲートを敷きます。
- PR段階:
terraform planの結果をPRにコメントし、client scopeやflowの変更は人のレビューを必須にする。認証フローの意味は認証フロー設計を参照。 - 環境昇格:dev→staging→prod を同一コードでworkspace/変数分離し、realm名やIdP設定だけを変数で差し替える。手作業のGUI変更を各環境で繰り返さない。
- 適用:prodへの
applyは承認付き手動トリガーに。service accountのsecretはパイプラインのシークレットストアから注入し、ログに出さない。 - Kubernetes運用の注意:Operatorの
KeycloakRealmImportは「新規realmの作成のみ」で、同名realmが既にあれば上書きせず、更新・削除もしません。つまり継続的な同期ツールではなく初回投入用です。日々の設定変更はTerraform、初回のブートストラップはOperator、と役割を分けるのが噛み合います。
07実装の落とし穴 — 現場でハマる点
- 順序依存とサイクル:client scope→client、role→group、IdP→mapper のように依存があります。Terraformは概ね解決しますが、authentication flowのように相互参照しやすい箇所は明示的な依存指定が要ることがあります。
- secretの扱い:clientのsecretやSMTPパスワードをコードに直書きしない。変数注入し、stateの保護を前提にします。
- バージョン差:Keycloakのメジャーバージョンでリソースのフィールドや既定値が変わることがあります。providerとKeycloak本体のバージョン組み合わせは固定し、アップグレードはバージョンアップグレードの手順に乗せて検証してから上げます。
- export JSONのバージョン依存:realm exportのJSONは、出力元と大きく異なるバージョンへそのままimportすると差異が出ることがあります。移行時はバージョンを合わせて経由するのが安全です。
—まとめ
Keycloakの設定自動化は、Admin REST APIという単一の土台の上に、export/import・partial import・Terraform providerという粒度の異なる手段が乗る構造です。塊で運ぶexport/importはバックアップの代替にはならず、部分適用にはpartial import、継続的な統制とドリフト検知にはTerraform、という使い分けが軸になります。理想は全設定のコード化ですが、現場では「守るべき土台をTerraformで固め、増減の激しい部分は割り切る」現実解が効きます。まずは terraform plan で差分が見える状態を作ることが、realm as codeの第一歩です。設計方針で迷う場合はお問い合わせください。