TerraformのModuleでデータマネジメントしやすくする

背景: Terraformを使いつつ、データマネジメントの観点から統制を取りたい

GCPでデータ基盤を管理する場合、Terraformはよい選択肢の一つです。データセットやそれに関連するIAMの管理、データセット内のビューの定義をIaCとして管理できます。

データマネジメント、特にメタデータ管理の観点でもTerraformは有用です。例えばこういう用途に使えます。

  • descriptionにデータセットの生成元や活用場所を書ける
    • 簡易データリネージ的な使い方
  • データセットをTerraformで管理しているGitHubのURLをdescriptionに書いておくことで、定義を修正したい場合にどこを見ればいいか詳しくない人にもすぐ分かる
  • labelにowner情報を付与することで問い合わせ先が分かるようにできる
  • labelにhas_piiを付与しておくことで、個人情報を含んでいるデータセットか一目で分かるようにできる
  • ビューの場合はschemaにカラムのdescriptionを書くことができる

様々なことに対応でき自由度が高いのは魅力ですが、自由度が高すぎることは問題点でもあります。というのも

  • 人によってdescriptionの書き方がバラバラ
  • 必須の項目なので入力しておいて欲しいが、人によって情報を入れてくれなかったりする
  • (メタデータは関係ないけど)google_bigquery_datasetaccessはauthorativeでterraform管理外の権限を削除してしまう可能性がある

などの状況が容易に起こってしまうからです。こうした事項を反映前のコードレビューでチマチマと指摘するでもよいですが、疲れますし漏れもでます。管理する人間側のコストを下げつつ、データマネジメントの観点からは統制も取りたいものです。

今回はTerraformのModuleを使うことで、これを実現できる方法を考えてみました。

Terraform Moduleを定義する

例: データセット

最初にBigQueryのデータセットについて見ていきます。やることは単純でgoogle_bigquery_datasetのモジュールをwrapするモジュールを作るだけです。modules/dataset/dataset.tfを以下のように定義します。

# https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_dataset

resource "google_bigquery_dataset" "dataset" {
  project    = var.project_id
  location   = var.location
  dataset_id = var.dataset_id

  description = <<-EOT
    ${var.description}

    このデータセットは ${var.source_code_management_url} で管理されています。
    EOT

  labels = merge(local.default_labels, var.labels)

  lifecycle {
    # accessを使った権限管理はauthorative(terraform管理外で付与された権限も削除し得る)のため、事故に繋がりやすい
    # そのため、データセットへの権限付与はbigquery_dataset_accessを通じて行なう
    # ref: https://scrapbox.io/pokutuna/google_bigquery_dataset_%E3%81%AE_access_%E5%B1%9E%E6%80%A7%E3%81%A8_google_bigquery_dataset_access
    # ref: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/bigquery_dataset_access
    ignore_changes = [access]
  }
}

locals {
  default_labels = {
    owner      = "syou6162"
    has_pii    = var.has_pii
    managed_by = "terraform"
  }
}

ラベルはキーを自由に設定できるため、何かしらの形で正規化しておきます(キー名が微妙に違うものがたくさん存在すると統制が取れなくなるため)。modules/dataset/variables.tfの中でvalidationとして表現します。

...

variable "labels" {
  type        = map(string)
  default     = {}
  description = "データセットに付与するラベル"
  # 無闇にラベルが増えていかないようにラベルのキーに制約を付ける。追加したい場合はここを修正する
  validation {
    condition = alltrue(
      [for k, v in var.labels :
        contains(["owner", "has_pii"], k)
    ])
    error_message = "All key of labels must be one of `owner` / `has_pii`."
  }
}

...

データマネジメントの観点から入れておいて欲しい以下の観点を強制することで、統制が取りやすくなります。

  • 管理しているgithubなどのURLの情報
  • データセットのオーナーが分かるようにディフォルトでラベルを差し込んでおく
  • PIIに関する情報をラベルで必ず入れておく

使う側はwrapされたモジュールに情報を入れておくだけで、データマネジメントされやすい型に沿った情報を自動的に埋め込めます。

module "moduled_dataset_yoshida" {
  source     = "modules/dataset"
  project_id = var.project_id
  location   = var.location

  dataset_id  = "syou6162_dataset_module_test"
  description = "これはテスト用のデータセットです"
  has_pii     = false

  source_code_management_url = "https://github.com/syou6162/my_project/blob/master/dataset.tf"
}

できあがりはこちら。データセットの詳細について知りたかったら誰に聞けばいいか分かりますし、定義を修正したかったらどこを見に行けばいいか一目で分かります。PIIの入ったデータセットを棚卸ししたかったらラベルの情報を元にCloud DataCatalogから一括検索をすることもできます。

https://cdn-ak.f.st-hatena.com/images/fotolife/s/syou6162/20210710/20210710170425_original.png

今回はBigQueryのデータセットの例を取り上げましたが、ビューについても同様にすぐできると思います。

まとめ

Terraformを使ってBigQueryのデータセットやビューをモジュールとしてwrapする方法を紹介しました。データマネジメントしやすい形でwrapすることで管理をより効率的に分かりやすい形にどんどんしていきたいですね。