アプリケーションにおける権限モデル(ACL/RBAC/ABAC/ReBAC)をきちんと理解する
こんにちは。
本記事では、アプリケーションの権限制御の実装でよく用いられる権限モデルと、それらの違いや使い所についてまとめます。
想定読者
- 権限モデルの種類や概要を知りたい方
- RBACは実装したことがあるが、ABACは実装したことがなく、何となくだけ知っている方
- ReBACは全く知らなかったのでとりあえず概要を知りたい方 →私です
前提
アプリケーションの権限制御とは、「アプリケーションが管理するリソースに対して、ある主体が行う何らかの操作を許可するか否かを判定する制御」だと考えます。
主体はユーザー単体であることもあれば、グループという形でユーザーの集合である場合もあります。
ECサイトを例にすると、以下のようなケースが考えられます。
- 顧客は自身の注文情報を閲覧することは許可されるが、他の顧客の注文情報を閲覧することは拒否される
- 顧客が商品を購入することは許可されるが、商品を作成することは拒否される
- 商品管理チームが商品を作成することは許可されるが、顧客情報を閲覧することは拒否される
- カスタマーサービスチームが顧客情報を閲覧することは許可されるが、商品を作成することは拒否される
- システムの特権を持つ管理者であれば全ての操作が許可される
権限モデル
アプリケーションの権限制御でよく用いられる権限モデルを4つ紹介します。
ACL
最もシンプルな権限モデルで古くからよく用いられる手法です。
主体がリソースに対して権限がある場合は、ホワイトリストとして保持します。
よって、権限判定としては、ホワイトリストに主体とリソースの関係が存在すれば許可、存在しなければ拒否となります。
RBAC(ロールベースアクセス制御)
こちらも特に業務用アプリケーションでは古くからよく用いられる手法です。
主体に対してロールを設定し、ロールがリソースに対して権限を保持することで、権限判定を行います。
下の図では以下のように権限が設定されています。
- システムのロールは、管理者(admin)と運用者(operator)が存在する
- 商品の閲覧は、管理者と運用者共に許可されている
- 商品の書き込みは、運用者は自身の組織の商品のみ許可され、管理者は全ての商品に対して許可される
ABAC(属性ベースアクセス制御)
ABACは主体やリソースの属性情報を元に権限判定を行います。
例えば、以下のように属性情報を用いて動的に権限制御するケースでABACが有用です。
- 商品Aは日本限定商品として、日本在住の顧客にのみ購入が許可され、他の地域に住むユーザーには許可しない
- 商品Bはプレミアム会員限定商品として、会員ランクがプレミアムランクの顧客のみ購入が許可され、他のユーザーには許可しない
これを実現するために、ポリシーとして権限制御における判定条件をコードベースやDBに保持することが一般的です。
OPAやCasbinといった認可ライブラリでは、ポリシーエンジンとして機能を提供していて、独自の形式(OPAではRego、CasbinではCONF)でポリシーテンプレートを定義します。
また、ポリシーをコード化することによって、内容を容易にレビュー可能とし、CIと結合することでテストやデプロイを自動化する手法が近年提唱されており、この思想はPolicy as Codeと呼ばれます。
もちろん、認可ライブラリを用いずに自前でポリシーエンジンを実装することも可能です。
以下にJSON形式でポリシーをコード化した簡単な例を示します。
アプリケーションでJSONからポリシーを解析し、対象のリソースや主体と照らし合わせて権限判定するイメージです。
{
"policy_name": "product_access_policy",
"description": "商品アクセス権限のポリシー",
"rules": {
"or": [
{
"and": [
{"user.country": {"equals": "JP"}},
{"product.region_restriction": {"contains": "JP"}}
]
},
{
"and": [
{"user.membership_tier": {"equals": "premium"}},
{"product.premium_only": {"equals": true}}
]
}
]
}
}
ReBAC(関係ベースアクセス制御)
ReBACは「ユーザーとリソースの間の関係性」に基づいてアクセス権を判断するモデルです。
今回取り上げた権限モデルの中で、最も高度で難易度が高いモデルであると言えます。
ReBACの設計は、Googleが自社の権限システムZanzibarが元になっています。
ZanzibarはGoogleのあらゆるサービスの権限制御に用いられていて、特にGoogle Driveがイメージしやすいと思います。
Driveにおけるフォルダには、編集者、閲覧者といったロールが主体に対して設定されており、そのフォルダ配下のファイルや子フォルダにも権限が継承されます。この階層構造や親子関係における権限制御が、まさにReBACで実現されているということです。
リレーションシップ・タプル
Zanzibarでは、リレーションシップ・タプル(Relationship Tuple)というデータ構造が提唱され、これがReBACのデータ構造の基本となっています。
リレーションシップ・タプルは、以下の3つの要素で構成されます。
(Subject) は (Relation) として (Object) に関係する
- Subject (主体): 誰が。ユーザー個人だけでなく、グループや他のリソースも主体になり得る
- 例: user:tanaka, group:store_A_staff
- Relation (関係): どのような関係で。owner (所有者), editor (編集者), viewer (閲覧者), member (メンバー) など、アプリケーションのドメインに応じて定義する
- Object (客体): 何に。商品、ストア、注文など、アクセス制御の対象となるリソース
- 例: product:prod_001, store:store_A
このシンプルなタプルを組み合わせ、関係性のグラフを構築することで、複雑な権限制御を実現します。
といってもイメージがしづらいため、簡単に行形式で表現すると、以下のようなイメージでしょうか。
object_type | object_id | relation | subject_type | subject_id | 説明 |
---|---|---|---|---|---|
product | prod_001 | editor | user | tanaka | ユーザーtanakaは商品prod_001の編集者である |
product | prod_002 | viewer | group | premium_members | グループpremium_membersは商品prod_002の閲覧者である |
group | premium_members | member | user | sato | ユーザーsatoはグループpremium_membersのメンバーである |
store | store_A | owner | user | suzuki | ユーザーsuzukiはストアstore_Aの所有者である |
product | prod_003 | parent | store | store_A | 商品prod_003の親はストアstore_Aである |
ReBACによる権限制御を提供するプロダクト
前述の通り、ReBACによる権限制御の構築は非常に難易度が高いです。
OSOから出ている記事では、独自にZanzibarを構築するには、専任のチームが少なくとも1年かけて対応する必要があると述べられています。
そのため、ReBACの構築の際には、以下のようなReBACを提供する既存のプロダクトを用いることで、近道になるかもしれません。
-
OpenFGA: Fine-Grained Authorization
- Zanzibarを元に、CNCFでSandbox maturity levelでも採択された認可OSS
-
Okta FGA
- OpenFGAを元に、Oktaが提供しているSaas
-
AWS Verified Permissions
- ReBACを提供するAWSのマネージドサービス
- 関係グラフとしてAmazon Neptuneを使用し、AWS Verified Permissionsを組み合わせたReBACの構築例の紹介
権限モデルの比較
前述の権限モデルについて再度整理し、比較しています。
権限モデル | ACL | RBAC | ABAC | ReBAC |
---|---|---|---|---|
概要 | 主体とリソースのホワイトリスト | 主体にロールを割り当て、ロールがリソースに対して権限を保持することによる権限判定 | 主体とリソースの属性の照合による権限の判定 | 主体とリソースとの間の関係性の探索(再帰)による権限の判定 |
認可判定の手法 | ホワイトリストの照合 | 主体のロールとロールに紐づく権限の照合 | ポリシーテンプレートと属性情報を元に、アプリケーションロジックで判定 | リレーションシップグラフを探索し、要求された操作がその関係性において許可されているかを判定 |
権限判定の性質 | 静的(明示的な許可) | 準静的 ロール割り当て変更時に権限が変化 |
動的 ルールベースでリアルタイムに変化 |
動的 ユーザー間の関係性やリソースの所有権が変化すると、動的に変化 |
柔軟性 | 低だが、簡単 | 中程度でバランスが良い | 高だが、ポリシー管理が複雑 | 最高だが、実装が複雑 |
適したユースケース | 小規模なファイルシステムなど、リソース数が限定的で、静的な権限管理で十分な場合 | 企業の業務システムや管理画面など、職責に応じた権限制御が必要な場合 | 動的に変化する属性に基づく権限制御 リアルタイムな判定が必要な権限制御 |
大規模で複雑な権限管理が必要なコラボレーションツール 継承やグループといった階層構造を柔軟に扱う必要がある |
まとめ
最も柔軟性が高いReBACも含めて、それぞれの手法に向き不向きが存在するため、それらを組み合わせてアプリケーションの権限制御を行うことがベストプラクティスといえます。
一般的なアプリケーションでは、やはりRBAC&ABACによるハイブリッドアプローチをベースとし、必要に応じてReBACの導入を検討していく、という方針がよさそうです。
その他の参考文献
https://www.aserto.com/blog/abac-vs-rebac-fine-grained-access-control
https://www.permit.io/blog/rbac-vs-abac-vs-rebac
https://www.okta.com/ja-jp/identity-101/role-based-access-control-vs-attribute-based-access-control/
https://www.splunk.com/en_us/blog/learn/rbac-vs-abac.html
https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/saas-multitenant-api-access-authorization/access-control-types.html
Discussion