如何通过Terraform授予WIF访问服务账号权限以实现身份池模拟
我需要为WIF授予服务账号访问权限,让workload identity pool(身份池)能够模拟服务账号。在UI里我可以点击「授予」按钮完成该操作(配图:WIF授予权限界面)。请问如何通过Terraform实现该配置?
以下是当前Terraform代码:
resource "google_iam_workload_identity_pool" "gha-identity-pool" { workload_identity_pool_id = "gha-identity-pool-3" } resource "google_iam_workload_identity_pool_provider" "gha-identity-pool-provider" { workload_identity_pool_id = google_iam_workload_identity_pool.gha-identity-pool.workload_identity_pool_id workload_identity_pool_provider_id = "gha-identity-pool-provider" display_name = "GHA identity pool provider" attribute_mapping = { "google.subject" = "assertion.sub" "attribute.actor" = "assertion.actor" "attribute.repository" = "assertion.repository" } oidc { issuer_uri = "https://token.actions.githubusercontent.com" } } data "google_project" "gcp_project" {} resource "google_service_account_iam_member" "gha-sv-account-wif-iam-member" { service_account_id = var.gha_service_account_name role = "roles/iam.workloadIdentityUser" member = "principalSet://iam.googleapis.com/projects/${data.google_project.gcp_project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.gha-identity-pool.workload_identity_pool_id}/attribute.repository/org1/repo1" }
执行时出现如下错误:
google.auth.exceptions.RefreshError: ('无法获取模拟凭据:响应中无访问令牌或过期时间无效。', '{
"error": {
"code": 403,
"message": "对资源的权限 'iam.serviceAccounts.getAccessToken' 被拒绝(或资源可能不存在)。",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "IAM_PERMISSION_DENIED",
"domain": "iam.googleapis.com",
"metadata": {
"permission": "iam.serviceAccounts.getAccessToken"
}
}
]
}
}
')
解决方案
1. 检查执行账号权限
运行Terraform的账号必须拥有以下权限:
iam.serviceAccounts.setIamPolicy:给目标服务账号绑定IAM角色iam.workloadIdentityPools.get:读取身份池配置信息- 若用服务账号模拟执行,需额外给该账号授予
iam.serviceAccounts.getAccessToken权限
2. 修正Principal格式(核心)
当前代码的member字段格式存在两种可能的问题:
- 若要匹配单个代码仓库,应使用
principal://格式而非principalSet://:member = "principal://iam.googleapis.com/projects/${data.google_project.gcp_project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.gha-identity-pool.workload_identity_pool_id}/subject/repo:org1/repo1" - 若用
principalSet://批量匹配,需确保属性名和值与attribute_mapping完全对齐:你的映射规则是attribute.repository = "assertion.repository",所以当前格式是对的,但要确认OIDC断言中的repository值确实是org1/repo1
3. 验证服务账号有效性
确保var.gha_service_account_name对应的服务账号已存在,建议使用完整资源路径格式:
service_account_id = "projects/${data.google_project.gcp_project.project_id}/serviceAccounts/${var.gha_service_account_name}@${data.google_project.gcp_project.project_id}.iam.gserviceaccount.com"
修正后的完整google_service_account_iam_member示例:
resource "google_service_account_iam_member" "gha-sv-account-wif-iam-member" { service_account_id = "projects/${data.google_project.gcp_project.project_id}/serviceAccounts/${var.gha_service_account_name}@${data.google_project.gcp_project.project_id}.iam.gserviceaccount.com" role = "roles/iam.workloadIdentityUser" member = "principalSet://iam.googleapis.com/projects/${data.google_project.gcp_project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.gha-identity-pool.workload_identity_pool_id}/attribute.repository/org1/repo1" }
内容的提问来源于stack exchange,提问作者Aseem

