KeycloakのAuthorization Servicesは、resource / scope / policy / permission という4つの部品で集中認可を組み立てる仕組みです。本記事では各要素の関係、decision strategyの挙動、UMAのRPT取得フロー、そしてpolicy enforcerのキャッシュや性能設計まで、エンタープライズの実構築で押さえるべき勘所を整理します。

Keycloakを「ログインとトークン発行の箱」として使っている現場は多いですが、Authorization Services(認可サービス)まで踏み込むと、アプリ側に散らばりがちな認可ロジックをKeycloakに集約できます。本記事では、resource / scope / policy / permission の4要素を軸に、UMA的な集中認可、RBAC/ABACの実装、そして性能設計までを実務目線で掘り下げます。バージョン差の激しい領域なので、細かい挙動は必ず稼働バージョンの公式ドキュメントで確認する前提で読んでください(本記事は新しめのバージョン基準です)。

014つの部品:resource / scope / policy / permission

Authorization Servicesを有効にしたクライアント(confidential + Authorization有効)は「resource server」になります。認可はこの上で、次の4部品の組み合わせで表現します。

ここで効いてくる設計思想が「ポリシーとパーミッションの分離」です。公式のAuthorization Services Guideでも強調されているとおり、policyは条件だけを表す再利用可能な部品で、どのリソースに効かせるかはpermissionが決めます。条件の変更(例:営業時間の変更)はpolicyを1箇所直せば全permissionに波及し、適用範囲の変更はpermission側で行う、という関心の分離ができます。

現場のコツ:最初にやりがちなのが「permissionにポリシー条件を直書きして再利用できない」パターンです。role-based policyやtime-based policyは名前付きの部品として先に切り出し、permissionからは参照するだけにしておくと、後からの棚卸しと監査が段違いに楽になります。

02permissionは2種類:resource-based と scope-based

permissionには2タイプあります。使い分けが認可設計の粒度を決めます。

実務では「粗い制御はresource-based、動詞レベルの制御はscope-based」と割り切ると見通しが良くなります。scope-basedを多用すると柔軟ですが、permission数が爆発しやすいので、まずresource typeで大枠を締めてから、例外的にscope-basedで穴を開ける/絞る、という順番が管理しやすいです。

Authorization Services:4要素の関係 resource 保護対象(Document等) scope 操作(read/write) permission resource/scope と policy の紐付け policy(条件) role/js/time/aggregate decision strategy unanimous(既定) affirmative/consensus permission が中心。左(守る対象)と右(許可条件・集約方法)を結ぶ
図:resource/scopeは守る対象、policyは許可条件、permissionがそれらを紐付ける。集約方法はdecision strategyで決まる。

02policyの種類:role / js / time / aggregate ほか

policyは条件の表現手段が複数あります。よく使うものを挙げます。

JavaScriptポリシーには重要なバージョン依存の注意があります。新しめのバージョンでは、管理コンソールからのインラインJSアップロードは既定で無効化されており、公式ガイドも「JS Policiesはサーバへ直接デプロイ(JavaScript Providers)せよ」と明記しています。つまりJSポリシーはJARとしてビルド時にサーバへ載せる運用が基本です。ビルド時/実行時設定の考え方は ビルド時・実行時設定 の整理も参考にしてください。なお、いずれのpolicyもlogic(positive/negative)で評価結果を反転でき、「このロールでない場合」といった否定条件を逆ポリシーを作らずに表現できます。

現場のコツ:「JSでなんでも書ける」からといって業務ロジックをJSポリシーに寄せすぎると、認可のテスト容易性とレビュー性が落ちます。まずrole/group/time/regexの宣言的ポリシーで表現できないかを先に検討し、JSは「宣言的に書けない少数の条件」に限定するのが、監査にも強く保守も楽です。

03decision strategy:unanimous / affirmative / consensus

1つのpermissionに複数policyを紐付けたとき、最終判定をどうまとめるかがdecision strategyです。

  • unanimous(既定):全policyがpositiveで初めて許可。ANDに近い、最も厳しい挙動。
  • affirmative:1つでもpositiveなら許可。ORに近い。
  • consensus:positiveの数がnegativeを上回れば許可。多数決。

既定がunanimousである点は必ず意識してください。「roleAとroleBのどちらか一方でOK」にしたいのに、1つのpermissionへ両方のrole-based policyを付けると、既定のunanimousでは両方必須になってしまいます。OR条件が欲しい場合は、affirmativeにするか、aggregated policyで束ねて意図を明示します。aggregatedはそれ自体に決定戦略を持てるため、複雑な論理を「部品化された小さなpolicy+集約」で組み立てるのがKeycloak流のdivide-and-conquerです。

04RBAC/ABACの実装マッピング

Authorization Servicesは、RBACとABACの両方をカバーできます。実装の対応づけは次のとおりです。

  • RBAC:role-based / group-based policy が中心。「編集者ロールなら write スコープ許可」といった素直な役割ベース制御。ロール・グループ設計そのものは ロール・グループ・属性設計 の整理とセットで考えると破綻しません。
  • ABAC:regex-based policy(属性マッチ)やJavaScript policy、time-based policyで、ユーザー属性・環境属性・リソース属性を条件化します。「部署属性がリソースの所属部署と一致する場合のみ」といった関係性判定はここに載せます。
  • ReBAC的な所有者判定:Protection APIでリソース作成時に owner を設定しておき、JS policyで「リクエスト主体=リソース所有者」を評価する、という定番パターンで表現できます。

現実のエンタープライズ要件は「基本はロール、例外は属性」という混在がほとんどです。KeycloakはRBACをベースにABACを重ねられるため、この混在を1つの認可基盤に集約できるのが強みです。組織横断の権限統制という観点では マルチアカウント統制 の考え方とも接続します。

05UMA的な集中認可:permission ticket と RPT

Authorization ServicesはUMA 2.0に準拠したフローを備えます。中心は、トークンエンドポイントの urn:ietf:params:oauth:grant-type:uma-ticket グラントで取得するRPT(Requesting Party Token)です。RPTには、評価済みのpermission(どのリソースのどのスコープが許可されたか)が入ります。

典型的なフローはこうです。クライアントが保護リソースへアクセス → resource serverがpermission ticket(要求リソース/スコープとコンテキストを表す不透明な構造)を発行 → クライアントがそのticketをKeycloakのトークンエンドポイントへ送る → ポリシー評価の結果としてRPTが返る、という流れです。permission ticketを介さず、audience にresource serverのクライアントIDを指定してインクリメンタルにpermissionを要求するentitlement的な使い方もできます。詳細な要求構文は authz-clientのドキュメントで確認できます。

UMA的フロー:permission ticket と RPT Client アプリ利用者 Resource Server 保護API Keycloak Token/認可 エンドポイント (1)アクセス (2)permission ticket (3)ticket+uma-ticketグラントで要求 (4)ポリシー評価 → RPT(許可permission入り)を返却
図:resource serverがpermission ticketを発行し、クライアントがuma-ticketグラントでRPTを取得する。ポリシー評価はKeycloak側で集中的に行われる。

06policy enforcer:PEPとキャッシュ

アプリ側で認可を効かせる部品がpolicy enforcer(PEP)です。リクエストを傍受し、Keycloakが与えたpermissionに応じてアクセス可否を判断します。policy enforcerのドキュメントによれば、enforcementには3モードあります。

  • enforcing(既定):リソースにpolicyが紐付いていなくても、既定で拒否。安全側。
  • permissive:policyが無ければ許可。段階導入時に有効。
  • disabled:評価を止めて全許可(ただしAuthorization Contextから許可情報は取得可能)。

性能面で重要なのがpath-cacheです。パスとKeycloakリソースの対応をキャッシュし、サーバへの過剰な問い合わせを抑えます。既定でlifespanは30,000ミリ秒、max-entriesは1,000件です(0で無効、-1で無期限)。リソース定義が安定している本番では、このキャッシュが実効レイテンシを大きく左右します。段階導入では、まずpermissiveで挙動を観測し、リソース/permissionの穴を潰してからenforcingへ切り替えるのが安全な進め方です。

現場のコツ:path-cacheのlifespanを長くすると性能は上がりますが、リソースやpermissionを変更した際にPEP側が古い対応を掴み続けます。CI/CDでリソース定義を頻繁に更新する環境では、キャッシュ寿命とデプロイ後の反映遅延をセットで設計し、「変更後どれだけで効くか」を運用ドキュメントに明記しておくと現場が混乱しません。

07性能設計と設計判断の勘所

Authorization Servicesは強力ですが、リクエストごとにポリシー評価が走る以上、設計を誤るとレイテンシに直結します。実構築で効いたポイントを挙げます。

  • 評価はできるだけRPTにまとめる:エンドポイントごとに個別評価するより、必要なpermissionをRPTへ一括で載せ、以後はRPT検証で済ませる方が往復が減ります。
  • permission爆発を避ける:resource typeとaggregated policyで論理を集約し、個別permissionの数を抑える。数が増えるほど評価も管理も重くなります。
  • JS policyの多用に注意:宣言的policyより評価コストとレビューコストが高くなりがち。宣言的に書ける条件はそちらへ寄せる。
  • PEPキャッシュを活かす:path-cacheのlifespan/max-entriesを本番の変更頻度に合わせて調整する。
  • 評価はEvaluateタブで先に検証:本番前にPolicy Evaluationツール(identity/context/permissionを与えて評価をシミュレート)で意図どおりか確認する。Red Hat build of Keycloakのガイドにも手順があります。

もう一段引いた設計判断として、「認可をどこまでKeycloakに寄せるか」があります。全アプリの認可をKeycloakへ集約すると統制と監査は効きますが、Keycloakが認可のクリティカルパスに乗ります。ドメインロジックに密結合した細粒度の認可はアプリ側に残し、横断的・組織的な権限統制をKeycloakへ寄せる、という切り分けが現実的です。

まとめ

Authorization Servicesは、resource / scope / policy / permission の4部品と、unanimousを既定とするdecision strategy、そしてUMAのRPTフローで、認可をKeycloakに集約する仕組みです。RBACをベースにregex/JS/timeでABACを重ねられる柔軟性が魅力ですが、その分「既定のunanimous」「JSポリシーはサーバへ直接デプロイ」「PEPのpath-cache」といったバージョン依存の勘所を外すと、意図しない挙動や性能劣化を招きます。細かい仕様は稼働バージョンの公式ドキュメントで必ず確認し、まずpermissiveで観測してからenforcingへ、という段階導入をおすすめします。Keycloakでの認証・認可基盤の実構築については 導入事例 も参考にしてください。

参考(一次情報)

認可設計をどこまでKeycloakに寄せるか迷ったら、実構築の経験をふまえてお問い合わせください。

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