業界・業務から探す
導入目的・課題から探す
データ・AIについて学ぶ
News
Hakkyについて
ウェビナーコラム
◆トップ【データ基盤】
クラウドDWHを比較
BigQuery Data Transfer Service
概要テーブルクエリコーディングスタイルINFORMATION_SCHEMABI EnginePolicyTag
Cloud ComposerData Catalog
VPC Service Controls
データの保守運用
AI

執筆者:Handbook編集部

BigQueryのポリシータグ設定から適用までをTerraformで実装

はじめに

本記事ではポリシータグの設定からそのポリシータグをBigQueryの対象カラムに反映させるまでTerraformで実装する方法を解説します。 更にその先のユースケースとして、LookerStudioのレポート上ではポリシータグのマスキングルールが適用されている列を閲覧したい場合が考えられまれますので、本記事ではLookerStudio周りの権限設定にも触れていきます。 そもそもポリシータグやマスキングルールとは?と気になる方は以下のの記事を参照してください。

warning
注意

Troccoで定期的に実行されるパイプラインに組み込んでいるテーブルに対してポリシータグを設定する場合、パイプライン実行時にポリシータグが外されてしまう事象を確認しています。(2024年9月時点) これはデータ転送時のWRITE_TRUNCATEモードによる影響が関係していると推測しています。

BigQueryのポリシータグの作成から対象カラムへの適用までをTerraformで実装するコード

以下、Terraformコードの全体です。

variable "project_id" {
  description = "The Google Cloud project ID"
  type        = string
  default     = "example.project"
}

# Google Cloud プロバイダーの設定
provider "google" {
  project = var.project_id
  region  = "asia-northeast1"
}

# Looker Studio 用のサービスアカウントを作成
resource "google_service_account" "looker_viewer_service_account" {
  account_id   = "looker-studio-viewer"
  display_name = "Looker Studio Viewer Service Account"
}

# サービスアカウントにBigQueryデータ閲覧者のロールを付与
resource "google_project_iam_member" "add_bigquery_data_viewer_role_to_service_account" {
  project = var.project_id
  role    = "roles/bigquery.dataViewer" # サービスアカウントがBigQueryデータを閲覧できるロールを付与します。
  member  = "serviceAccount:${google_service_account.looker_viewer_service_account.email}"
}

# サービスアカウントにBigQueryジョブ実行のロールを付与
resource "google_project_iam_member" "add_bigquery_job_user_role_to_service_account" {
  project = var.project_id
  role    = "roles/bigquery.jobUser" # サービスアカウントがBigQueryジョブ実行できるロールを付与します。
  member  = "serviceAccount:${google_service_account.looker_viewer_service_account.email}"
}


# サービスエージェントにアクセストークン作成者のロールを付与
resource "google_project_iam_member" "add_service_token_creator_role_to_service_agent" {
  project = var.project_id
  role    = "roles/iam.serviceAccountTokenCreator" # サービスエージェントがアクセストークンを作成する権限を付与します。
  member  = "serviceAccount:service-org-XXXXXXXXXXXX@gcp-sa-datastudio.iam.gserviceaccount.com"
}

# Googleグループにサービスアカウントユーザーのロールを付与
resource "google_service_account_iam_binding" "group_binding" {
  service_account_id = google_service_account.looker_viewer_service_account.id

  role = "roles/iam.serviceAccountUser"

  members = [
    "group:admin@sample.co.jp"
  ]
}

# Personal テーブル用のポリシータグの分類を作成
resource "google_data_catalog_taxonomy" "personal_taxonomy" {
  project                = var.project
  region                 = "asia-northeast1"
  display_name           = "Personal Table Masking Policy"
  description            = "Taxonomy for masking policies related to personal data"
  activated_policy_types = ["FINE_GRAINED_ACCESS_CONTROL"]
}

# Personal ポリシータグ: Name を作成
resource "google_data_catalog_policy_tag" "name" {
  taxonomy     = google_data_catalog_taxonomy.personal_taxonomy.id
  display_name = "Name"
  description  = "Policy tag for masking data related to  name"
}


# Personal ポリシータグ:Corpを作成
resource "google_data_catalog_policy_tag" "corpname" {
  taxonomy     = google_data_catalog_taxonomy.personal_taxonomy.id
  display_name = "CorpName"
  description  = "Policy tag for masking data related to CorpName"
}


# Name ポリシータグのIAMメンバーを設定
resource "google_data_catalog_policy_tag_iam_binding" "name_tag_viewer" {
  policy_tag = google_data_catalog_policy_tag.name.id
  role       = "roles/datacatalog.categoryFineGrainedReader"
  members = [
    "group:admin@sample.co.jp",
  ]
}

# CorpName ポリシータグのIAMメンバーを設定
resource "google_data_catalog_policy_tag_iam_binding" "corpname_tag_viewer" {
  policy_tag = google_data_catalog_policy_tag.corpname.id
  role       = "roles/datacatalog.categoryFineGrainedReader"
  members = [
    "group:admin@sample.co.jp",
  ]
}

# personal ポリシータグ:  Name にデータマスキングポリシーを設定
resource "google_bigquery_datapolicy_data_policy" "masking_name_policy" {
  project          = var.project
  location         = "asia-northeast1"
  data_policy_id   = "masking_name_policy"
  policy_tag       = google_data_catalog_policy_tag.name.id
  data_policy_type = "DATA_MASKING_POLICY"
  data_masking_policy {
    predefined_expression = "ALWAYS_NULL"
  }
}

# personal ポリシータグ:  Corp Name にデータマスキングポリシーを設定
resource "google_bigquery_datapolicy_data_policy" "masking_corpname_policy" {
  project          = var.project
  location         = "asia-northeast1"
  data_policy_id   = "masking_corpname_policy"
  policy_tag       = google_data_catalog_policy_tag.corpname.id
  data_policy_type = "DATA_MASKING_POLICY"
  data_masking_policy {
    predefined_expression = "ALWAYS_NULL"
  }
}


#  Name MaskingデータポリシーのIAMバインディング
resource "google_bigquery_datapolicy_data_policy_iam_binding" "name_masked_reader" {
  # データポリシーが適用されるプロジェクトID
  project        = var.project_id
  location       = "us"
  data_policy_id = google_bigquery_datapolicy_data_policy.masking_name_policy.data_policy_id
  role           = "roles/bigquerydatapolicy.maskedReader"
  members = [
    "group:viewer@sample.co.jp"
  ]
}


#  CorpName MaskingデータポリシーのIAMバインディング
resource "google_bigquery_datapolicy_data_policy_iam_binding" "corpname_masked_reader" {
  project        = var.project_id
  location       = "us"
  data_policy_id = google_bigquery_datapolicy_data_policy.masking_corpname_policy.data_policy_id
  role           = "roles/bigquerydatapolicy.maskedReader"
  members = [
    "group:viewer@sample.co.jp"
  ]
}

# BigQueryテーブルリソース
resource "google_bigquery_table" "identity" {
  dataset_id = "customer"
  table_id   = "identity"
  project    = var.project_id

  schema = jsonencode(
    [
      {
        "mode" : "NULLABLE",
        "name" : "name",
        "type" : "STRING",
        "policyTags" : {
          "names" : [
            "${google_data_catalog_policy_tag.name.id}"
          ]
        }
      },
      {
        "mode" : "NULLABLE",
        "name" : "corpName",
        "type" : "STRING",
        "policyTags" : {
          "names" : [
            "${google_data_catalog_policy_tag.corpname.id}"
          ]
        }
      }
    ]
  )

}

以下より、上記Terraformコードを部分的に分けて解説していきます。

変数定義

variable "project_id" {
  description = "The Google Cloud project ID"
  type        = string
  default     = "example.project"
}

project_id変数が定義されています。Google CloudのプロジェクトIDを指定するための変数で、デフォルト値はexample.projectに設定されています。

Google Cloud プロバイダー設定

provider "google" {
  project = var.project_id
  region  = "asia-northeast1"
}

Google Cloudのプロバイダーを設定しています。var.project_id変数でプロジェクトIDが指定され、リージョンはasia-northeast1に設定されています。

Looker Studio用サービスアカウント作成

resource "google_service_account" "looker_viewer_service_account" {
  account_id   = "looker-studio-viewer"
  display_name = "Looker Studio Viewer Service Account"
}

Looker Studioビューアー用のサービスアカウントを作成しています。account_iddisplay_nameを設定し、BigQueryデータの閲覧やジョブ実行に使用されます。

IAMロールの割り当て: BigQueryデータ閲覧者

resource "google_project_iam_member" "add_bigquery_data_viewer_role_to_service_account" {
  project = var.project_id
  role    = "roles/bigquery.dataViewer"
  member  = "serviceAccount:${google_service_account.looker_viewer_service_account.email}"
}

サービスアカウントにroles/bigquery.dataViewerのロールを付与し、BigQueryデータの閲覧権限を与えています。

IAMロールの割り当て: BigQueryジョブユーザー

resource "google_project_iam_member" "add_bigquery_job_user_role_to_service_account" {
  project = var.project_id
  role    = "roles/bigquery.jobUser"
  member  = "serviceAccount:${google_service_account.looker_viewer_service_account.email}"

}

サービスアカウントにBigQueryジョブを実行できるroles/bigquery.jobUserのロールを付与しています。

IAMロールの割り当て: アクセストークン作成者

resource "google_project_iam_member" "add_service_token_creator_role_to_service_agent" {
  project = var.project_id
  role    = "roles/iam.serviceAccountTokenCreator"
  member  = "serviceAccount:service-org-XXXXXXXXXXXX@gcp-sa-datastudio.iam.gserviceaccount.com"
}

特定のサービスエージェントにアクセストークン作成権限を与えるロールroles/iam.serviceAccountTokenCreatorを付与しています。

Googleグループにサービスアカウントユーザーロールの付与

resource "google_service_account_iam_binding" "group_binding" {
  service_account_id = google_service_account.looker_viewer_service_account.id
  role               = "roles/iam.serviceAccountUser"
  members            = [
    "group:admin@sample.co.jp"
  ]
}

Looker Studioのサービスアカウントに対してGoogleグループadmin@sample.co.jproles/iam.serviceAccountUserのロールを持つようにバインディングしています。 このロールは、そのグループのメンバーがサービスアカウントを使用して操作を行うことを許可します。

ポリシータグの作成: Personalデータ

resource "google_data_catalog_taxonomy" "personal_taxonomy" {
  project                = var.project
  region                 = "asia-northeast1"
  display_name           = "Personal Table Masking Policy"
  description            = "Taxonomy for masking policies related to personal data"
  activated_policy_types = ["FINE_GRAINED_ACCESS_CONTROL"]
}

personalデータのマスキングポリシーを適用するためのポリシータグ分類を作成しています。リージョンはasia-northeast1に設定されています。

ポリシータグの作成: NameとCorpName

resource "google_data_catalog_policy_tag" "name" {
  taxonomy     = google_data_catalog_taxonomy.personal_taxonomy.id
  display_name = "Name"
  description  = "Policy tag for masking data related to name"
}

resource "google_data_catalog_policy_tag" "corpname" {
  taxonomy     = google_data_catalog_taxonomy.personal_taxonomy.id
  display_name = "CorpName"
  description  = "Policy tag for masking data related to CorpName"
}

personalデータのNameとCorpNameに関連するデータをマスキングするためのポリシータグを作成しています。

IAMロールの割り当て: ポリシータグでマスキングされているカラムを閲覧させるグループを設定

resource "google_data_catalog_policy_tag_iam_binding" "name_tag_viewer" {
  policy_tag = google_data_catalog_policy_tag.name.id
  role       = "roles/datacatalog.categoryFineGrainedReader"
  members    = [
    "group:admin@sample.co.jp"
  ]
}

NameポリシータグのIAMメンバーにデータ閲覧権限を与えています。同様にCorpNameにも同じ設定がされています。 roles/datacatalog.categoryFineGrainedReaderロールを持つユーザーやグループはマスキングされいているデータを閲覧することができます。

IAMロールの割り当て: ポリシータグでマスキングされているカラムを閲覧させないグループを設定

resource "google_bigquery_datapolicy_data_policy_iam_binding" "name_masked_reader" {
  project        = var.project_id
  location       = "us"
  data_policy_id = google_bigquery_datapolicy_data_policy.masking_name_policy.data_policy_id
  role           = "roles/bigquerydatapolicy.maskedReader"
  members        = [
    "group:viewer@sample.co.jp"
  ]
}

Nameポリシータグに対して、データマスキングを適用するためのIAMバインディングを設定しています。同様にCorpNameにも同じ設定がされています。 roles/bigquerydatapolicy.maskedReaderロールを持つユーザーやグループはマスキングルールが適用されているカラムは閲覧できません。

データマスキングポリシーの作成

resource "google_bigquery_datapolicy_data_policy" "masking_name_policy" {
  project          = var.project
  location         = "asia-northeast1"
  data_policy_id   = "masking_name_policy"
  policy_tag       = google_data_catalog_policy_tag.name.id
  data_policy_type = "DATA_MASKING_POLICY"
  data_masking_policy {
    predefined_expression = "ALWAYS_NULL"
  }
}

personalデータのNameとCorpNameに対するマスキングルールを設定しています。マスキングルールとしては「常にNULL」を返す設定です。

BigQueryテーブルリソース

# BigQueryテーブルリソース
resource "google_bigquery_table" "identity" {
  dataset_id = "customer"
  table_id   = "identity"
  project    = "${var.project_id}"

 schema = jsonencode(
    [
      {
        "mode": "NULLABLE",
        "name": "name",
        "type": "STRING",
        "policyTags": {
        "names": [
          "${google_data_catalog_policy_tag.name.id}"
        ]
    }
      },
      {
        "mode": "NULLABLE",
        "name": "corpName",
        "type": "STRING",
        "policyTags": {
        "names": [
          "${google_data_catalog_policy_tag.corpname.id}"
        ]
    }
      }
    ]
 )

}

このコードはBigQueryのcustomerデータセットにidentityというテーブルを作成し、データの機密性を確保するために特定のカラムにデータマスキングポリシーを適用しています。 テーブルのスキーマにはnameとcorpNameという2つのカラムがあり、それぞれSTRING型のデータを格納しデータがなくても許容(NULLABLE)される設定です。 さらにこれらのカラムにはデータマスキング用のポリシータグが付与されており、権限のあるユーザーのみが実際のデータにアクセス可能で、それ以外のユーザーにはデータがマスクされて見えないように設定されています。 このようにして、BigQuery内でのデータセキュリティを強化しています。

まとめ

この記事はBigQueryのポリシータグの作成から対象カラムへの適用までをTerraformで実装するコードについて解説しました。 Terraformでインフラ構成を管理することは大規模なチームになるほどその恩恵を享受することができます。 今後ビジネスのスケールなどでチームが拡大する可能性がある場合は早めにインフラをTerraformで管理することをお勧めします。

参考

info
備考

Hakky では社内のデータ活用やサービスとしてデータ提供を行うためのソリューションを展開しております。

「社内のデータを一元管理し、よりデータドリブンな組織を構築したい」など具体的な相談はもちろんのこと、「どんなことをお願いできるのか知りたい」や「こんなことをやりたい」など、ご検討段階でも構いませんので、ぜひお気軽にフォームよりお問い合わせくださいませ。

Hakkyへのお問い合わせ
2025年07月06日に最終更新
読み込み中...