GCP Workload Identity Federation
本指南通过 Workload Identity Federation 配置 Google Cloud Secret Manager 作为密钥 provider:CrewAI Platform 会生成短期 OIDC tokens,通过 Security Token Service 换取 Google Cloud 凭据,然后读取你的密钥 - 全程不会存放长期 service account key。
运行时如何工作
Section titled “运行时如何工作”- 部署 worker 从 CrewAI Platform 请求一个新的 OIDC JWT。
- worker 通过 Security Token Service 将 JWT 交换为 federated Google credential,引用下面设置的 Workload Identity Pool Provider。
- worker 调用
secretmanager.googleapis.com:accessSecretVersion读取 secret,直接使用 federated credential(federated principal 持有roles/secretmanager.secretAccessor- 见第 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 步会用到它。
第 2 步 - 创建 Workload Identity Pool
Section titled “第 2 步 - 创建 Workload Identity Pool”Workload Identity Pool 是 Google Cloud 侧用于受信任外部身份的容器。你会在这个 pool 中把 CrewAI Platform 注册为一个 provider。
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 中”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 的subclaim,CrewAI Platform 会将其设置为organization:<uuid>。attribute.organization是一个自定义属性 - 我们把它映射到 JWT 的organization_idclaim,这样后续可以在 IAM binding 中引用它。
--attribute-condition 是一个深度防御检查,用于拒绝缺少 organization_id claim 的 token。
获取 provider resource name(audience 和 IAM bindings 会用到它):
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。两个都需要,功能才能端到端正常工作。
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 kickoffgcloud 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:
- 打开你 project 的 IAM & Admin → IAM。
- 点击 GRANT ACCESS。
- New principals: 粘贴完整的
principalSet://...attribute.organization/<YOUR_CREWAI_ORG_UUID>字符串。 - 分配角色 Secret Manager Viewer (
roles/secretmanager.viewer)。 - 点击 SAVE。
- 再次点击 GRANT ACCESS,并重复一次,角色换成 Secret Manager Secret Accessor (
roles/secretmanager.secretAccessor)。
第 5 步 - 在 GCP 中至少创建一个 Secret
Section titled “第 5 步 - 在 GCP 中至少创建一个 Secret”如果你还没有可用于测试的 secret,可以通过 gcloud CLI 创建一个:
echo -n "hello from gcp" | gcloud secrets create crewai-test-keyword \ --data-file=- \ --project=<YOUR_PROJECT_ID> \ --replication-policy=automatic或者通过 Secret Manager console:
- 在你的 GCP project 中打开 Secret Manager。
- 点击 + CREATE SECRET。
- Name:
crewai-test-keyword. Secret value: 粘贴你的值。 - 点击 CREATE SECRET。
第 6 步 - 在 CrewAI Platform 中添加 Workload Identity Configuration
Section titled “第 6 步 - 在 CrewAI Platform 中添加 Workload Identity Configuration”在 CrewAI Platform 中,进入 Settings → Workload 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”进入 Settings → Secret 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。
第 8 步 - 测试连接
Section titled “第 8 步 - 测试连接”保存凭据后,点击 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.list 和 secretmanager.versions.access 会在 Secret Name autocomplete 加载时,或者在环境变量解析 kickoff 时分别被单独执行。参见 Troubleshooting 了解 handshake 失败模式。
第 9 步 - 在环境变量中引用密钥
Section titled “第 9 步 - 在环境变量中引用密钥”就像引用其他 Secrets Manager-backed env var 一样,在 automation 上引用这个 secret。有关表单字段和行为,请参见 Using the Secrets Manager。
第 10 步 - 验证轮换
Section titled “第 10 步 - 验证轮换”部署运行起来后,通过添加新版本来轮换 GCP 中的 secret(Secret Manager 默认总是读取最新启用的版本):
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_target | audience claim 与 Workload Identity Provider 期望的 audience 不匹配。CrewAI Platform 会自动设置 audience;如果你自定义过,请确保它匹配 //iam.googleapis.com/<provider-resource-name>。 |
Failed to fetch JWKS from issuer | GCP STS 无法访问你的 CrewAI Platform host。确认该 host 在互联网上可访问,并且 /.well-known/openid-configuration 返回 200。 |
Attribute condition rejected token | OIDC provider 的 attribute condition(第 3 步)要求 organization_id。CrewAI Platform 总会设置这个 claim,因此这通常意味着 pool/provider 配置错误。重新检查 provider 的 attribute condition。 |
Secret Name autocomplete 显示 PERMISSION_DENIED: secretmanager.secrets.list | federated principal 缺少 project scope 下的 roles/secretmanager.viewer。secretmanager.secrets.list 权限只能在 project scope 授予,不能按 secret 授予。参见第 4 步。 |
| 明明 Test Connection 通过了,kickoff 仍无法解析 secret | WI 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。 |