BuildingBlockのデザインパターンに従って、組織単位の活用測定と権限管理をした話

# はじめに

こんにちは。株式会社タイミーのデータ統括部BIチームに所属してます。オコドンです

全社的にLookerの活用を推進していくために、既存の権限管理方法をLookerの提唱するデザインパターンに沿ってリプレイスしてみました。
Lookerが推奨する権限管理方法は知ってるけど、実践すると何かいいことあるの？って方の参考になればと思います。


## 既存の管理方法と課題感

これまで弊社ではLookerの権限管理にチームとしてリソースを割けておらず、メンバーへの権限付与はLookerで用意されているデフォルトのRoleをそのまま紐づけている状態でした

<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/966fbfff-23a2-9f99-4ea3-be31ed54e889.png"width="400">
<caption>図: 以前のLooker権限の管理方法</caption>

このような権限付与体制だと以下のような課題が解決できず、Looker利用推進をしていくための現状把握や詳細な権限設計がやりづらい状態でした
- Lookerを"どのチームが"活用しているかわからない
- "どのチーム"が"どのライセンス"を"どれだけ"持っているかわからない
- 開発権限を持つメンバー間でも、〇〇ができる権限保持者と△△ができる権限保持者など権限が詳細化していくと管理できない
- ロールの付け替えなどをする場合
- フォルダ単位の閲覧権限設計をチーム単位で実行したいができない。

そこでLookerが公式ドキュメント等でも推しているBuildingBlockの概念に従って権限管理を行うことで、これらの課題を解決しようと試みました。

## Building Blockとは？
<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/8a5a77a4-099d-c8e9-a47c-da000866cc6a.png"width="300">

上記図のように、ModelSet/PermissionSet=>Role=>Group=>Userと継承されていく権限を付与できるのがBuildingBlockの簡単な説明となります
詳細はこちら<a href="https://cloud.google.com/looker/docs/access-control-and-permission-management#building_blocks_youll_need_to_understand">公式ドキュメント</a>に記載されています。

- Roleは1つのPermissionSetと1つのModelSetを組み合わせたもの。
    - PermissionSet: 1つ以上のPermissionで構成されます
    - ModelSet: 1つ以上のModelで構成されます。

このRoleをUser,Groupに適応することで、ModelSetで定義したModel群に対して、PermissionSetで定義したPermission群の権限を与えることができます。
- RoleはユーザーもしくはGroupに対して付与することができます。
    - ユーザー自身が複数のRoleを付与されている場合、付与されている全てのRoleを継承します
    - ユーザー自身が複数のGroupに属している場合、所属している全てのGroupに紐づくRoleを継承します
    - ユーザー自身にRoleが付与されていて、ユーザーが所属するGroupもある場合、ユーザー自身に付与されているRoleと所属しているGroupのRole全てを継承します。

この積み重ねていくような概念を利用して、綺麗に権限設計をしていきたいと考えたのが始まりです

## チーム単位の活用測定設計
BuildingBlockの概念を頭に入れた上で、まずは一番やりたかった「どのチームがどう活用しているか」を知ることができるように、会社の組織図に沿ったGroupを作ることを考えていきます。
例として所属する組織にペリカンさんチームが存在すると仮定します。
<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/df8852f1-2b32-232f-975b-85e341ba5707.png"width="300">
今回の権限設計では、組織図上でペリカンさんチームになっているメンバーを「ペリカンさんチームGroup」に入れて、そのGroupに対して「チーム判別Role」と命名したロールを割り当てています。(※注1)
チーム判別Roleにはライセンスを消費しない適当なPermissionSet(今回だと`mobile_app_access permission`だけ)を割り当てています。

<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/585be241-d0c9-f15e-43a6-ac17ddf7b0d8.png"width="500">
この実装によってBuildingBlockのベースの部分に「チームを判別する機能」だけを持たせたような形になります

この権限付与ではライセンス消費が発生しないので、正社員として組織図上に登録されているメンバー全員をlooker上にアカウントを作り、チーム判別のGroupを作成して紐づける作業を実行しました。
こうすることでLookerの管理機能で用意されているUserActivityの探索環境などを使うことで、「どのチームが何人いて、そのうち何人がライセンスを持っていて、そのうち何人が活用しているか」まで追える形となります。

:::note warn
※注1
数ヶ月前にこの設計を考えていたときは、Role無しのGroupが作れないと勘違いor動作確認ミスをしており、このような設計になっています。最近動作確認したところGroupはRole無しでも作ることが出来たため、Roleを付与しないGroupを作るだけでやりたかったことが出来ます。
一応利点として「チーム判別Groupに所属していないユーザー」を出力するより「チーム判別Roleが付与されていないユーザー」を出力する方がAdminのUserExplorer上ではやりやすいため、チーム判別付与漏れがチェックしやすいのと、ライセンス消費などもされずコストがかからないためそのままにしています。
:::

#### チームの階層とGroupについて
ホラクラシー型組織でもない限り、大抵の会社組織は以下のような階層構造になっているかと思います。
<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/c8b860b2-202c-6c85-2317-37f250e977e5.png"width="500">
つまりペリカンさんチームのメンバーは、鳥類グループのグループメンバーでもあり陸生生物部門の部門メンバーでもあるわけです。
"全社の"意思決定確度を向上させたいBIとしては `チーム単位でLookerが活用されているか`,`グループ単位でLookerが活用されているか`, `部門単位でLookerが活用されているか`を把握して改善を進めていきたいです。
なのでそれを確認できるように、以下図で示した組織図の階層構造上で属している組織体ごとにチーム判別のGroupを付与しています。

| 組織判別用のGroupを1人に対して複数個紐付け | BuildingBlockの概念図だとこんな感じ|
| --- | --- |
| <img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/1034fb6d-03c3-062f-6693-f8dd8bbb7771.png"width="500"> | <img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/514570f5-14b6-d8c0-4a47-3f2a6f2734ef.png"width="500"> |

これによって組織のレイヤーごとにUserActivity explorer上で探索可能な形になりました。
<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/360a3f2e-b517-8376-2679-2cae8751aa17.png"width="500">


## ライセンス数管理と詳細権限設計

次はライセンス数の管理がちょっとやりづらい問題と、細やかな権限付与をカオスにすることなく実装したいニーズをBuildingBlockに従って解決していきます。


Lookerの権限管理は少しややこしく、<a href="https://cloud.google.com/looker/docs/admin-panel-users-roles?hl=ja#permissions_and_looker_licenses">公式ドキュメント</a>でも説明されている通り、ユーザーに継承されているpermissionのうち、ライセンス消費に値するpermissionが付与されていた場合にライセンスが消費されたと判断されます。
例えば
```
- access_data
```
が付与されていたら閲覧ライセンスが消費される形となり

```
- develop
- manage_models
- see_datagroups
- see_logs
- see_pdts
- sudo
```
これら6つのpermissionのうちどれか１つでも付与されていたら開発ライセンスが消費される形となります。
50個弱あるpermissionの中で、どれがライセンスを消費するpermissionなのかを意識しながら権限を管理するのは大変です。

そこでデフォルトで用意されていた`開発権限Role/編集権限Role/閲覧権限Role`から、`開発/編集/閲覧に必要最低限のpermission`を抜き出して、各種ライセンスで`最低限できることを定義したRole`を付与したGroupを作ることで、ライセンス付与をGroupで管理しつつ各種権限のベースとなる権限を作成しました。

|  ライセンス消費管理用Roleの作り方イメージ図 | BuildingBlockで表すとこんな感じ|
| --- | --- |
| <img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/47f3908c-1563-5585-d5ec-4a424a030b1c.png"width="500"> |<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/1e2fd29f-4e41-ee8f-4a62-3f64cb02504e.png"width="500"> |

#### 詳細な権限設計

ベースの権限+αの権限付与を柔軟に実現するために、BuildingBlockの考え方に従った設計を行いました
ベースとなる最低限の権限の上にカスタムなRoleを積み木のように載せていく形です

デフォルトで用意されているFatなRoleをそのまま付与する既存の運用だと実現できなかったことには以下のようなことが挙げられます。

- 開発者権限からsudo(他のユーザーとしてログインして操作可能となる権限)permissionは抜きたいが、Adminにアサインした開発メンバーのみsudo権限を持たせたい
- デフォルトの編集権限ではLookerのUserActivityが見られないが、チームリーダーやLooker推進メンバーなどの編集権限ユーザーにはUserActivityが見られるようにしたい
- 個人情報系が含まれるモデルを切り出して、そのモデルへのアクセスは特定のメンバーのみ可能にしたい

これらのニーズに対して
- sudoのpermissionだけを切り出したRoleを作成してsudo可能グループに付与する
- UserActivity閲覧権限だけを切り出したRoleを作成してUserActivity閲覧可能グループに付与する
- 個人情報系のモデルセットへの閲覧/編集権限を切り出したRoleを作成して、個人情報系閲覧可能グループに付与する

などのRole,Group作成を行うことで管理を可能にします。

<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/6173e4b0-fd32-121d-ddf0-37b9ee682afd.png"width="500"> 
最終的にはこのように、`組織を分類する権限`,`ライセンスのベースとなる権限`,`ベースに含まれないカスタムな権限`を順に積み重ねたような形となります。
それぞれの権限はGroupに付与されるので、Group単位で権限管理が可能となり、カスタマイズ性と管理しやすさが両立した権限管理体制とできました。

ごちゃごちゃしてきたのでGroup, Role, Permission, Modelを図にしてまとめると以下のようになります
<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/53dd19d9-c074-79ce-dac2-d2f58152696b.png"width="800"> 

## フォルダ単位の権限管理について

上記図を見て、1Groupに対して1RoleなのだとしたらGroupを挟まずにRoleをそのままメンバーに紐づければいいのでは？と思われた方も多いかと思います。
僕も当初そう思ったのですがフォルダ単位での権限管理を今後行っていくことを考えると、Groupを経由する方針に統一した方がやりやすそうだと考えて、Group経由の権限付与にしている背景があります。

LookerはダッシュボードやLooksなどをフォルダに格納することができ、共有フォルダ以下にフォルダの階層を構築することで、全メンバーがフォルダごとにGroupingされたアウトプットを閲覧できる形になっております。
フォルダ単位で閲覧/編集権限を設定できるのですが、その権限の付与単位が`ユーザーorグループ`であったため、グループを全てのRoleに紐づけている形です
<img class="fit-picture"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/1d811b3f-b16e-fcd2-a592-93f232d83e26.png"width="800"> 

例えば
- 〇〇チームの人達のアウトプットを入れるフォルダでは、Adminを除く他チームの編集権限は無くしてほしい
- 個人情報系のアウトプットを入れるフォルダには、個人情報閲覧可能グループメンバー以外は閲覧/編集ができないようにしてほしい
- プロトタイプのデータマートのアウトプットなどを格納するフォルダには、開発メンバーとレビュアー以外は閲覧権限を無くしてほしい

などの想定されるニーズに対応可能となる予定です。

## 今回紹介した権限管理方法の注意点・弱点

閲覧ベース権限を持つメンバーが、何らかのGroup経由で編集ライセンス相当のPermissionを持つRoleを継承した場合
消費されるライセンスは編集権限のライセンスとなります。
そのため、`閲覧権限ライセンス数消費 = 閲覧ベース権限Group人数`の等式が崩れる形となります。

![Looker権限設計-アセスメントレベル.drawio (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981664/82f8c4de-2d96-8c50-4ba4-740767920bce.png)

現在は全然管理できている範囲内ですが、将来的なカオスに備えてこの現象が起きることを防止する策を何か打ちたいと考えています。

## Next To Do

#### 権限付与の自動化・組織図上の移動の反映
弊社内のHR系のデータをBigQueryに取り込んでモデリングをしている最中でして、モデリング完了次第CloudFunctionなどの簡単な実装で権限付与を自動化するフローと組織図上のチーム移動を反映するフローを組みたいと思っております。


#### アセスメントレベルの設計
組織図上のチームごとに`Lookerにアカウントがあるメンバー数`, `〇〇ライセンスを持つメンバー数`, `活用しているメンバー数`などは計測可能になったのですが
計測した結果それがデータアセスメントレベルとして高い状態なのか低い状態なのかをしっかりとは定義できていない状態です。
アセスメントレベル定義のプロジェクトは走り始めており、アセスメントレベルの定義をしっかり固めた上で、全社での活用に向けた目標の設定とそれに向けた推進を行っていきたいです。