BigQuery権限設計：部署ごとに最適なデータアクセスを実現する方法

### はじめに

[リンクアンドモチベーション Advent Calendar 2024](https://qiita.com/advent-calendar/2024/lmi)の21日目を担当します。弊社のデータチームで、データ分析の基盤の開発を担当しております。

### 背景

弊社では今年から、データチームのメンバーを対象とし、BigQueryデータマートの開発・運用を開始しました。([小さく始めるBigQuery：お試し利用から本格導入への道のり](https://findy-tools.io/products/bigquery/49/337))。

これを利用している弊社データチームのアナリストから、次のような相談を受けました。

「これ、(経理が管理する)弊社の営業やコンサルが利用する帳票のデータ基盤に使えたりしない？」

弊社はかなりの割合スプレッドシートを用いてPDCA管理を行っているため、要するに「**スプシのデータコネクタを用いたBQ連携を促進したい！**」ということです。

スプレッドシートでデータを活用するにあたり、利用する部署ごとに適切なデータを提供し、不要なデータへのアクセスを制限する必要が出てきました。そこで問題になるのが『権限』の話です。

これまでデータを自発的に使ってきていない、さまざまな部署の方が利用する、ということで

- A部署にはA部署のデータを、B部署はB部署のデータを見せたい
- ユーザーのデータリテラシーは、既存ユーザー(開発者)ほど高くない

という条件のもと、**ある程度データマートの利用方法をこちらでハンドリングできないか**、と試行錯誤しました。

### 実現方法

「普段データを使わない人でも、**必要最小限の権限**で、BQのデータをスプシで扱える」ために必要な権限として、今回は以下3つのレイヤで権限セットを作成し、管理することにしました。

1. プロジェクト単位でユーザーに付与する権限(IAM管理)
    1. resourcemanager.projects.get
    2.  bigquery.jobs.create
2. ユーザーが閲覧したいデータベース単位でユーザーに付与する権限
    1. bigquery.datasets.get
    2. bigquery.tables.list
3. ユーザーが利用したいテーブル単位でユーザーに付与する権限
    1. bigquery.tables.get
    2. bigquery.tables.getData

(参考：[BigQuery アクセス権設定まとめ & グループ設計例](https://qiita.com/na0/items/dcb7030a1b5c5e707807) )

### 詳細

上記6つの権限でできることは以下になります。

1. プロジェクト単位のIAM権限
    
    以下2つは「IAMでユーザーに付与しないと効力を発揮しないもの」です。
    
    1. resourcemanager.projects.get
        
        個々のプロジェクトの表示権限。
        
        スプシの「データコネクタ」→「BigQueryに接続」→「データ接続の追加」で、接続されるクラウドプロジェクトを表示するために必要。
        
    2. bigquery.jobs.create
        
        BQからデータを取得、抽出やピボットテーブルの作成に必要な権限
        
        BQのデータを実際に取得し、抽出やピボットテーブルを組むために必要。
        
2. データベース・テーブル単位でユーザーに付与する権限
    
    具体のデータセットやテーブルに関するロールは下記4つでした。
    
    1. bigquery.datasets.get
        
        データセットを取得するのに必要な権限
        
    2. bigquery.tables.list
        
        データセットに含まれるテーブルの一覧を取得するのに必要な権限
        
    3. bigquery.tables.get
        
        テーブルを取得するのに必要な権限
        
    4. bigquery.tables.getData
        
        テーブルの中身のデータを取得するのに必要な権限
        

### 比較した案

この形になるまでに検討した他の方法と、それを選択しなかった理由も合わせて説明します。

1. 権限をつけるレイヤの検討
    
    今回、プロジェクト・データセット・テーブルの3レイヤで権限をつけましたが、もっとシンプルに、以下のような検討も行いました。
    
    - 必要な権限をプロジェクトレイヤに全部つける
    - テーブルレイヤの権限をデータセットレイヤにつける
    
    これらを実行すると、**現場が必要最小限以上のデータを閲覧できてしまう**ことになってしまいます。それによって、
    
    - 最初から多数のデータセットが目について(一覧として表示されて)しまい、利用しづらい
    - A部署の人が他部署のデータを見て、利益にならないことを行う可能性がある
    
    というUXとリスクの面からこれらは棄却しました。
    
2. 「部署ごとに見れるデータを制限する」やり方の検討
    
    今回、「ローデータとして持ってくるのは全社データのみ、それをBigQuery上で部署上で見れるようにする」という条件であったため、2つの実装方針がありました。
    
![image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3509672/81111581-0142-c0de-9f02-702a713b3f01.png)

    
1. Dataform上で分割し、部署ごとにテーブルを作成し、アクセス権限で管理する方法
2. テーブルは一つだが、[行アクセスポリシー](https://cloud.google.com/bigquery/docs/managing-row-level-security?hl=ja)を用いて閲覧できる行を制限できる方法
    
    これらは以下の観点で比較を行い、今回はa.部署ごとのテーブル作成を選択しました。
    
|  | ユーザーの利便性 | 運用コスト | 開発工数・部署変更時の保守工数 | 通常の保守工数 |
| --- | --- | --- | --- | --- |
| a. 部署ごとにテーブル作成し、データベース・テーブル単位で権限を管理 | ◯ 不具合なく利用可能| ◯ 先に切り分けておくことでスキャン量を減らせる | × 部署ごとにテーブルの追加が必要 部署変更のたびにシートを追加・削除する必要あり | ◯ 利用者が変化する際、IAM, テーブル単位のUI操作ですむ |
| b. 行アクセスポリシーを用いて行レベルで権限を管理 | × スプシでデータを抽出するときに「ポリシーで制限されている」の警告が表示される| × 毎回「全社データ」をもとに抽出するためスキャンデータが増大する | ◯ 作成するシートは1つで済む | × 利用者が変化する際、更新のたびにクエリを書き直す必要がある |

### 結論
プロジェクト単位、データベース単位、テーブル単位で権限を整理し、最小限の権利を付与することでハンドリングすることを実現しました。

### 学び

これを実現するために様々なレイヤでの制限を考えたのですが、特に最後の行アクセスポリシーの部分で明確に学んだことは以下になります。

::: note info
要件を満たせる権限の付け方が複数ある場合、できる限り上流の方で権限を整理すべき！
:::