跳到内容
观澜涉川 · 札记EN

在本地运行 Pulumi 管理 GCP 资源

· 约 3 分钟阅读

用 CI/CD 流水线部署 GCP 基础设施,是 Cloud Engineering 的正道:比如 GitHub Actions 配合 Workload Identity Federation,把身份、权限、审计都收敛到流水线里,本地不必持有长期凭据。但在学习阶段,或者线上出了故障需要紧急手工修一把时,从本地跑 Pulumi 依然很实用。

麻烦往往出在本地认证上。Pulumi 的 GCP Provider 在没有显式配置时,会回退到 Application Default Credentials(ADC);而在企业环境里,这条路径经常被组织策略挡住,需要 Google Workspace 或 Cloud 管理员放行。本文记录一个更轻的技巧:复用 gcloud 已经登录的身份,打印一个临时访问令牌并导出成环境变量,就能让本地 Pulumi 直接跑起来。

常规的本地认证方式

Pulumi 的 GCP Provider 支持几种认证方式。本地开发时官方推荐的是先登录 ADC:

Terminal window
gcloud auth application-default login

它会把用户凭据写进 ADC 文件,供 Pulumi 等客户端库读取。另一条路是创建服务账号密钥,再通过 GOOGLE_APPLICATION_CREDENTIALS 指向密钥文件。若没有配置任何凭据,Provider 最后才会回退到 ADC。

在企业环境里,这两条路都可能走不通:

  • 创建服务账号密钥通常被组织策略禁用,例如约束 constraints/iam.disableServiceAccountKeyCreation。
  • ADC 登录、以及在组织中放行某些认证方式,往往需要管理员操作。

于是就出现了”本地跑 Pulumi 还得找管理员开权限”的尴尬。下面这个技巧绕开了这些步骤:既不创建密钥,也不单独登录 ADC,只是复用 gcloud 已登录的用户身份。

技巧:用 gcloud 的临时访问令牌

前提是本机已经用 gcloud auth login 登录过,并且该账号本身能访问目标项目。

打印访问令牌

Terminal window
gcloud auth print-access-token

它会打印当前 gcloud 活跃账号的 OAuth 2.0 访问令牌。

导出为 Pulumi 读取的环境变量

Terminal window
export GOOGLE_OAUTH_ACCESS_TOKEN="$(gcloud auth print-access-token)"

这里有两个容易混淆的环境变量,值得单独说清楚:

  • GOOGLE_OAUTH_ACCESS_TOKEN:Pulumi 的 GCP Provider 读取的变量,对应 provider 的 accessToken 配置。
  • CLOUDSDK_AUTH_ACCESS_TOKEN:gcloud CLI 自身读取的变量。

如果导出的是后者,gcloud 命令会正常使用它,但 Pulumi 依然认不出——这也是我一开始记不清”到底是哪个变量”的原因。

指定项目并执行

Terminal window
export GOOGLE_PROJECT="your-gcp-project-id"
pulumi up

GOOGLE_PROJECT 是 Provider 读取项目的环境变量之一;按其优先级依次还有 GOOGLE_CLOUD_PROJECT、GCLOUD_PROJECT、CLOUDSDK_CORE_PROJECT。当然,也可以在 Pulumi.<stack>.yaml 里用 gcp:project 指定项目。

这样一来,Pulumi 就用自己的用户身份调用 GCP API,不再需要单独配置 ADC 或服务账号密钥。pulumi preview、pulumi refresh、pulumi import 等命令同理,都能直接用这套凭据。

注意事项

  • 令牌有有效期,默认 1 小时。Pulumi 命令要在有效期内跑完;超时就重新执行 gcloud auth print-access-token 并重新导出即可。
  • Pulumi 不会自动刷新这个令牌,它和 Terraform 的 access_token 一样,只是拿来即用、过期作废。
  • 不要把令牌写进代码或提交到 Git。临时会话用环境变量最省事;若一定要落到 Pulumi 配置里,至少用 pulumi config set --secret。
  • 本文的环境变量技巧适用于 pulumi-gcp(classic)Provider。若你用的是较新的 pulumi-google-native,它不读 GOOGLE_OAUTH_ACCESS_TOKEN,需要把令牌通过 pulumi config set 放进 Provider 配置里。

先提权:用 PAM 临时拿权限

在权限收紧的组织里,日常账号通常没有部署所需的角色,需要先提权。Google Cloud 的 Privileged Access Manager(PAM)提供”按需、限时、可审批”的临时授权,正好适合这种场景。

先搜索自己可以申请的 entitlement:

Terminal window
gcloud pam entitlements search \
--caller-access-type=grant-requester \
--location=global \
--project="your-gcp-project-id"

再发起授权申请,例如申请 1 小时:

Terminal window
gcloud pam grants create \
--entitlement="ENTITLEMENT_ID" \
--requested-duration=3600s \
--justification="emergency hotfix"

如果 entitlement 配置了审批,还需要审批人执行:

Terminal window
gcloud pam grants approve GRANT_NAME --reason="approved"

授权生效后,再用上面的方式打印令牌并运行 Pulumi 命令(例如 pulumi up)。GCP 在每次调用 API 时都会按当前 IAM 角色鉴权,因此 PAM 临时授予的角色会一并生效。

提示:gcloud pam 的部分子命令目前仍处于 beta / alpha,参数可能变化,以本机 gcloud pam --help 为准。

小结

  • CI/CD 流水线仍是默认路径,Workload Identity Federation 能免去本地长期凭据。
  • 需要在本地临时操作时,用 gcloud auth print-access-token 配合 GOOGLE_OAUTH_ACCESS_TOKEN 最省事,无需 ADC 或服务账号密钥。
  • 权限不够就先用 PAM 做限时提权。
  • 令牌短命、用完即弃;事情处理完,回到流水线。

参考文档