Slack の Role Management 調査

参考文献
1個目の記事がおすすめ。2個目は薄い。

「特定のユーザーに特定のチャンネルの管理のみを許可したい」というニーズがあった。
一方でそれに対して、これまでの管理者ロールは権限が強すぎた。
ダッシュボードを表示したり、チャンネル管理とは無関係な情報を閲覧できてしまっていた。

これまでのロール
- Guest
- 1つまたは複数の許可されたチャンネルのみを閲覧できる
- Member
- 管理能力はもたない
- 組織のSlackワークスペースへの基本的なアクセス権をもっている
- Admin
- チャンネル名の変更、チャンネルのアーカイブ、設定やポリシーの変更、新規ユーザーの招待、アプリケーションのinstall など
- Owner
- Adminの管理能力に加え、データ損失防止(DLP)や保持設定など追加のコンプライアンス能力を持つ
- Primary Owner
- 組織の最高管理者。なんでもできる。

ロールへの新たな要件
Admin ユーザーのコア能力を分解した細粒度のRole Systemが必要だった。
既存のRoleも動作しつづける必要があった。
RBACを選択した。
Organization または Workspace レベルで使えるものにする必要があった。

Walk Through Data Model
Permission
- Slackで何らかのアクションを遂行する能力
- 例
- ワークスペースにユーザーを招待する能力
- チャンネルをアーカイブする能力
- 組織全体のユーザーを閲覧する能力
- 例
Role
Role は Permission の セットとして定義される。
Role は ユーザーに割り当てることができる。
- 例: role「チャンネル管理者」
- チャンネルの作成権限
- チャンネル名の変更権限
- アーカイブ権限
Entity
-
Entity は Slack内のObject
-
User が 特定のEntity に対して Role を Assignされる
-
例
- ある Organizationでは
- Aさんは company (= entity:Enterprise) 内でのChannel Admin
- Bさんは workspace (= entity:Workspace) 内での Channel Admin
- ある Organizationでは
RBAC

How this works in practice (実際の仕組み)
-
ユーザーがアクションを実行する
-
そのアクションに必要な権限をチェックする
-
ユーザーが割り当てられたRoleを通じて そのアクションを実行する権限を
- もっている => 許可
- もっていない => レガシーモデル(pre-defined role)にFallbackする
-
権限チェックは常にサーバーサイドで行う
-
一方でClient Sideでは その時点で ユーザーに表示されるであろうUI コンポーネントを予測に基づき、non-authoritative(非権威的に) に 表示している
- 低レイテンシーを重視したいため、このnon-authoritativeなcheck は Flannel エッジキャッシュに対して行う
- 結果として クライアント再度での権限チェックは、ニアリアルタイムでの反映になる

3つのシステムロール
Channel Admin
チャンネルのアーカイブ、名前の変更、プライベートチャンネルの作成、パブリックチャンネルのプライベート化
Users Admin
ワークスペースへのユーザーの追加、削除、組織のユーザーグループを閲覧する
Roles Admin
ロール自体を管理し、各ロールにユーザーを割り当てる

Backend の 設計
Vitess store というやつに 永続化しているらしい。(分散的なRDB? NoSQL?)
sharding architecture, scale by user_idVitess store には もともと Slack Webapp のデータもはいってるっぽいな。
data drift を防ぐために centralized する選択をしたと。

Communication Architecture
ユーザーがチャンネルをArchiveするときの例
Policy
Channels\ChannelCanActorArchivePolicy::checkPolicy($permission_context, $channel)
- context: who is this user (in this case)
- entity: a channel
Policy 内では以下のことをチェックする
- DenyIfActorRestricted (e.g. Guest User)
- AllowIfUserHasArchiveChannelLegacyPermission
- AllowIfUserHasArchiveChannelPermission
1つめは Restricted User (e.g. Guest) のチェック
2つめは Legacy な Role Systemへのチェック
3つめのやつが 権限サービスにリクエストをおくるやつ。以下のようなリクエストが送られる
EligibilityRequest(
'team_id' => T12345, // ボブのチーム
'user_id' => U12345, // ボブのユーザーID
'entity_id' => C12345, // #proj-marketing-campaign
'permission' => ['ARCHIVE_CHANNEL'] // ボブがこのチャンネルで何をしようとしているか
)
感想: これ見ると もうちょっといい感じのID体系が欲しくなるのでは...? となってくる

余談: Flannel
Application Level Edge Cache to Make Slack Scale

Client Architecture
Client は Bob が Channels Admin かどうかを気にしない
Client は Bob が 「そのチャンネルをArchiveできるかどうか」だけが気になる。
Clientは起動時にessential な permission情報を読取る。
初期のpermission setはreduxにcacheされる。
admin が userに新たなroleをassignしたら、clientは real-time messageを受け取り、role/permissionを受け取る。
そのdispatch によって UI components も updateされる。

Roll Out 戦略
- Slack Webアプリ内に存在するループバックgRPCサービスを作成する (切り替えのgateway的なやつ? ストラングラーパター?)
- 社内ワークスペースに展開する
- パイロット顧客に展開
- ダークモードで外部サービスから読み取る
- 認可サービスからデータを取るが、実際には使わない。
- 結果をログに残す
- ライトモードでサービスから読み取る

個人的な学びまとめ
- Slack の権限管理は意外とシンプル
- 細粒度といってもやってることは RBACの範囲内
- Business Plan 向けに 管理者のロールの種別を細分化
- Enterprise Plan 向けに カスタムロール(これもRBAC)
- 細粒度といってもやってることは RBACの範囲内
- Chatサービスは意外と細粒度認可の要求が弱いんだなという感想
- Client視点の低レイテンシのために ニアリアルタイムで権限情報を反映するためのキャッシュがあるのは面白い
- 正確さ、リアルタイム性は一定犠牲にしている
- 権限やroleへの関心はもたず、あるアクションが実行可能か? というレベルに抽象化されている。
- Flannel という Cache for Application の仕組みがもとからある
- Rollout 戦略はかなり参考になる
- ストラングラーパターンの準備 -> 社内利用 -> Pilot利用 -> ダークモード -> ライトモード
- ダークモード(ログにだけ仕込んで実際は動作しない)はいいかも。