みーのぺーじ

みーが趣味でやっているPCやソフトウェアについて.Python, Javascript, Processing, Unityなど.

tfsec google-iam-no-project-level-service-account-impersonation

Terraform でインフラストラクチャを管理している場合, tfsec を使用することで,セキュリティとして好ましくない設定を簡単に検知できます.

https://aquasecurity.github.io/tfsec/v1.28.1/

tfsec is a static analysis security scanner for your Terraform code.

好ましくない設定のルールが事前定義されており,以下に公開されています.

https://aquasecurity.github.io/tfsec/v1.28.1/checks/

この中に,google-iam-no-project-level-service-account-impersonation というルールが存在します.

Users should not be granted service account access at the project level.
Users with service account access at project level can impersonate any service account. Instead, they should be given access to particular service accounts as required.
プロジェクトレベルでサービスアカウントへのアクセスを許可してはならない.
プロジェクトレベルでサービスアカウントへのアクセスを許可されたユーザーは,任意のサービスアカウントとして操作が可能になります.その代わりに,必要に応じて特定のサービスアカウントへのアクセスを許可するべきです. (拙訳: みー)

例えば,Cloud PubSub を使用して,Cloud Run にリクエストを送信するように Terraform で構成するケースで考えます.リクエストの流れはこのようになります.

PubSub Topic a → PubSub Subscription a → Cloud Run target

以下のような tf ファイルが考えられますが,過剰な権限を付与しています.

resource "google_service_account" "sa" {
  account_id = "cloud-run-invoker"
}
resource "google_project_iam_member" "sa-token" {
  project = var.project
  role    = "roles/iam.serviceAccountTokenCreator"
  member  = "serviceAccount:${google_service_account.sa.email}"
}
resource "google_cloud_run_service" "target" {
  name = "target"
  template {
    spec {
      service_account_name = google_service_account.sa.email
    }
}
resource "google_pubsub_topic" "a" {
  name = "topic-a"
}
resource "google_pubsub_subscription" "a" {
  name                       = "subscription-a"
  topic                      = google_pubsub_topic.a.name
  push_config {
    push_endpoint = "${google_cloud_run_service.target.status[0].url}/endpoint"
    oidc_token {
      audience              = google_cloud_run_service.target.status[0].url
      service_account_email = google_service_account.sa.email
    }
  }
}

google_project_iam_member で権限を付与するとプロジェクトレベルの権限となるため,代わりに google_service_account_iam_member を使用し,権限の範囲を絞ります.この時に,google_service_account_iam_member の元になるサービスアカウントが必要になります.先程はプロジェクトレベルの権限を付与していたため気にしなくてもよかったのですが,PubSub が動作するデフォルトのサービスアカウントを取得する必要があります.これは google_project_service_identity を使用すれば解決できます.

resource "google_project_service_identity" "pubsub" {
  project  = var.project
  provider = google-beta
  service  = "pubsub.googleapis.com"
}
resource "google_service_account_iam_member" "sa-token" {
  service_account_id = google_service_account.sa.name
  role               = "roles/iam.serviceAccountUser"
  member             = "serviceAccount:${google_project_service_identity.pubsub.email}"
}

tfsec を実行して,google-iam-no-project-level-service-account-impersonation を指摘されなくなりましたので,修正完了です.

参考