Tags
FirestoreSecurityData Model PatternData Modelアクセス制御
Last Updated
Sep 5, 2024 4:19 PM
Created
Sep 2, 2024 6:55 AM
Role-Based Authorization Pattern (RBAC)は、サービス内のコンテンツにグローバルにアクセス制御を行う(ex. NetflixのSubscription)ときに用いられる Data Model Patternである
なお、個別コンテンツへのアクセス制御は、一般にABACが用いられる
一方で、個別コンテンツへのアクセス制御(ex. NetfrixのSubscription)には、ABACが用いられるケースが多いです。 (以下、ABACの解説記事もご参照ください)
本記事では、NoSQL DatabaseであるFirestoreにおける実装方法、およびABACの応用的なデータモデルについて解説していきます。
目次
- Firestoreにおける実装
- 基本形
- Data Model
- Security Rule
- Triggers of Update Duplicated Data
- 応用系
- A: マルチテナントにおけるRBAC
- 参考資料
Firestoreにおける実装
基本形
以下、基本形となるData Model、Security Rule、 冗長化したデータを更新するトリガーの構成を整理する
Data Model
- roles Collectionを作成し、roleの名称をdocumentIdとしたroleを作成
- users Collectionを作成し、にroleのDocumentIdをString型のArrayで格納
# roles
- documentId: 'admin'
- documentId: 'editor'
- …
# users
- documentId: 'ヒソカ=モロウ'
- roles :Array
- String: 'admin' ※
- String: 'editor'
- …
- …
※Document Reference型としてもよいがIndexが効かなくなるため、String型としている
Security Rule
- request.auth.uid (ログイン中のuser)と一致するusersのrolesの有無を参照して、アクセス制御を行う
// rules.json
match /posts/{id} {
function getRoles() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.roles;
}
allow create: if getRoles().hasAny(['admin']) == true;
allow read: if request.auth != null;
allow update: if getRoles().hasAny(['admin', 'editor']) == true;
allow delete: if getRoles().hasAny(['admin']) == true;
}
Triggers of Update Duplicated Data
- 以下、Triggerとなる事象の発生に基づきCloud Functionを起動、冗長化されたデータのUpdateの処理を行う
# | Trigger | Frequency | Update |
1 | rolesからdocumentをDelete | very low | users内のすべてのドキュメントのrolesから削除対象となるroleを削除 |
応用系
A: マルチテナントにおけるRBAC
基本形を応用して、マルチテナントへ対応させた例
Data Model
- usresCollectionにrolesに代わりorganization_rolesを追加。 posts (RBACを適用したいCollectionの例) にowner_organizationフィールドを追加する
# roles
- documentId: 'admin'
- documentId: 'editor'
- …
# organizations
- documentId: 'google' ※
- documentId: 'apple'
- …
# users
- documentId: 'ヒソカ=モロウ'
- organization_roles: Map
- name: String ※
- roles :Array
- String: 'admin'
- String: 'editor'
- …
- name: String
- roles :Array
- String: 'viewer'
- …
- …
# user_organization_roles
- document_id:
- user_id :String
- organization_id :String ※
- role_id :String
# posts
- documentId: '幻影旅団のひみつ'
- owner_organization :String
※ organizations と user_organization_roles の documentIdを一致させる
Security Rule
- hasRoleInOrganization関数を用いてorganization_rolesに設定されたRole情報を利用する
// rules.json
match /posts/{id} {
function isSignedIn() {
return request.auth != null;
}
function hasRoleInOrganization(organization_id, role_id) {
return isSignedIn()
&& get(/databases/$(database)/documents/users/$(request.auth.uid)).data.organization_roles[organizationId].hasAny([role]);
}
allow create: if hasRoleInOrganization(request.resource.data.owner_organization_id, 'admin')
|| hasRoleInOrganization(request.resource.data.owner_organization_id, 'author');
allow read: if isSignedIn();
allow update: if hasRoleInOrganization(resource.data.owner_organization_id, 'admin')
|| hasRoleInOrganization(resource.data.owner_organization_id, 'auther')
|| hasRoleInOrganization(resource.data.owner_organization_id, 'editor');
allow delete: if hasRoleInOrganization(request.resource.data.owner_organization_id, 'admin');
}
Triggers of Update Duplicated Data
- 基本形での処置に加えて、organizationの削除も冗長化された情報に反映させる必要がある
# | Trigger | Frequency | Update |
1 | rolesからdocumentをDelete | very low | usersのorganization_rolesから削除対象となるrole名を削除 |
2 | organizationsからdocumentをDelete | low | usersのorganizationRolesに削除対象となるorganization名を削除 |