created: 2022-09-15T07:07:39.718Z

[GCP] CloudLogging のフィルタで CloudFunction をキックする PubSub を terraform で定義する

たとえば「BigQuery でどんなクエリが発行されているかを Slack に通知したいな」という要件があった場合。

こんなログフィルタでそんなイベントを知ることができるので、このフィルタにマッチしたログが出たときに CloudFunction とかを動かせるようにする。

resource.type="bigquery_resource"
protoPayload.methodName="jobservice.jobcompleted"

実装

こんな tf ファイルの定義で CloudFunction 以外のリソースは生成できる。意外と少ない。

  • google_logging_project_sink
    • ログを検索するクエリを管理するリソース
  • google_pubsub_topic
    • sink に入った(検索に引っかかった)ログの情報をイベントとして処理をキックするリソース
    • 具体的には CloudRun や CloudFunction の処理をキックする
resource "google_logging_project_sink" "bigquery-jobcompleted" {
  destination            = "pubsub.googleapis.com/projects/${var.GCP_PROJECT_ID}/topics/bigquery-jobcompleted"
  name                   = "bigquery-jobcompleted"
  filter                 = <<-FILTER
  resource.type="bigquery_resource"
  protoPayload.methodName="jobservice.jobcompleted"
  FILTER
}

resource "google_pubsub_topic" "bigquery_jobcompleted" {
  name    = "bigquery-jobcompleted"
}

# unique_writer_identity=true で払い出される SA に pubsub を publish する権限を付与
resource "google_project_iam_member" "bigquery_jobcompleted_pubsub_writer" {
  member  = google_logging_project_sink.bigquery_jobcompleted.writer_identity
  role    = "roles/pubsub.publisher"
}

unique_writer_identity?

専用のサービスアカウントを作るかどうか。複数プロジェクトへ publish するシンクを作りたい場合は true にする必要がある。

ちなみにコンソールからポチポチ作業するとこれは true でつくったような状態になるようだ。

(Optional) Whether or not to create a unique identity associated with this sink. If false (the default), then the writer_identity used is serviceAccount:cloud-logs@system.gserviceaccount.com. If true, then a unique service account is created and used for this sink. If you wish to publish logs across projects or utilize bigquery_options, you must set unique_writer_identity to true.

サービスアカウントへのロール付与

unique_writer_identity = true でリソースを生成すると自動的にサービスアカウントが払い出される。このサービスアカウントは GCP のコンソールに表示されないが、これに pubsub を publish できるロールが付与されていないと権限がないということで期待通り動作しない。

確認

# sinksの情報からServiceアカウントのIDを取得
$ gcloud logging sinks describe bigquery-jobcompleted | grep serviceAccount
writerIdentity: serviceAccount:p123456@gcp-sa-logging.iam.gserviceaccount.com
$ export SERVICE_ACCOUNT="p123456@gcp-sa-logging.iam.gserviceaccount.com"
$ gcloud projects get-iam-policy \
    $GCP_PROJECT_ID \
    --flatten="bindings[].members" \
    --format="table(bindings.role)" \
    --filter="bindings.members:$SERVICE_ACCOUNT"
ROLE
roles/pubsub.publisher

terraform import

もしコンソールの検索画面から作った場合は terraform import で tfstate に取り込むことになる。

$ terraform import google_logging_project_sink.bigquery_jobcompleted projects/$GCP_PROJECT_ID/sinks/bigquery-jobcompleted
$ terraform import google_pubsub_topic.bigquery_jobcompleted bigquery-jobcompleted

参考