GCSの複数バケットを対象としたイベントをトリガーするcloud functionsをterraformで作る
Cloud FunctinsにはGCS(Google Cloud Storage)の各種イベントを受け取って起動する機能があります。
特にオブジェクトのファイナライズをトリガーとしたFunctionsなんかは、GCSを使ったパイプラインを構築する上ではよく使います。
従来のGCSイベントでは単一バケットのイベントしか受けとれない
GCSのイベントを利用したFunctionsはとても便利ですが、基本的にFunctionsとバケットが一対一で結びつくような形になるため、複数のバケットを対象にすることができませんでした。
GCSのイベント駆動ではなくHTTPリクエスト起動のFunctionsを作れば可能ではありますが・・・
Cloud Audit Logのエントリ駆動のFunctionsを使う
従来のGCSイベントはPub/Subを介してFunctionsを起動していましたが、Cloud Audit LogのエントリをトリガーとするFunctionsを作成することで、複数のGCSイベントをトリガーにすることができます。
Cloud Audit Logは文字通りGCPの監査ログの仕組みですね。
GCSのAudit Logを有効にする
GCSのAudit Logはデフォだと無効になってるので有効化しないと使えません。ダッシュボードからだとAudit Logのページから編集できます。
Terraformだと以下のように書けば反映されます。
resource "google_project_iam_audit_config" "this" {
project = var.project_id
service = "storage.googleapis.com"
audit_log_config {
log_type = "DATA_WRITE"
}
}
今回はデータ書き込みだけ有効にしてます。
必要な権限を持ったService Accountを作成
こんな感じので必要な権限を持ったService Accountを作成します。
resource "google_service_account" "this" {
account_id = var.name
display_name = var.name
}
resource "google_project_iam_member" "this" {
for_each = toset([
"roles/pubsub.publisher",
"roles/eventarc.eventReceiver",
"roles/run.invoker",
])
project = var.project_id
role = each.value
member = "serviceAccount:${google_service_account.this.email}"
}
Audit Logのエントリ通知はEventarc経由となるため、eventarc.eventReceiver
が必要です。また、これから作成するCloud Functions(第二世代)は内部的にはCloudRunなので、run.invoker
も必要になります。pubsub.publisher
が必要だったかどうはイマイチ覚えてないので念のため書いてますが、もしかしたら必要ないかもです。
Cloud Functions(第二世代)を作成
Audit Logをトリガーとするには第二世代のCloud Functionを使う必要があります。ソースコードを配置するGCSバケットは既に作成している前提で進めます。
一応source artifactの部分も載せます。
data "archive_file" "this" {
type = "zip"
source_dir = var.source_dir # ソースコードのディレクトリ
output_path = "${var.source_dir}.zip"
}
resource "google_storage_bucket_object" "this" {
name = "functions/${var.name}/${data.archive_file.this.output_md5}.zip"
bucket = var.source_bucket_name # ソースをアップするバケット名
source = data.archive_file.this.output_path
}
上記のsourceを使ったFunctionsを作成します。
resource "google_cloudfunctions2_function" "this" {
name = var.name
location = var.region
build_config {
runtime = "ランタイムを入れる"
entry_point = "エントリポイント"
source {
storage_source {
bucket = var.source_bucket_name # ソースをアップするバケット名
object = google_storage_bucket_object.this.name
}
}
}
service_config {
ingress_settings = "ALLOW_INTERNAL_ONLY"
all_traffic_on_latest_revision = true
service_account_email = google_service_account.this.email
}
event_trigger {
trigger_region = var.region
event_type = "google.cloud.audit.log.v1.written"
retry_policy = "RETRY_POLICY_RETRY"
service_account_email = google_service_account.this.email
event_filters {
attribute = "serviceName"
value = "storage.googleapis.com"
}
event_filters {
attribute = "methodName"
value = "storage.objects.create"
}
event_filters {
attribute = "resourceName"
value = var.resource_path_pattern
operator = "/projects/_/buckets/hogehoge-*/objects/**"
}
}
}
重要なのはevent_trigger
の部分ですね。event_type
で、先ほど有効化したAudit LogのGCSイベントログを指定しています。
ちなみにgoogle.cloud.audit.log.v1.written
には以下のイベントが含まれるっぽいです。
その後、3つのevent_filters
でさらに具体的なトリガー対象を指定しています。
1つ目のevent_filters
はGCSのLogであることを示し、2つ目はstorage.objects.create
イベントであることを示します。そして3つ目のevent_filters
で対象とするバケットをパスパターンで指定しています。上記の例だと「バケット名がhogehoge-
で始まるバケットの全ファイル」が対象になります。パスパターンに関しては以下のドキュメントに詳しく書いてあります。
最後に
使い方に若干クセがありますが、Audit Logを使うことで複数バケットを対象とするFunctionsのトリガーを作成できます。用途次第では有効そうですね。Audit LogをトリガーとしたFunctionsはGCS以外にも応用できそうなので、他にも色々試したみたいです。
Discussion