BigQuery のリソースへのアクセスを IAM Conditions とリソース名で制御してみた

BigQuery のリソースへのアクセスを IAM Conditions とリソース名で制御してみた

Clock Icon2024.12.22

Google Cloud データエンジニアのはんざわです。
クラスメソッドの Google Cloud Advent Calendar 2024 の 18 日目のブログです。(投稿がだいぶ遅れてしまいました...)

https://qiita.com/advent-calendar/2024/cm-google-cloud

今回のブログでは、BigQuery のデータセットやテーブルへのアクセスを IAM Conditions とリソース名を使って、よりきめ細かく制御する方法を紹介します。

タグで制御する場合の問題点

以前のブログで、IAM Conditions とタグを用いて BigQuery へのアクセスを制御する方法を紹介しました。

https://dev.classmethod.jp/articles/gcp-bigquery-access-control-iam-conditions-with-tag-summary

タグによる制御は、異なる環境ごとのタグの付与などプロジェクト全体でタグの整備が進んでいたり、これから注力していく場合に、非常に有効な手段だと思います。

しかし、タグを利用するためには、Resource Manager のタグ機能やタグを管理するための仕組みを別途導入・運用する必要があります。少数のデータセットや数人のユーザーにのみアクセスを制限したいといったピンポイントな要件には、やや大掛かりになるという課題があります。

本ブログでは、このような問題の解決策として、データセット名やテーブル名といったリソース名に基づいてアクセスを制御する方法を紹介します。

アクセス制御に利用可能なリソース名

https://cloud.google.com/iam/docs/conditions-resource-attributes?hl=ja

BigQuery でアクセス制御に利用可能なリソース名は、全部で 4 つです。

  • データセット:projects/<PROJECT_ID>/datasets/<DATASET_ID>
  • モデル:projects/<PROJECT_ID>/datasets/<DATASET_ID>/models/<MODEL_ID>
  • ルーティン:projects/<PROJECT_ID>/datasets/<DATASET_ID>/routines/<ROUTINE_ID>
  • テーブル:projects/<PROJECT_ID>/datasets/<DATASET_ID>/tables/<TABLE_ID>

IAM Conditions でこれらのリソース名と一致する場合に API の操作を許可する条件を付与することで、リソース名に基づいた柔軟なアクセス制御を実現できます。

実際に試してみる

ここから具体的なユースケースを例に、実際にアクセス制御を試してみたいと思います。

ユースケースの例

  1. 特定のデータセット配下のテーブルにのみアクセスを許可する
  2. 特定のテーブルにのみアクセスを許可する

1. 特定の名前のデータセット配下のテーブルにのみアクセスを許可する

前提として、以下のリソースが準備済みであると仮定します。

  • アクセスを制限したいサービスアカウント:access-dataset@<PROJECT_ID>.iam.gserviceaccount.com
  • アクセスを許可したいデータセット:iam_conditions_dataset

以下のコマンドで、サービスアカウントに権限と条件を付与します。

# テーブルの API を制限する条件を記述したファイルを作成
cat << EOF > condition_table.json
{
  "title": "iam_conditions_dataset_Table",
  "expression":
    "resource.name.startsWith('projects/<PROJECT_ID>/datasets/iam_conditions_dataset') && resource.type == 'bigquery.googleapis.com/Table'"
}
EOF

# データセットの API を制限する条件を記述したファイルを作成
cat << EOF > condition_dataset.json
{
  "title": "iam_conditions_dataset_Dataset",
  "expression":
    "resource.name.startsWith('projects/<PROJECT_ID>/datasets/iam_conditions_dataset') && resource.type == 'bigquery.googleapis.com/Dataset'"
}
EOF

# テーブルの API の条件を付与した BigQuery Data Viewer の権限を付与
gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member "serviceAccount:access-dataset@<PROJECT_ID>.iam.gserviceaccount.com" \
  --role "roles/bigquery.dataViewer" \
  --condition-from-file condition_table.json

# データセットの API の条件を付与した BigQuery Data Viewer の権限を付与
gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member "serviceAccount:access-dataset@<PROJECT_ID>.iam.gserviceaccount.com" \
  --role "roles/bigquery.dataViewer" \
  --condition-from-file condition_dataset.json

# BigQuery Job User の権限を付与
gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member "serviceAccount:access-dataset@<PROJECT_ID>.iam.gserviceaccount.com" \
  --role "roles/bigquery.jobUser" \
  --condition None

条件の内容は以下の通りです。

  • resource.name.startsWithiam_conditions_dataset データセット名を指定
  • 上記の条件と一致する場合、bigquery.googleapis.com/Tablebigquery.googleapis.com/Dataset の API の操作を許可

注意点として、resource.name == 'projects/<PROJECT_ID>/datasets/iam_conditions_dataset' とすると、データセット自体へのアクセスは許可されますが、配下のテーブルへのアクセスは許可されません。これは、テーブルのリソース名がデータセット名から始まるためです。startsWith を使用することで、データセット配下のすべてのテーブルへのアクセスを許可できます。

次に、このサービスアカウントの権限を借用して、いくつかの bq コマンドを実行します。

# 制限をかけたサービスアカウントの権限を借用
$ gcloud config set auth/impersonate_service_account access-dataset@<PROJECT_ID>.iam.gserviceaccount.com

# データセットの一覧を表示
$ bq ls

> WARNING: This command is using service account impersonation. All API calls will be executed as [access-dataset@<PROJECT_ID>.iam.gserviceaccount.com].
        datasetId         
 ------------------------ 
  iam_conditions_dataset  

# iam_conditions_dataset 配下のテーブル一覧を表示
$ bq ls iam_conditions_dataset

> WARNING: This command is using service account impersonation. All API calls will be executed as [access-dataset@<PROJECT_ID>.iam.gserviceaccount.com].
  tableId   Type    Labels   Time Partitioning   Clustered Fields  
 --------- ------- -------- ------------------- ------------------ 
  sample1   TABLE                                                  
  sample2   TABLE 

# iam_conditions_dataset.sample1 のテーブルにクエリを発行
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM iam_conditions_dataset.sample1'

> WARNING: This command is using service account impersonation. All API calls will be executed as [access-dataset@<PROJECT_ID>.iam.gserviceaccount.com].
 +-----+
 | f0_ |
 +-----+
 |   0 |
 +-----+

サービスアカウント access-dataset@<PROJECT_ID>.iam.gserviceaccount.com は、iam_conditions_dataset データセットとその配下のテーブルに対して、一覧表示やクエリ実行などの操作が許可されていることが確認できます。

2. 特定の名前のテーブルにのみアクセスを許可する

次に、前提として、以下のリソースが準備済みであると仮定します。

  • アクセスを制限したいサービスアカウント:access-table@<PROJECT_ID>.iam.gserviceaccount.com

  • アクセスを許可したいテーブル:iam_conditions_table.all_user_can_not_access

以下のコマンドで、サービスアカウントに権限と条件を付与します。

# テーブルの API を制限する条件を記述したファイルを作成
cat << EOF > condition.json
{
  "title": "iam_conditions_table",
  "expression":
    "resource.name == 'projects/<PROJECT_ID>/datasets/iam_conditions_table/tables/all_user_can_not_access' && resource.type == 'bigquery.googleapis.com/Table'"
}
EOF

# テーブルの API の条件を付与した BigQuery Data Viewer の権限を付与
gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member "serviceAccount:access-table@<PROJECT_ID>.iam.gserviceaccount.com" \
  --role "roles/bigquery.dataViewer" \
  --condition-from-file condition.json

# BigQuery Job User の権限を付与
gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member "serviceAccount:access-table@<PROJECT_ID>.iam.gserviceaccount.com" \
  --role "roles/bigquery.jobUser" \
  --condition None

同様に、サービスアカウントの権限を借用して bq コマンドを実行します。

# 制限をかけたサービスアカウントの権限を借用
$ gcloud config set auth/impersonate_service_account access-table@<PROJECT_ID>.iam.gserviceaccount.com

# iam_conditions_table 配下のテーブル一覧を表示
$ bq ls iam_conditions_table

> WARNING: This command is using service account impersonation. All API calls will be executed as [access-table@<PROJECT_ID>.iam.gserviceaccount.com].
BigQuery error in ls operation: Access Denied: Dataset <PROJECT_ID>:iam_conditions_table: Permission bigquery.tables.list denied on dataset <PROJECT_ID>:iam_conditions_table (or it may not exist).

# iam_conditions_table.all_user_can_not_access のテーブルにクエリを発行
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM iam_conditions_table.all_user_can_not_access'

> WARNING: This command is using service account impersonation. All API calls will be executed as [access-table@<PROJECT_ID>.iam.gserviceaccount.com].
 +-----+
 | f0_ |
 +-----+
 |   0 |
 +-----+

サービスアカウント access-table@<PROJECT_ID>.iam.gserviceaccount.com は、iam_conditions_table データセット内のテーブル一覧の取得は拒否されていますが、iam_conditions_table.all_user_can_not_access テーブルに対してはクエリの発行が許可されていることが確認できます。これは特定のテーブル名 iam_conditions_table.all_user_can_not_access にリクエストを送る場合に、API の操作を許可する条件を付与しているためです。

注意点

BigQuery で IAM Conditions を利用したアクセス制御には、いくつかの制限事項があります。詳細は以下のドキュメントを確認してください。

参考:制限事項

また、タグによるアクセス制御と同様に、リソース名による制御でも否定条件は使用しないようにしましょう。resource.name != resource のような否定条件を使用すると、意図しない過剰なアクセス権が付与されてしまう可能性があります。

参考:否定条件

まとめ

本記事では、BigQuery のデータセットやテーブルへのアクセスを IAM Conditions とリソース名を使って、よりきめ細かく制御する方法を紹介しました。

タグによる制御はプロジェクト全体での一貫性を持たせるのに有効ですが、リソース名による制御は、特定のデータセットやテーブルへのアクセスをピンポイントで制限したい場合に有効です。それぞれの特性を理解した上で、適切な方法を選択する参考になれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.