こんにちは。2024年4月に新卒で入社したバックエンドエンジニアの筒井(@tsuttsun_wind)です。
今回は、BigQuery Data Transfers(以下Data Transfers)をエンジニア全員が実行できるようにした背景や設定方法について紹介します。
背景
PR TIMESでは、Contents Delivery Network(CDN)にFastlyを採用しており、FastlyのアクセスログをAmazon S3に保存しています。

保存されたログは24時間に1回の間隔でS3からBigQueryに転送が行われますが、障害など問題が発生した場合には最新のアクセスログが必要になります。

そのため、アクセスログが素早く取得可能な仕組みが要求されます。
素早く取得可能な仕組みを導入するための手法
この仕組みを導入するために、以下の3つを候補として挙げました。
- S3などの外部データからData Transfersを利用したimport
- Google Cloud Storage(GCS)を利用したimport
- Streaming Insertを利用したimport
外部データからData Transfersを利用したimportのメリット/デメリット
- メリット
- 外部のデータベースやストレージからデータを定期的にimportが可能
- importしたデータを利用して分析が容易に行える
- デメリット
- 最新のログを取得するためには手動で転送を実行する必要がある
- BigQuery Adminまたはオーナーのロールが必要
- 最新のログを取得するためには手動で転送を実行する必要がある
GCSを利用したimportのメリット/デメリット
- メリット
- Data Transfersの自動転送を15分ごとに行うことが可能
- デメリット
- ストレージを2つ持つため、それぞれでストレージ料金が掛かる
- S3に保存されているログは他の用途で利用しているため、削除が困難
Streaming Insertを利用したimport
- メリット
- 数秒程度でデータをリアルタイムで挿入可能
- JSON形式で格納されているデータのStreaming Insertをサポート
- デメリット
- アクセスログの欠損が発生するケースがあり、問題発生時にログが欠損しているという事態が発生しかねない
- Insertを行う度に料金が発生し、コストが200MBごとに0.012ドル掛かる
これらの候補の中で短期的に実現可能な手法は、コスト面やログ保守性を考慮してS3からBigQueryに手動でimportを行う方法を採用しました。これを行うためには、BigQuery Adminロールの付与を行う必要があります。
しかし、これには問題点があります。
BigQuery Adminロールを付与する問題点
BigQuery Adminロールは、BigQueryの全操作権限を持つロールであり、プロジェクト内のデータ操作 (作成、編集、削除) や、他ユーザーが実行中のジョブがキャンセル出来てしまいます。

このような強力な権限を全員に付与することは行いたくないため、以下の対策を取ることにしました。
- カスタムロールを作成し、手動転送を可能にする権限を付与
- カスタムロールを任意のユーザに割り当てることにより、付与されている権限のみ実行可能
- デフォルトで用意されているロールと組み合わせて利用可能
現在、最新のログが必要になるケースは障害時のみであるため、今回はData Transfersを実行可能にするカスタムロールを作成し、エンジニア全員に権限の付与を行いました。
権限付与を行う
今回、Data Transfersの権限を付与するにあたって、Terraformを採用しました。
Terraformは、インフラのプロビジョニング及び管理をコード化し、環境設定を一貫して再現可能にするため、様々なクラウドサービスに対して簡潔かつ効率にリソース管理が行えます。
今回は以下の流れで権限の付与を行いました。
権限付与の流れ
1. 対象プロジェクトとリージョンの設定
Google Cloudをプロバイダとして指定し、プロジェクト名とリージョンを指定します。
provider "google" {
project = "big-query"
region = "asia-northeast1"
}2. プロジェクト詳細を取得
プロバイダであらかじめ指定したプロジェクトの詳細データを取得します。
data "google_project" "current" {} 3.カスタムロールの作成
BigQueryのProjectに対して、Data Transferの権限を付与するカスタムロールを作成します。
今回は以下の権限を付与しました。
- bigquery.transfers.update
- この権限は、Data Transferを手動実行するために必要です。他には、転送元データソースやスケジュール、転送先のBigQueryデータ設定を変更するために使用されます。
- bigquery.transfers.get
- この権限は、転送状態の確認、例えば正常に転送が行われているか確認するために必要です。他には、転送設定の構成やスケジュール確認のために使用されます。
resource "google_project_iam_custom_role" "big_query_transfers" {
project = data.google_project.current.project_id
role_id = "bigQueryEngineer"
title = "BigQuery Engineer"
description = "エンジニアがBigQueryのTransfersを実行するためのロール"
permissions = ["bigquery.transfers.update", "bigquery.transfers.get"]
}4. 作成したカスタムロールの付与
作成したカスタムロールを指定し、対象メンバーをエンジニアグループに指定します。
- memberには個人ユーザに加え、グループも指定可能です。
resource "google_project_iam_member" "transfers_role_apply" {
project = data.google_project.current.project_id
role = google_project_iam_custom_role.big_query_transfers.id
member = "<group:engineer@example.com>"
} 以上の流れを行うことにより、対象メンバーに権限の付与が行われます。

権限付与で詰まったところ
社内ではTerraformの変更を行うGitHub Actionsが整備されており、Pull Request(PR)の作成時に変更差分を出力するterraform plan が実行されます。
変更差分は、PRがmainブランチにMergeされた後にterraform apply が実行され、Google Cloudの指定したプロジェクトに対して適用が行われます。
今回追加した権限付与の設定を適用するためにPRをMergeしたところ、Identity and Access Management(IAM)の操作権限がGitHub Actionsにないため、適用作業が以下のエラーで落ちてしまいました。
│ Error: Error creating the custom project role projects/big-query/roles/bigQueryEngineer:
│ googleapi: Error 403: You don't have permission to create a role in projects/big-query., forbidden
│
│ with google_project_iam_custom_role.big_query_transfers,
│ on grant_role.tf line 1, in resource "google_project_iam_custom_role" "big_query_transfers":
│ 1: resource "google_project_iam_custom_role" "big_query_transfers" {
Error: Process completed with exit code 1.GitHub ActionsにIAM管理権限を付与する
GitHub ActionsでIAMロールの操作を行えるようにするため、IAM管理用のresourcemanager.projectIamAdminロールを、GitHub Actionsを管理するサービスアカウントに対して付与を行います。
こちらは以下の流れでGitHub Actionsを管理しているtfファイルに記載を行いました。
1. ロールを追加
GitHub Actionsにresourcemanager.projectIamAdminロールを追加します。
- このロールは、IAMポリシーとプロジェクトの管理権限を持っており、プロジェクト内リソースのアクセス権限の取得及び設定、プロジェクトのメタデータの取得及び更新が可能です。
locals {
roles = [
"roles/editor",
"roles/resourcemanager.projectIamAdmin",
]
}2. 対象プロジェクトとリージョンの設定
Google Cloudをプロバイダとして指定し、プロジェクト名とリージョンを指定します。
provider "google" {
project = "big-query"
region = "asia-northeast1"
} 3. プロジェクト詳細を取得
プロバイダで指定したプロジェクトの詳細データを取得します。
data "google_project" "current" {}4. サービスアカウントの指定
GitHub ActionsのアカウントIDを指定します。
resource "google_service_account" "github_actions" {
account_id = "github-actions"
}5. ロール付与を行う
BigQueryのプロジェクトに存在するGitHub Actionsを管理しているサービスアカウントに対し、1.で指定したロールの付与を行います。
- 今回は
roles/editorとresourcemanager.projectIamAdminロールの付与が行われます。
resource "google_project_iam_member" "github_actions" {
for_each = toset(local.roles)
project = data.google_project.current.project_id
member = "serviceAccount:${google_service_account.github_actions.email}"
role = each.value
}この変更により、google_project_iam_custom_role や google_project_iam_member を Terraform に記述することで、ロールの作成、付与、削除を GitHub Actions を通じて適用できるようになります。
他のロール付与方法について
google_project_iam_member は、すでに存在するロールを付与しようとした場合は無視されるため、影響範囲を抑えることが可能です。
ここでは詳しく解説しませんが、他のロール付与方法にgoogle_project_iam_binding とgoogle_project_iam_policy があります。
この2つは、他のユーザやプロジェクト全体に大きな影響を与えるため、使用する場合は慎重に設定を行う必要があります。
実行可能にして変化したこと
Data Transfersの手動実行を可能にした結果、問題発生時にData Transfersの手動実行依頼をエンジニア全員に対してSlackで呼び掛けることが可能になりました。
これにより、実行結果の共有や原因究明が早くなり、障害対応が以前と比べてスムーズになりました。

おわりに
今回、BigQuery Data Transfersをエンジニア全員に対して実行可能にした話について紹介しました。
実装前はTerraformとGoogle Cloudに触れる機会があまり無く、権限付与というプロジェクトに影響を与えかねない実装を行うことに心配がありました。
ですが、Terraformの書き方、ロール作成や付与方法が学びになり、今後もTerraformを活用していきたいという気持ちになりました。
この記事が、Google Cloudにおけるロール作成や付与をTerraformで実現したいという方々に参考になれば幸いです。

