Open13

Slack の Role Management 調査

mori5321mori5321

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

mori5321mori5321

これまでのロール

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

ロールへの新たな要件

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

mori5321mori5321

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

RBAC


mori5321mori5321

How this works in practice (実際の仕組み)

  • ユーザーがアクションを実行する

  • そのアクションに必要な権限をチェックする

  • ユーザーが割り当てられたRoleを通じて そのアクションを実行する権限を

    • もっている => 許可
    • もっていない => レガシーモデル(pre-defined role)にFallbackする
  • 権限チェックは常にサーバーサイドで行う

  • 一方でClient Sideでは その時点で ユーザーに表示されるであろうUI コンポーネントを予測に基づき、non-authoritative(非権威的に) に 表示している

    • 低レイテンシーを重視したいため、このnon-authoritativeなcheck は Flannel エッジキャッシュに対して行う
    • 結果として クライアント再度での権限チェックは、ニアリアルタイムでの反映になる
mori5321mori5321

3つのシステムロール

Channel Admin

チャンネルのアーカイブ、名前の変更、プライベートチャンネルの作成、パブリックチャンネルのプライベート化

Users Admin

ワークスペースへのユーザーの追加、削除、組織のユーザーグループを閲覧する

Roles Admin

ロール自体を管理し、各ロールにユーザーを割り当てる

mori5321mori5321

Backend の 設計

Vitess store というやつに 永続化しているらしい。(分散的なRDB? NoSQL?)
https://slack.engineering/scaling-datastores-at-slack-with-vitess/
sharding architecture, scale by user_id

Vitess store には もともと Slack Webapp のデータもはいってるっぽいな。
data drift を防ぐために centralized する選択をしたと。

mori5321mori5321

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体系が欲しくなるのでは...? となってくる

mori5321mori5321

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される。

mori5321mori5321

Roll Out 戦略

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

個人的な学びまとめ

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