Keycloakの認証・管理操作を漏れなく監査ログとして残し、外部のSIEMやWebhookへ確実に届ける。そのための正攻法がEvent Listener SPIです。トランザクション境界と失敗時の挙動を正しく設計しないと、監査ログに穴が空きます。実装の勘所を整理します。
01Keycloakの「イベント」は2系統ある
Keycloakは、認証基盤で起きた出来事を「イベント」として記録・配信する仕組みを標準で備えています。監査ログやSIEM連携を設計するうえで、まず押さえるべきは、イベントが2系統に分かれている点です。
- ログインイベント(User Events):エンドユーザーの操作。
LOGIN/LOGIN_ERROR/LOGOUT/CODE_TO_TOKEN/REFRESH_TOKEN/UPDATE_PASSWORDなど。realm単位で有効化します。 - 管理イベント(Admin Events):Admin ConsoleやAdmin REST API経由の構成変更。ユーザー作成、ロール割り当て、クライアント登録の変更など。「誰が・いつ・何を」変えたかの証跡で、こちらも別途有効化が必要です。
両方とも、既定ではデータベースに保存され、Admin Consoleから閲覧できます。ログインイベントには保持期間(expiration)を設定でき、期限切れは自動削除されます。管理イベントには、変更内容そのもの(Representation)を含めるかどうかのフラグがあります。詳細はServer Administration Guideの監査(auditing)の章を確認してください。
02Event Listener SPIとは何か
DB保存とは別に、イベントが発生した瞬間に任意の処理を差し込むための拡張点がEvent Listener SPIです。標準ではjboss-loggingリスナー(サーバーログへ出力)が組み込まれており、これを有効化するだけでもログ基盤への一次連携はできます。ただしSIEM向けの構造化送信や、外部Webhook連携をやりたい場合は、独自リスナーを実装するのが正攻法です。
実装は次の2つのインターフェースと、1つのサービス登録ファイルで構成されます。
EventListenerProviderFactory:プロバイダの生成とID定義。create(KeycloakSession)とgetId()が中心。EventListenerProvider:実際のイベント処理。onEvent(Event)(ログインイベント)とonEvent(AdminEvent, boolean includeRepresentation)(管理イベント)を実装します。META-INF/services/org.keycloak.events.EventListenerProviderFactory:ファクトリの完全修飾名を1行書くサービスローダー登録。
インターフェースの正確なシグネチャはEventListenerProviderのJavadocで確認できます。実装後は、Admin Consoleの Realm settings → Events → Event listeners で、getId() が返すIDを登録すると有効になります。
standalone/deployments/ へのホットデプロイは非推奨で、Quarkus版ではJARを providers/ に配置し kc.sh build を実行してから起動する手順が基本になります。ビルド時/実行時の設定分離はバージョンで挙動が変わるため、採用バージョンの公式手順で必ず裏取りしてください。03トランザクション境界を外さない
ここがEvent Listener SPI最大の落とし穴です。onEvent は、そのイベントを生んだ実行中のトランザクションの内側で呼ばれます。つまりリスナーの中で重い外部I/O(HTTP送信やSIEMへの書き込み)を同期実行すると、そのレイテンシがユーザーのログイン処理そのものを遅延させます。さらに、外部送信が失敗して例外を投げれば、元のトランザクションごとロールバックされ、ログインが失敗しかねません。
Javadocはこの点を明確に述べています。イベント処理をJPAでDBに書くならトランザクション整合が取れて都合が良い一方、ログファイルへの書き込みや外部送信のようにロールバックできない副作用は、トランザクションのコミット完了後に回すべきだとしています。そのための仕組みが KeycloakTransactionManager.enlistAfterCompletion(...) です。イベントを一旦メモリ上に積み、元トランザクションが成功コミットした後にだけ実際の送信を行います。
04非同期化と失敗時の扱い
コミット後に送信するとしても、送信処理自体をリクエストスレッドで同期的に待つと、やはりレスポンスが遅くなります。実務では、コミット後フックの中で送信タスクをスレッドプールへ投入し、即座にリターンする構成を採ります。実際、代表的なOSS実装であるp2-inc/keycloak-eventsも、送信タスクをスレッドプールでスケジュールし、Keycloakトランザクションのコミット後に実行する設計を採っています。
非同期化すると、次は「送信に失敗したイベントをどう扱うか」が論点になります。監査ログは欠損が許されないため、失敗時の戦略を必ず決めます。
- リトライ:一時的なネットワーク障害に備え、指数バックオフで再送。前述のOSS実装も、2xx以外のレスポンスに対して指数バックオフで再試行する仕組みを持っています。
- デッドレター/ローカル退避:リトライ上限を超えたイベントは、ローカルファイルやDBのバッファテーブルに退避し、取りこぼしを可視化する。「送れなかった」を握りつぶさないことが監査上の肝です。
- バックプレッシャー:送信先が長時間ダウンした場合にキューが際限なく膨らむと、メモリ枯渇でKeycloak本体が落ちます。キュー上限とあふれ時の挙動(ローカル退避へフォールバック等)を先に決めておきます。
05SIEM / Webhook連携の設計パターン
送信先ごとに、現実的なパターンを整理します。
- 直接HTTP/Webhook送信:リスナーからHTTPS POSTで外部エンドポイント(SIEMのHTTP Collectorや業務側Webhook)へ送る。改ざん検知のためHMAC署名を付与し、受信側で検証するのが定石です。前掲のOSSもHMAC署名とリトライを標準装備しています。
- 耐久キュー経由:Kafkaやメッセージブローカーへ流し、SIEM側はそこから購読。ピーク吸収と再処理のしやすさが利点。大規模・多realm環境で有効です。
- ローカルログ+収集エージェント:
jboss-loggingリスナーや独自リスナーで構造化ログ(JSON)を吐き、Fluent Bit/Fluentd/Vectorで収集。既存のログ基盤に乗せられるのが強みです。
SIEMに渡す際は、イベントのフィールド設計が効いてきます。type(イベント種別)、realmId、clientId、userId、ipAddress、error、そして相関のためのsessionIdを必ずマッピングします。管理イベントでは、operationType(CREATE/UPDATE/DELETE)とresourcePath、変更主体(authDetails)が監査の中核です。なおonEvent(AdminEvent, includeRepresentation) の第2引数を有効にすると変更後のRepresentationも取得できますが、パスワードや機密属性が乗る場合があるためマスキング方針を決めてから有効化します。
実案件でのKeycloak構築事例は導入事例もあわせてご覧ください。マルチアカウント環境での証跡集約はマルチアカウント統制とも接続する論点です。
06監査要件へのマッピング
監査要件(内部統制、PCI DSS、各種セキュリティ基準など)に照らすと、Event Listener SPIで担保すべき点は概ね次に集約されます。
- 完全性:認証成功/失敗、権限変更が漏れなく記録され、外部の改ざん困難なストレージに保全されること。DB保存だけで完結させない。
- 追跡可能性:「誰が・いつ・どのIPから・何を」が特定できること。管理イベントのauthDetailsとresourcePathが要。
- 可用性・保全期間:ログインイベントのexpirationはKeycloak側の運用データ用と割り切り、長期保全は外部側の保持ポリシーで満たす。
- 異常検知:
LOGIN_ERRORの急増などをSIEMのアラートに接続する。
なお、監査ログ(イベントの証跡)と、監視メトリクス(件数の傾向)は目的が異なります。ログインや失敗の件数の傾向監視には、Keycloak標準のイベントメトリクスが使えます。--metrics-enabled=true と --event-metrics-user-enabled=true で有効化し、PrometheusエンドポイントへLOGIN/LOGIN_ERROR等のカウンタが出ます。既定はrealm単位で、event-metrics-user-tags でclientやIdP次元を追加できます(カーディナリティに注意)。詳細はMonitoring user activities with event metricsを参照してください。この機能はKeycloak 26.1で正式に取り込まれています。
07まわりの拡張点との棲み分け
Event Listener SPIは「起きたことを記録・通知する」拡張点です。「起きる前に介入する」用途では別のSPIを使い分けます。認証フローそのものにステップを差し込むならCustom Authenticator SPI、認証フロー全体の設計は認証フロー(Authentication Flow)の記事が該当します。イベント連携と合わせて、認証の入口(検知・記録)と処理(制御)を両輪で設計すると、監査と防御が一枚岩になります。
また、監視・可観測性の全体像はKeycloakの可観測性もあわせてご覧ください。イベントメトリクス、ログ、トレースの三点で認証基盤の状態を捉える設計につながります。
—まとめ
Event Listener SPIは、Keycloakの監査ログを「Keycloakの外」に確実に逃がすための正攻法です。実装はEventListenerProviderFactoryとEventListenerProviderの2つとサービス登録だけとシンプルですが、勘所は実装量ではなく境界設計にあります。
- 外部送信のようなロールバック不能な副作用は、トランザクションのコミット後(
enlistAfterCompletion)に回す。 - 送信はスレッドプールで非同期化しつつ、リトライ・ローカル退避・バックプレッシャーで欠損を防ぐ。
- DB保存は運用画面用、外部保全が監査の本命。メトリクスは傾向監視として併用する。
ここを外すと、ログインが遅くなる・巻き添えでコケる・監査ログに穴が空く、のいずれかを踏みます。逆に押さえておけば、堅牢で説明可能な監査基盤になります。
—参考(一次情報)
- EventListenerProvider (Keycloak Javadoc) — onEvent/onAdminEventのトランザクション挙動とenlistAfterCompletionの推奨
- Keycloak Server Developer Guide — Event Listener SPI
- Keycloak Server Administration Guide — Configuring auditing to track events
- Keycloak — Monitoring user activities with event metrics
- p2-inc/keycloak-events — Webhook/HTTP送信リスナーとリトライ実装(GitHub)