跳转到内容

GCP Workload Identity Federation

本指南通过 Workload Identity Federation 配置 Google Cloud Secret Manager 作为密钥 provider:CrewAI Platform 会生成短期 OIDC tokens,通过 Security Token Service 换取 Google Cloud 凭据,然后读取你的密钥 - 全程不会存放长期 service account key。

  1. 部署 worker 从 CrewAI Platform 请求一个新的 OIDC JWT。
  2. worker 通过 Security Token Service 将 JWT 交换为 federated Google credential,引用下面设置的 Workload Identity Pool Provider。
  3. worker 调用 secretmanager.googleapis.com:accessSecretVersion 读取 secret,直接使用 federated credential(federated principal 持有 roles/secretmanager.secretAccessor - 见第 4 步)。
  4. 获取到的值会在本次 automation kickoff 中被注入为环境变量值。

OIDC subject tokens 会缓存大约 1 小时,以避免每次 kickoff 都重新签发。无论 OIDC 缓存状态如何,secret values 都会在每次 kickoff 时刷新获取,这也是这条路径具备 rotation awareness 的原因。

第 1 步 - 找到 CrewAI Platform 的 OIDC Issuer URL

Section titled “第 1 步 - 找到 CrewAI Platform 的 OIDC Issuer URL”

你的 CrewAI Platform 安装会在 https://<your-platform-host>/.well-known/openid-configuration 发布一个 OpenID Connect discovery document。该文档中的 issuer 字段就是 Google 会注册为受信任 OIDC provider 的 URL。

在浏览器中打开这个 URL:

https://<your-platform-host>/.well-known/openid-configuration

你应该会看到 JSON,包含:

{
"issuer": "https://<your-platform-host>",
"jwks_uri": "https://<your-platform-host>/oauth2/jwks",
...
}

记下 issuer 的准确值 - 第 3 步会用到它。

Workload Identity Pool 是 Google Cloud 侧用于受信任外部身份的容器。你会在这个 pool 中把 CrewAI Platform 注册为一个 provider。

Terminal window
gcloud iam workload-identity-pools create crewai-pool \
--project=<YOUR_PROJECT_ID> \
--location=global \
--display-name="CrewAI Platform"

或者在 Workload Identity Pools console 中点击 Create Pool

第 3 步 - 将 CrewAI Platform 作为 OIDC Provider 添加到 pool 中

Section titled “第 3 步 - 将 CrewAI Platform 作为 OIDC Provider 添加到 pool 中”
Terminal window
gcloud iam workload-identity-pools providers create-oidc crewai-provider \
--project=<YOUR_PROJECT_ID> \
--location=global \
--workload-identity-pool=crewai-pool \
--display-name="CrewAI Platform OIDC" \
--issuer-uri="https://<your-platform-host>" \
--attribute-mapping="google.subject=assertion.sub,attribute.organization=assertion.organization_id" \
--attribute-condition="assertion.organization_id != ''"

--attribute-mapping 告诉 Google 如何把 JWT claims 映射到 Google attributes:

  • google.subject 是 principal 标识符 - 我们把它映射到 JWT 的 sub claim,CrewAI Platform 会将其设置为 organization:<uuid>
  • attribute.organization 是一个自定义属性 - 我们把它映射到 JWT 的 organization_id claim,这样后续可以在 IAM binding 中引用它。

--attribute-condition 是一个深度防御检查,用于拒绝缺少 organization_id claim 的 token。

获取 provider resource name(audience 和 IAM bindings 会用到它):

Terminal window
gcloud iam workload-identity-pools providers describe crewai-provider \
--project=<YOUR_PROJECT_ID> \
--location=global \
--workload-identity-pool=crewai-pool \
--format="value(name)"

输出类似于:

projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/crewai-pool/providers/crewai-provider

这就是第 6 步中 CrewAI Platform 要填写的 Workload Identity Provider 值。CrewAI Platform 在签发 token 时会自动将 OIDC audience 计算为 //iam.googleapis.com/<this-resource-name>

第 4 步 - 为 federated principal 授予 Secret Manager 访问权限

Section titled “第 4 步 - 为 federated principal 授予 Secret Manager 访问权限”

在 project scope 下,把两个 Secret Manager role 都绑定给 federated principal - 一个 role 用于启用 env-var form 中的 Secret Name autocomplete,另一个用于在 automation kickoff 时读取 secret value。两个都需要,功能才能端到端正常工作。

Terminal window
PRINCIPAL_SET="principalSet://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/crewai-pool/attribute.organization/<YOUR_CREWAI_ORG_UUID>"
# Required for the Secret Name autocomplete (calls secretmanager.secrets.list)
gcloud projects add-iam-policy-binding <YOUR_PROJECT_ID> \
--member="$PRINCIPAL_SET" \
--role="roles/secretmanager.viewer"
# Required to read secret values at kickoff
gcloud projects add-iam-policy-binding <YOUR_PROJECT_ID> \
--member="$PRINCIPAL_SET" \
--role="roles/secretmanager.secretAccessor"

<PROJECT_NUMBER> 替换成数字 project number(gcloud projects describe <YOUR_PROJECT_ID> --format='value(projectNumber)'),并把 <YOUR_CREWAI_ORG_UUID> 替换成应该被允许读取密钥的 CrewAI Platform organization 的 UUID。你可以在平台 UI 的组织设置页找到 org UUID,或者通过 API 获取。这样就把 federation 范围限定到了一个特定 CrewAI organization - 只有为该组织的 automations 签发的 token 才会被接受。

或者通过 Google Cloud console:

  1. 打开你 project 的 IAM & AdminIAM
  2. 点击 GRANT ACCESS
  3. New principals: 粘贴完整的 principalSet://...attribute.organization/<YOUR_CREWAI_ORG_UUID> 字符串。
  4. 分配角色 Secret Manager Viewer (roles/secretmanager.viewer)。
  5. 点击 SAVE
  6. 再次点击 GRANT ACCESS,并重复一次,角色换成 Secret Manager Secret Accessor (roles/secretmanager.secretAccessor)。

第 5 步 - 在 GCP 中至少创建一个 Secret

Section titled “第 5 步 - 在 GCP 中至少创建一个 Secret”

如果你还没有可用于测试的 secret,可以通过 gcloud CLI 创建一个:

Terminal window
echo -n "hello from gcp" | gcloud secrets create crewai-test-keyword \
--data-file=- \
--project=<YOUR_PROJECT_ID> \
--replication-policy=automatic

或者通过 Secret Manager console

  1. 在你的 GCP project 中打开 Secret Manager
  2. 点击 + CREATE SECRET
  3. Name: crewai-test-keyword. Secret value: 粘贴你的值。
  4. 点击 CREATE SECRET

第 6 步 - 在 CrewAI Platform 中添加 Workload Identity Configuration

Section titled “第 6 步 - 在 CrewAI Platform 中添加 Workload Identity Configuration”

在 CrewAI Platform 中,进入 SettingsWorkload Identity 并点击 Add Workload Identity Config

填写表单:

  • Name: 描述性名称,例如 gcp-prod
  • Cloud Provider: GCP
  • Workload Identity Provider: 第 3 步中的 provider resource name,例如 projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/crewai-pool/providers/crewai-provider。 -(可选)如果你希望它成为创建 GCP-backed secret credential 时默认选择的 WI config,请打开 Default Configuration

点击 Create

第 7 步 - 添加绑定到 WI Config 的 Secret Provider Credential

Section titled “第 7 步 - 添加绑定到 WI Config 的 Secret Provider Credential”

进入 SettingsSecret Provider Credentials 并点击 Add Credential

填写表单:

  • Name: 描述性名称,例如 gcp-prod-wi
  • Provider: Google Cloud Secret Manager
  • Authentication Method: Workload Identity
  • Workload Identity Configuration: 选择你在第 6 步创建的 config。
  • Project ID: 你的 GCP project ID(也就是拥有这些 secrets 的同一个 project)。 -(可选)勾选 Set as default credential for this provider

在 Workload Identity 下方,表单只会要求填写 Project ID - Service Account JSON 字段会被刻意隐藏,因为它不适用于这条路径;federated identity 来自关联的 WI config。

点击 Create

保存凭据后,点击 Test Connection。对于 workload-identity 凭据,这会验证 OIDC handshake:CrewAI Platform 会生成一个 JWT,并通过 Security Token Service 交换成 federated Google access token。绿色结果表示 federation binding 正常。

成功的 Test Connection 说明 Workload Identity Pool、OIDC provider、attribute mapping 和 attribute condition 都已正确连接。它不能证明 Secret Manager IAM 正确 - secretmanager.secrets.listsecretmanager.versions.access 会在 Secret Name autocomplete 加载时,或者在环境变量解析 kickoff 时分别被单独执行。参见 Troubleshooting 了解 handshake 失败模式。

第 9 步 - 在环境变量中引用密钥

Section titled “第 9 步 - 在环境变量中引用密钥”

就像引用其他 Secrets Manager-backed env var 一样,在 automation 上引用这个 secret。有关表单字段和行为,请参见 Using the Secrets Manager

部署运行起来后,通过添加新版本来轮换 GCP 中的 secret(Secret Manager 默认总是读取最新启用的版本):

Terminal window
echo -n "rotated value" | gcloud secrets versions add crewai-test-keyword \
--data-file=- \
--project=<YOUR_PROJECT_ID>

触发一次新的 automation kickoff。该 kickoff 的环境会看到 "rotated value" - 无需重新部署、无需 worker restart、也不必等待 TTL。

若要在 worker logs 中确认,请查找:

Workload identity config '<id>' (gcp): N secret(s) resolved

这行会在每次 kickoff 时出现,并表明对 GCP 进行了新的 accessSecretVersion 调用。

症状可能原因
Test Connection 在 handshake error 处失败STS token exchange 被拒绝。验证 Workload Identity Pool 是否存在、OIDC provider 的 issuer 是否与平台的 issuer 值匹配,以及 attribute condition 是否接受 JWT 的 claims。确认平台的 OIDC discovery URL 可从 GCP 通过公网访问。
Could not refresh access token: invalid_targetaudience claim 与 Workload Identity Provider 期望的 audience 不匹配。CrewAI Platform 会自动设置 audience;如果你自定义过,请确保它匹配 //iam.googleapis.com/<provider-resource-name>
Failed to fetch JWKS from issuerGCP STS 无法访问你的 CrewAI Platform host。确认该 host 在互联网上可访问,并且 /.well-known/openid-configuration 返回 200。
Attribute condition rejected tokenOIDC provider 的 attribute condition(第 3 步)要求 organization_id。CrewAI Platform 总会设置这个 claim,因此这通常意味着 pool/provider 配置错误。重新检查 provider 的 attribute condition。
Secret Name autocomplete 显示 PERMISSION_DENIED: secretmanager.secrets.listfederated principal 缺少 project scope 下的 roles/secretmanager.viewersecretmanager.secrets.list 权限只能在 project scope 授予,不能按 secret 授予。参见第 4 步。
明明 Test Connection 通过了,kickoff 仍无法解析 secretWI binding 正常,但失败的 secret 上缺少 secretmanager.versions.access。审计 roles/secretmanager.secretAccessor(project-scoped,或者如果你按 secret 绑定则检查 per-secret 绑定)。
轮换后的值没有在下一次 kickoff 中生效确认 automation 上的 env var 引用的是 Workload Identity-backed credential(而不是 static-keys credential)。静态路径会把值写入 deploy image。