[BigQuery] データセットやテーブルのオーナーだと、明示的な権限付与なしでも参照・更新・削除も可能なのか確認してみた

2020.05.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、みかみです。

前回、ロールごとに可能な操作を確認した際、bigquery.datasets.delete 権限が付与されていない BigQuery データ編集者や BigQuery ユーザーのロールで、データセットの削除もできてしまいました。

やりたいこと

  • bigquery.datasets.create 権限だけで、本当にデータセットの削除も実行できるのか確認したい
  • データセット作成権限があれば、更新も実行できるのか確認したい
  • テーブルもデータセットと同様の挙動なのか確認したい

前提

BigQuery のデータセットやテーブルの作成、更新、削除などの操作は、BigQuery Python クライアントライブラリを使用して実行します。クライアントライブラリを実行する環境は準備済みです。

また、カスタムロールやサービスアカウントを作成する権限は持っていることを前提としています。

カスタムロールを作成してサービスアカウントに付与する

前回は事前定義ロールで確認しましたが、より詳細に、権限ごとに可能な操作を確認するため、必要な権限のみ付与したカスタムロールを、GCP 管理コンソールから作成します。

以下の権限を持つカスタムロールを作成しました。

# ロール 権限
1 データセット作成 bigquery.datasets.create
2 テーブル作成 bigquery.tables.create

上記のカスタムロールを、それぞれサービスアカウントに付与しました。

(test_role) [ec2-user@ip-10-0-43-239 test_role]$ gcloud projects add-iam-policy-binding cm-da-mikami-yuki-258308 \
>         --member serviceAccount:bq-table-create@cm-da-mikami-yuki-258308.iam.gserviceaccount.com \
>         --role projects/cm-da-mikami-yuki-258308/roles/104
Updated IAM policy for project [cm-da-mikami-yuki-258308].
bindings:
- members:
  - serviceAccount:bq-table-create@cm-da-mikami-yuki-258308.iam.gserviceaccount.com
  role: projects/cm-da-mikami-yuki-258308/roles/104
- members:
  - serviceAccount:bq-dataset-create@cm-da-mikami-yuki-258308.iam.gserviceaccount.com
  role: projects/cm-da-mikami-yuki-258308/roles/880
(省略)
version: 1

データセットを作成して、参照・更新・削除を実行してみる

bigquery.datasets.create 権限を付与したサービスアカウントで、Python クライアントライブラリからデータセット関連操作を実行してみます。

まずは、以下の Python コードで既存のデータセットを参照してみます。

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json
from pprint import pprint

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-dataset-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)

# get list
datasets = client.list_datasets(credentials.project_id)
for obj in datasets:
    print('get list -------->')
    pprint(vars(obj))

# get
dataset_id = '{}.dataset_1'.format(credentials.project_id)
dataset =  client.get_dataset(dataset_id)
print('get -------->')
pprint(vars(dataset))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python dataset_get.py
Traceback (most recent call last):
  File "dataset_get.py", line 23, in <module>
    dataset =  client.get_dataset(dataset_id)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 586, in get_dataset
    retry, method="GET", path=dataset_ref.path, timeout=timeout
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 556, in _call_api
    return call()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 286, in retry_wrapped_func
    on_error=on_error,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 184, in retry_target
    return target()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/_http.py", line 423, in api_request
    raise exceptions.from_http_response(response)
google.api_core.exceptions.Forbidden: 403 GET https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1: Access Denied: Dataset cm-da-mikami-yuki-258308:dataset_1: User does not have bigquery.datasets.get permission for dataset cm-da-mikami-yuki-258308:dataset_1.

list_datasets でデータセットの一覧を参照しようとしたところ、パーミッションエラーにはなりませんでしたが、データが取得できません。

get_dataset で既存のデータセット名を指定して参照しようとしてみても、パーミッションエラーで参照できませんでした。

続いて、新規にデータセットを作成します。

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-dataset-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)

# create
dataset_id = '{}.dataset_1_sub'.format(credentials.project_id)
dataset = bigquery.Dataset(dataset_id)
dataset.location = "asia-northeast1"
dataset = client.create_dataset(dataset)
print("Created dataset {}.{}".format(dataset.project, dataset.dataset_id))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python dataset_create.py
Created dataset cm-da-mikami-yuki-258308.dataset_1_sub

bigquery.datasets.create 権限を付与しているので、問題なく作成できました。

今作成したデータセットを参照してみます。

(省略)
# get list
datasets = client.list_datasets(credentials.project_id)
for obj in datasets:
    print('get list -------->')
    pprint(vars(obj))

# get
#dataset_id = '{}.dataset_1'.format(credentials.project_id)
dataset_id = '{}.dataset_1_sub'.format(credentials.project_id)
dataset =  client.get_dataset(dataset_id)
print('get -------->')
pprint(vars(dataset))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python dataset_get.py
get list -------->
{'_properties': {'datasetReference': {'datasetId': 'dataset_1_sub',
                                      'projectId': 'cm-da-mikami-yuki-258308'},
                 'id': 'cm-da-mikami-yuki-258308:dataset_1_sub',
                 'kind': 'bigquery#dataset',
                 'location': 'asia-northeast1'}}
get -------->
{'_properties': {'access': [{'role': 'WRITER',
                             'specialGroup': 'projectWriters'},
                            {'role': 'OWNER', 'specialGroup': 'projectOwners'},
                            {'role': 'OWNER',
                             'userByEmail': 'bq-dataset-create@cm-da-mikami-yuki-258308.iam.gserviceaccount.com'},
                            {'role': 'READER',
                             'specialGroup': 'projectReaders'}],
                 'creationTime': '1589888206510',
                 'datasetReference': {'datasetId': 'dataset_1_sub',
                                      'projectId': 'cm-da-mikami-yuki-258308'},
                 'etag': '6obv64K4PRzPKi6botd80g==',
                 'id': 'cm-da-mikami-yuki-258308:dataset_1_sub',
                 'kind': 'bigquery#dataset',
                 'lastModifiedTime': '1589888206510',
                 'location': 'asia-northeast1',
                 'selfLink': 'https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1_sub'}}

自分で作成したデータセット情報であれば、サービスアカウントに bigquery.datasets.get 権限を付与していなくても参照することができました。

さらに、新規作成したデータセットを更新してみます。

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-dataset-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)

# get
dataset_id = '{}.dataset_1_sub'.format(credentials.project_id)
dataset =  client.get_dataset(dataset_id)

# update
dataset.description = 'ロール確認用'
dataset = client.update_dataset(dataset, ['description'])
print("Updated dataset description: {}".format(dataset.description))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python dataset_update.py
Updated dataset description: ロール確認用

GCP 管理コンソールからも、データセットの description が更新されたことが確認できました。

最後に、作成したデータセットを削除してみます。

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-dataset-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)


# get
dataset_id = '{}.dataset_1_sub'.format(credentials.project_id)
dataset =  client.get_dataset(dataset_id)

# delete
client.delete_dataset(dataset)
print("Deleted dataset {}.{}".format(dataset.project, dataset.dataset_id))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python dataset_delete.py
Deleted dataset cm-da-mikami-yuki-258308.dataset_1_sub

データセットを作成したサービスアカウントであれば、更新と同様、削除も bigquery.datasets.delete 権限の付与なしで実行でもきることが確認できました。

テーブルを作成して、参照・更新・レコード追加・削除を実行してみる

今度は bigquery.tables.create 権限のあるサービスアカウントで、データセット同様、Python クライアントライブラリからテーブル関連の操作を実行してみます。

既存テーブルを参照しようとしてみると・・・

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json
from pprint import pprint

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-table-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)

# get
table_id = '{}.dataset_1.table_dogs'.format(credentials.project_id)
table = client.get_table(table_id)
pprint(vars(table))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python table_get.py
Traceback (most recent call last):
  File "table_get.py", line 17, in <module>
    table = client.get_table(table_id)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 679, in get_table
    retry, method="GET", path=table_ref.path, timeout=timeout
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 556, in _call_api
    return call()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 286, in retry_wrapped_func
    on_error=on_error,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 184, in retry_target
    return target()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/_http.py", line 423, in api_request
    raise exceptions.from_http_response(response)
google.api_core.exceptions.Forbidden: 403 GET https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs: User does not have bigquery.tables.get permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs.

bigquery.tables.get 権限を付与していないので、当然パーミッションエラーとなります。

では、データセットと同じく自分で作成したテーブルなら参照できるのかどうか、確認してみます。

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json
from pprint import pprint

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-table-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)

table_id = '{}.dataset_1.table_dogs_2'.format(credentials.project_id)
schema = [
    bigquery.SchemaField("id", "INTEGER", mode="REQUIRED"),
    bigquery.SchemaField("name", "STRING", mode="REQUIRED"),
]
table = bigquery.Table(table_id, schema=schema)
table = client.create_table(table)
print("Created table {}.{}.{}".format(table.project, table.dataset_id, table.table_id))

# get
table = client.get_table(table_id)
pprint(vars(table))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python table_create.py
Created table cm-da-mikami-yuki-258308.dataset_1.table_dogs_2
Traceback (most recent call last):
  File "table_create.py", line 25, in <module>
    table = client.get_table(table_id)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 679, in get_table
    retry, method="GET", path=table_ref.path, timeout=timeout
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 556, in _call_api
    return call()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 286, in retry_wrapped_func
    on_error=on_error,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 184, in retry_target
    return target()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/_http.py", line 423, in api_request
    raise exceptions.from_http_response(response)
google.api_core.exceptions.Forbidden: 403 GET https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2: User does not have bigquery.tables.get permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2.

権限のあるテーブル作成処理は問題なく実行できましたが、データセットとは異なり、テーブルの場合は作成したアカウントであっても参照権限がないと参照できませんでした。

では、新規作成したテーブルにレコード追加はできるのか確認してみます。

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-table-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)

table_id = '{}.dataset_1.table_dogs_2'.format(credentials.project_id)
schema = [
    bigquery.SchemaField("id", "INTEGER", mode="REQUIRED"),
    bigquery.SchemaField("name", "STRING", mode="REQUIRED"),
]
table = bigquery.Table(table_id, schema=schema)
table = client.create_table(table)
print("Created table {}.{}.{}".format(table.project, table.dataset_id, table.table_id))

val = [(1, 'ボルゾイ')]
ret = client.insert_rows(table, val)
print("Inserted row {}".format(val))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python table_insert.py
Created table cm-da-mikami-yuki-258308.dataset_1.table_dogs_2
Traceback (most recent call last):
  File "table_insert.py", line 24, in <module>
    ret = client.insert_rows(table, val)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 2425, in insert_rows
    return self.insert_rows_json(table, json_rows, **kwargs)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 2569, in insert_rows_json
    timeout=timeout,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 556, in _call_api
    return call()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 286, in retry_wrapped_func
    on_error=on_error,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 184, in retry_target
    return target()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/_http.py", line 423, in api_request
    raise exceptions.from_http_response(response)
google.api_core.exceptions.Forbidden: 403 POST https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2/insertAll: Access Denied: Dataset cm-da-mikami-yuki-258308:dataset_1: User does not have bigquery.datasets.get permission for dataset cm-da-mikami-yuki-258308:dataset_1.

パーミッションエラーですが、エラーメッセージを見ると、bigquery.datasets.get 権限が不足していると怒られました。

...User does not have bigquery.datasets.get permission for dataset cm-da-mikami-yuki-258308:dataset_1.

テーブルに対する操作ですが、データセット参照権限も必要なようです。(クライアントライブラリの実装に依存しているのでしょうか?

作成したテーブルの更新と削除も確認してみます。

from google.cloud import bigquery
from google.oauth2 import service_account
import os
import json
from pprint import pprint

key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/bq-table-create.json')
service_account_info = json.load(open(key_path))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
client = bigquery.Client(
    credentials=credentials,
    project=credentials.project_id,
)

table_id = '{}.dataset_1.table_dogs_2'.format(credentials.project_id)
schema = [
    bigquery.SchemaField("id", "INTEGER", mode="REQUIRED"),
    bigquery.SchemaField("name", "STRING", mode="REQUIRED"),
]
table = bigquery.Table(table_id, schema=schema)
table = client.create_table(table)
print("Created table {}.{}.{}".format(table.project, table.dataset_id, table.table_id))

# update
try:
    table.description = 'ロール確認用'
    table = client.update_table(table, ['description'])
    print("Updated table description: {}".format(table.description))
except Exception as e:
    print('ERROR!! --> {}'.format(e))

# delete
try:
    client.delete_table(table)
    print("Deleted table {}.{}.{}".format(table.project, table.dataset_id, table.table_id))
except Exception as e:
    print('ERROR!! --> {}'.format(e))
(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python table_edit.py
Created table cm-da-mikami-yuki-258308.dataset_1.table_dogs_2
ERROR!! --> 403 PATCH https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2: User does not have bigquery.tables.get permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2.
ERROR!! --> 403 DELETE https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2: User does not have bigquery.tables.delete permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2.

更新、削除共にパーミッションエラーとなりました。

削除は User does not have bigquery.tables.delete permission ... とのことなので、設定した権限通りのエラーですが、更新のエラーメッセージは User does not have bigquery.tables.get permission ... とのことで、テーブルの参照権限が必要なようです。

参照権限を追加して、レコード追加とテーブル更新ができるか確認してみる

レコード追加に必要な権限は bigquery.tables.updateData ですが、エラーメッセージではデータセットの参照権限不足で怒られていました。

では、自分で作成したテーブルであれば、参照権の追加のみでレコード追加できるのか、確認してみます。

bigquery.datasets.get 権限を追加して再実行してみます。

(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python table_insert.py
Created table cm-da-mikami-yuki-258308.dataset_1.table_dogs_2
Traceback (most recent call last):
  File "table_insert.py", line 24, in <module>
    ret = client.insert_rows(table, val)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 2425, in insert_rows
    return self.insert_rows_json(table, json_rows, **kwargs)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 2569, in insert_rows_json
    timeout=timeout,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 556, in _call_api
    return call()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 286, in retry_wrapped_func
    on_error=on_error,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 184, in retry_target
    return target()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/_http.py", line 423, in api_request
    raise exceptions.from_http_response(response)
google.api_core.exceptions.Forbidden: 403 POST https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2/insertAll: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2: User does not have bigquery.tables.get permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2.

bigquery.tables.get 権限も必要なようです。

権限を追加して再度実行してみます。

(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python table_insert.py
Created table cm-da-mikami-yuki-258308.dataset_1.table_dogs_2
Traceback (most recent call last):
  File "table_insert.py", line 24, in <module>
    ret = client.insert_rows(table, val)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 2425, in insert_rows
    return self.insert_rows_json(table, json_rows, **kwargs)
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 2569, in insert_rows_json
    timeout=timeout,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/bigquery/client.py", line 556, in _call_api
    return call()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 286, in retry_wrapped_func
    on_error=on_error,
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/api_core/retry.py", line 184, in retry_target
    return target()
  File "/home/ec2-user/test_role/lib64/python3.7/site-packages/google/cloud/_http.py", line 423, in api_request
    raise exceptions.from_http_response(response)
google.api_core.exceptions.Forbidden: 403 POST https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2/insertAll: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2: User does not have bigquery.tables.updateData permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2.

最終的には bigquery.tables.updateData 権限不足でパーミッションエラーとなりました。

続いてテーブル更新処理も、エラーメッセージにあった bigquery.tables.get 権限は付与した状態で再確認してみます。

(test_role) [ec2-user@ip-10-0-43-239 test_role]$ python table_edit.py
Created table cm-da-mikami-yuki-258308.dataset_1.table_dogs_2
ERROR!! --> 403 PATCH https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2: User does not have bigquery.tables.update permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2.
ERROR!! --> 403 DELETE https://bigquery.googleapis.com/bigquery/v2/projects/cm-da-mikami-yuki-258308/datasets/dataset_1/tables/table_dogs_2: Access Denied: Table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2: User does not have bigquery.tables.delete permission for table cm-da-mikami-yuki-258308:dataset_1.table_dogs_2.

こちらもやはり、bigquery.tables.update 権限がないと、テーブル作成者であっても更新できないことが確認できました。

データセットのオーナー権限

テーブルとは異なり、データセットの場合は個別にアクセス権限を設定することができます。

BigQuery 管理画面から「共有データセット」をクリックして、クライアントライブラリから作成したデータセットのアクセス権を確認してみると、データセットを作成したサービスアカウントには BigQuery データオーナー権限が付与されていました。

ドキュメントにも、以下の記載がありました。

また、bigquery.datasets.create 権限を持つユーザーがデータセットを作成すると、そのデータセットに対する bigquery.dataOwner アクセス権がユーザーに付与されます。bigquery.dataOwner アクセス権により、ユーザーは自身が作成したデータセットを更新できます。

自分で作成したデータセットにおいてはデータオーナー権限がつくため、データセットやテーブル、ルーティンなどに関する操作も実行できるようになるわけですね。

まとめ(所感)

  • データセットを作成したアカウントにはデータオーナー権限が付くため、参照・更新・削除可能
  • テーブルは作成したアカウントであっても、参照・更新・削除を行うためには権限付与が必要
  • Python クライアントライブラリ経由でテーブルの更新やレコード追加を行うには、合わせて参照権限も付与する必要あり

権限やロールの観点のみから挙動を確認していた時には、create 権限だけでなぜ delete も実行できるのかよく分かりませんでしたが、作成したデータセットにオーナー権限が付与されることが分かり、納得しました。

今後もし、データセット同様テーブル単位でもアクセス制御ができるようになると、テーブルに対してもオーナー権限が付与されるようになるかもしれず、カスタムロールを使用した権限管理には注意が必要だと思いました。

参考