コンテンツにスキップ

【HCP Terraform】: Google Cloud の Dynamic Provider Credentials でつまづきそうなポイント

Dynamic Provider Credentials は、HCP Terraform のワークスペースに対して、必要なタイミングで動的に認証情報を提供する機能です。この機能を利用することで、認証情報を直接 HCP Terraform に保存する必要がなくなり、セキュリティが向上します。

公式ドキュメントや個人のブログ記事でも情報が提供されていますが、Google Cloud の Dynamic Provider Credentials を設定する際にドキュメントに記載されていないポイントでつまづくことがあります。この記事では、Google Cloud の Dynamic Provider Credentials を設定する際に注意すべきポイントを解説します。

Google Cloud の Dynamic Provider Credentials 設定例と注意点

以下は、Google Cloud の Dynamic Provider Credentials を設定するための Terraform コード例です。

locals {
  project = "my-project-id" # GCPプロジェクトIDを指定"
  service_account_roles = [
    "roles/storage.admin",                   # リソース管理のための権限付与
    "roles/resourcemanager.projectIamAdmin", # workload identity user role binding needs this permission
    "roles/iam.serviceAccountTokenCreator",  # to allow impersonation of the service account
  ]
}

# workload identity pool for HCP Terraform
resource "google_iam_workload_identity_pool" "hcp_terraform" {
  workload_identity_pool_id = "hcp-terraform-pool"
  display_name              = "HCP Terraform Pool"
  description               = "Used to authenticate to Google Cloud"
}

# workload identity pool provider for HCP Terraform
resource "google_iam_workload_identity_pool_provider" "hcp_terraform" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.hcp_terraform.workload_identity_pool_id
  workload_identity_pool_provider_id = "hcp-terraform-provider"
  display_name                       = "HCP Terraform Provider"
  description                        = "Used to authenticate to Google Cloud"
  attribute_condition                = "assertion.sub.startsWith(\"organization:my-org:project:my-project:workspace:my-workspace\")"
  attribute_mapping = {
    "google.subject"                        = "assertion.sub",
    "attribute.aud"                         = "assertion.aud",
    "attribute.terraform_run_phase"         = "assertion.terraform_run_phase",
    "attribute.terraform_project_id"        = "assertion.terraform_project_id",
    "attribute.terraform_project_name"      = "assertion.terraform_project_name",
    "attribute.terraform_workspace_id"      = "assertion.terraform_workspace_id",
    "attribute.terraform_workspace_name"    = "assertion.terraform_workspace_name",
    "attribute.terraform_organization_id"   = "assertion.terraform_organization_id",
    "attribute.terraform_organization_name" = "assertion.terraform_organization_name",
    "attribute.terraform_run_id"            = "assertion.terraform_run_id",
    "attribute.terraform_full_workspace"    = "assertion.terraform_full_workspace",
  }
  oidc {
    issuer_uri = "https://app.terraform.io"
  }
}

# service account that HCP Terraform will impersonate
resource "google_service_account" "hcp_terraform" {
  account_id   = "hcp-terraform"
  display_name = "Service Account for HCP Terraform"
}

# IAM verifies the HCP Terraform Workspace ID before authorizing access to impersonate the service account
resource "google_service_account_iam_member" "workload_identity_user" {
  service_account_id = google_service_account.hcp_terraform.name
  role               = "roles/iam.workloadIdentityUser"
  member             = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.hcp_terraform.name}/*"
}

# grant service account permissions to the roles defined in local.service_account_roles
resource "google_project_iam_member" "hcp_terraform_roles" {
  for_each = toset(local.service_account_roles)
  member   = "serviceAccount:${google_service_account.hcp_terraform.email}"
  role     = each.value
  project  = local.project
}

上記のコードは、Google Cloud の Dynamic Provider Credentials を設定するための基本的な例です。 リソースを作成するには Google Cloud で api を有効化する必要があります。適切な api を有効化しないと、以下のようなエラーが発生します。

│ Error: Error when reading or editing Folder Not Found : XXXXXXXXXXXX: Get "https://cloudresourcemanager.googleapis.com/v3/folders/XXXXXXXXXXXX?alt=json&prettyPrint=false": impersonate: status code 403: {
│   "error": {
│     "code": 403,
│     "message": "Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).",
│     "status": "PERMISSION_DENIED",
│     "details": [
│       {
│         "@type": "type.googleapis.com/google.rpc.ErrorInfo",
│         "reason": "IAM_PERMISSION_DENIED",
│         "domain": "iam.googleapis.com",
│         "metadata": {
│           "permission": "iam.serviceAccounts.getAccessToken"
│         }
│       }
│     ]
│   }
│ }

上記のエラーを回避するために、以下のコマンドで必要な API を有効化してください。コマンド実行以外にも、Google Cloud コンソールや Terraform から有効化することもできます。

1
2
3
4
5
gcloud services enable iam.googleapis.com \
    cloudresourcemanager.googleapis.com \
    sts.googleapis.com \
    iamcredentials.googleapis.com \
    --project=${PROJECT_ID}

これ以外につまづきやすいポイントとして、Terraform Workspace の環境変数の設定があります。設定する変数の一つにTFC_GCP_WORKLOAD_PROVIDER_NAMEがありますが、projects/プロジェクトNumber/locations/global/workloadIdentityPools/プールID/providers/プロバイダーIDの形式で指定する必要があります。 Google Cloud コンソール上で provider の値をコピーするとフォーマットが異なるため、注意が必要です。

参考