如何在 terraform 中创建 "impersonation" 模块?

How do I create an "impersonation" module in terraform?

我正在尝试使用以下项目结构编写具有角色分离功能的干净 Terraform 配置:

 terraform-infra-genesis
 ┣ modules
 ┃ ┗ impersonation
 ┃ ┃ ┣ generic_sa_impersonation.tf
 ┃ ┃ ┣ inputs.tf
 ┃ ┃ ┗ test_i1.tfvars
 ┣ org
 ┃ ┣ main.tf
 ┃ ┣ outputs.tf
 ┃ ┣ terraform.tfvars
 ┃ ┗ variables.tf
 ┣ .gitignore
 ┗ README.md

我的目标(目前)是 运行 通过 org 目录定义我的基础设施。

第一步 - 不使用模块:我能够使用 Service account impersonation guide found here 创建上述基础设施。执行 terraform apply 后,我在 GCP 上的基础设施状态已更新。这里没问题。

第二步 - 我创建了我将使用的 modules/impersionation,因为它可能对其他几个实例有用,例如创建 VPC、子网等...这里的目标是该模块将在设定的秒数内生成访问令牌。所以没有输出预期

在我的modules/impersonation中我写了下面的代码:

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "3.85.0"
    }
  }
}

# For a list of all scopes visit : https://developers.google.com/identity/protocols/oauth2/scopes
provider "google" {
  alias  = "service_account_impersonation"
  scopes = var.p_info.scopes
}

data "google_service_account_access_token" "service_account_to_impersonate" {
  provider               = google.service_account_impersonation
  target_service_account = var.sa_to_impersonate_info.email
  scopes                 = var.sa_to_impersonate_info.token_scopes
  lifetime               = var.sa_to_impersonate_info.token_lifetime
}

provider "google" {
  access_token = data.google_service_account_access_token.service_account_to_impersonate.access_token
  region       = var.p_info.region
  zone         = var.p_info.zone
}

# Add users as a token creators and impersonators for this service account
resource "google_service_account_iam_binding" "impersonators" {
  for_each = toset([
    for user in var.user_accs_impersonators_info : "${user.acc_type}:${user.acc_details.email}"
  ])
  service_account_id = "projects/${var.sa_to_impersonate_info.belonging_project_id}/serviceAccounts/${var.sa_to_impersonate_info.email}"
  role               = "roles/iam.serviceAccountTokenCreator"
  members            = [each.key]
}

我 test/debug 通过创建 test_i1.tfvars 这个模块将包含以下(已编辑)值:

p_info = {
  scopes = [
    "https://www.googleapis.com/auth/cloud-platform",
    "https://www.googleapis.com/auth/userinfo.email",
  ]
  region = <redacted>
  zone   = <redacted>
}

sa_to_impersonate_info = {
  email                = <redacted>
  belonging_org_id     = <redacted>
  belonging_project_id = <redacted>
  token_lifetime       = "1200s"
  token_scopes         = ["cloud-platform", "userinfo-email"]
}


user_accs_impersonators_info = [{
  acc_type = "user",
  acc_details = {
    email = <redacted>
  },
}]

当我执行 terraform plan 时有效,显示以下输出:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

    Terraform will perform the following actions:
    ... <redacted> ...
    Plan: 1 to add, 0 to change, 0 to destroy.

第三步——我在org/main.tf:

中使用了之前写好的模块
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "3.85.0"
    }
  }
}

module "terraform_super_admin_service_account_impersonation" {
  source = "../modules/impersonation"
  p_info = {
    region = <redacted>
    zone   = <redacted>
    scopes = [
      "https://www.googleapis.com/auth/cloud-platform",
      "https://www.googleapis.com/auth/userinfo.email",
    ]
  }
  sa_to_impersonate_info = {
    email                = <redacted>
    belonging_org_id     = <redacted>
    belonging_project_id = <redacted>
    token_lifetime       = "1200s"
    token_scopes = [
      "cloud-platform", "userinfo-email"
    ]
  }

  user_accs_impersonators_info = [{
    acc_type = "user"
    acc_details = {
      email = <redacted>
    }
  }]
}

这里我得到错误:

Error: Error when reading or editing Resource "service account '<redacted>'" with IAM Binding (Role "roles/iam.serviceAccountTokenCreator"): Error retrieving IAM policy for service account '<redacted>': googleapi: Error 403: Permission iam.serviceAccounts.getIamPolicy is required to perform this operation on service account '<redacted>'., forbidden

但这没有意义,因为我只是在第 1 步和第 2 步中使用了这些相同的凭据...我在想,也许我使用的 provider 块错误模块,但我看不出我有其他选择来进行模拟。

这是怎么回事?

当您从 top-level Terraform 代码中使用该模块时,您的“模拟”模块中的提供程序块将被忽略。根据 the documentation:

Provider configurations, unlike most other concepts in Terraform, are global to an entire Terraform configuration and can be shared across module boundaries. Provider configurations can be defined only in a root Terraform module.

和:

A module intended to be called by one or more other modules must not contain any provider blocks.

因此,您模块中的 provider 配置仅在您从同一文件夹中执行 运行 terraform 命令时才有效。在您的顶级文件夹中启动 运行 terraform 命令后,该配置将被忽略。

根据我的经验,您在“模拟”模块中尝试做的事情只属于 top-level .tf 文件,而不是模块。