🚀
BigQuery で特定アカウントが特定データセットにアクセスするのを拒否するタグを利用した設定をTerraformで表現してみる
はじめに
前提
BigQuery のデータセットを、 Terraform の google_bigquery_dataset_iam_binding
や google_bigquery_dataset_iam_member
もしくは google_bigquery_dataset
のなどで、データセット単位での個別のアクセス管理をしていない状態。
やりたかったこと
上記前提があり google_project_iam_member
で、 roles/bigquery.dataViewer
などプロジェクト全体へのアクセス許可しているケースで、そのユーザが特定データセットにアクセスさせたくない場合、どうしたらよいか?
王道メソッド(今回見送り)
- 他のプロジェクトでは、
google_bigquery_dataset_iam_binding
もしくは、google_bigquery_dataset
でのデータセット単位での個別のアクセス管理を導入していたので、それを今回のプロジェクトでも導入する。- 対象プロジェクトが大きく、また検証も困難事情があり、絶対無理ではないが作業コストが大きそうなため、この案は一旦見送った。
今回採用したメソッド
- 該当アカウントのアクセスを拒否したいデータセットに、「タグ」を付与する。
- その特定「タグ」が付与されているデータセットに対しては、該当アカウントのアクセスをiam condition で拒否する。
Terraform 設定サンプル
local "project_id" {
description = ""
type = string
default = "foobar-project"
}
resource "google_service_account" "test_user" {
project = local.project_id
account_id = "test-user"
display_name = "Service Account"
}
local "test_user_roles" {
type = list(string)
description = "test_user roles"
default = [
"roles/bigquery.jobUser",
"roles/bigquery.readSessionUser",
]
}
resource "google_project_iam_member" "test_user" {
project = local.project_id
count = length(local.test_user_roles)
role = element(local.test_user_roles, count.index)
member = "serviceAccount:${google_service_account.test_user.email}"
}
local "access_denied_target_dataset" {
type = list(string)
description = "Access denied target dataset"
default = [
"a_dataset",
"b_dataset"
]
}
resource "google_bigquery_dataset" "datasets" {
for_each = toset(local.access_denied_dataset)
dataset_id = each.key
location = "asia-northeast1"
}
resource "google_tags_tag_key" "target_tag_key" {
short_name = "access"
parent = "projects/${local.project_id}"
}
resource "google_tags_tag_value" "target_tag_value" {
short_name = "target_restricted"
parent = google_tags_tag_key.target_tag_key.id
}
resource "google_tags_location_tag_binding" "tag_bindings" {
for_each = toset(local.access_denied_target_dataset)
parent = "//bigquery.googleapis.com/projects/${local.project_id}/datasets/${each.value}"
tag_value = google_tags_tag_value.target_tag_value.id
location = "asia-northeast1"
}
resource "google_project_iam_member" "deny_service_account_access" {
for_each = toset(local.access_denied_target_dataset)
project = local.project_id
role = "roles/bigquery.dataViewer"
member = "serviceAccount:${google_service_account.test_user.email}"
condition {
title = "deny access"
description = "deny access"
expression = "!resource.matchTag('${local.project_id}/access', 'target_restricted')"
}
}
設定の解説
- サービスアカウント test-user を作成
- BigQuery のジョブ実行 (jobUser) などの IAM ロールを付与(dataViewer は削除)
- a_dataset, b_dataset に target_restricted タグを付与
- タグ付きデータセットには test-user の dataViewer 権限を拒否
ポイントは以下の部分で、google_project_iam_member の condition.expression を使い、特定タグにマッチした場合はアクセス拒否されないが、マッチした場合、アクセス拒否される。
resource "google_project_iam_member" "deny_service_account_access" {
for_each = toset(local.access_denied_target_dataset)
project = local.project_id
role = "roles/bigquery.dataViewer"
member = "serviceAccount:${google_service_account.test_user.email}"
condition {
title = "deny access"
description = "deny access"
expression = "!resource.matchTag('${local.project_id}/access', 'target_restricted')"
}
}
所感
- タグを利用した、BigQueryのアクセス制御は初めてやってみたが、柔軟性があるなと感じた。
- とはいえ、基本的には、データセット単位でのメンバーを定義したアクセス制御を導入するのが望ましいとは思うが...。
- ネットに転がっているタグを使った例が、何故か組織レベルのものが多かったが、別にプロジェクトレベルのタグでも問題ない。
Discussion