从 OIDC 身份提供商访问资源

本文档介绍如何使用身份联合从支持 OpenID Connect (OIDC) 的身份提供商访问 Google Cloud 资源。

传统上,在 Google Cloud 外部运行的应用使用服务帐号密钥来访问 Google Cloud 资源。通过使用身份联合,您可以让外部身份模拟服务帐号。这样一来,您的工作负载便可以使用短期有效的访问令牌直接访问 Google Cloud 资源,而与服务帐号密钥相关联的维护和安全负担也得以消除。

准备工作

  1. 确保您具有 Workload Identity Pool Admin 角色 (roles/iam.workloadIdentityPoolAdmin)。

    原初 IAM Owner (roles/owner) 和 Editor (roles/editor) 角色还可以授予配置身份联合的权限。但是,我们建议使用 Workload Identity Pool Admin 角色,以避免授予对 Google Cloud 资源的不必要访问权限。

  2. 创建 Google Cloud 服务帐号

  3. 向服务帐号授予调用您的工作负载所需的 Google Cloud API 的访问权限

创建工作负载身份池

工作负载身份池是外部身份集合的容器。工作负载身份池彼此隔离,但是单个池可以模拟任意数量的服务帐号。一般说来,我们建议为您的每个环境(例如开发环境、预演环境或生产环境)创建一个新池。

如需创建新的工作负载身份池,您需要提供一个 ID。您还可以提供可选的说明和显示名。

gcloud 命令

执行 gcloud beta iam workload-identity-pools create 命令以创建工作负载身份池:

gcloud beta iam workload-identity-pools create pool-id \
    --location="global" \
    --description="description" \
    --display-name="display-name"

REST API

projects.locations.workloadIdentityPools.create 方法可创建工作负载身份池。

HTTP 方法和网址:

POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools?workloadIdentityPoolId=pool-id

请求 JSON 正文:

{
  "description": "description",
  "display-name": "display-name"
}

如需发送您的请求,请展开以下选项之一:

 

添加 OIDC 身份提供商

如需为工作负载身份池配置 OIDC 身份提供商,请至少提供以下内容:

  • 提供商的 ID。

  • 本文档上一部分中的工作负载身份池 ID。

  • 提供商的颁发者 URI。其格式通常为 https://example.com。如需查找该 URI,请参阅提供商的 OIDC 集成文档。

您还可以提供几个可选参数:

  • 显示名和说明。

  • 特性映射列表,用于将外部令牌上的声明映射到 Google 令牌上的特性。您可以使用 assertion 来引用外部凭据,使用 google 来表示 Google 特性,使用 attribute 来表示自定义特性。

    Google 特性有两个:google.subjectgoogle.groups。您可以在 IAM 绑定中引用这些特性。google.subject 也会显示在 Cloud Logging 日志条目中。

    一般说来,我们建议将 assertion.sub 映射到 google.subject。这样可以提供在 IAM 绑定中使用的固定标识符。映射如下所示:

    google.subject=assertion.sub
    

    对于更复杂的断言,您可以使用通用表达式语言。例如,如果工作负载身份池包含多个身份提供商,则您可以附加前缀来区分它们:

    google.subject="provider-a::" + assertion.sub
    

    google.subject 字段不能超过 127 个字符。

    您还可以指定自定义特性。例如,以下代码将 assertion.foo 映射到 attribute.bar

    attribute.bar=assertion.foo
    

    如需查看您可以引用的声明的完整列表,请参阅提供商的访问令牌文档。

    如需在表达式中引用声明的特定部分,请使用 CEL extract() 函数,该函数会根据您提供的模板从声明中提取值。如需详细了解 extract(),请参阅从特性中提取值

    如需检查凭据是否包含声明,请使用 has() 函数。

  • 指定主帐号必须提供的特性的特性条件。该条件可以应用于外部凭据上的声明或 Google 凭据上的特性。任何不符合该条件的请求都会被拒绝。

    特性条件的格式为返回布尔值的 CEL 表达式。例如,以下代码会拒绝来自非特定群组成员的任何身份的请求:

    group in assertion.groups
    

    如果身份提供商面向公众提供服务,则我们强烈建议您使用特性条件。如需详细了解特性条件的常见使用场景,请参阅工作负载身份联合概览。

  • 允许的目标设备列表,用于指定外部凭据上的 aud 字段可以包含哪些值。您最多可以配置 10 个目标设备,每个目标设备最多 256 个字符。如需了解 aud 的默认值,请参阅提供商的文档。

    或者,如果身份提供商允许您配置 aud 的自定义值,则您可以将允许的目标设备参数留空,并将 aud 的值设置为工作负载身份提供商的完整资源名称。HTTP 前缀是可选的;例如:

    //iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
    https://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
    

    无论是哪种情况,系统都会拒绝任何不包含某个允许值的令牌交换请求。

以下示例演示了如何添加身份提供商:

gcloud 命令

执行 gcloud beta iam workload-identity-pools providers create-oidc 命令以添加身份提供商:

gcloud beta iam workload-identity-pools providers create-oidc provider-id \
    --workload-identity-pool="pool-id" \
    --issuer-uri="issuer-uri" \
    --location="global"

REST API

projects.locations.workloadIdentityPools.providers.create 方法会添加 OIDC 身份提供商。

HTTP 方法和网址:

POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools/pool-id/providers?workloadIdentityPoolProviderId=provider-id

请求 JSON 正文:

{
  "issuerUrl": "issuer-uri"
}

如需发送您的请求,请展开以下选项之一:

 

模拟服务帐号

您可以使用 IAM 向工作负载身份池以及从其提供商联合的身份授予针对资源的角色Workload Identity User 角色 (roles/iam.workloadIdentityUser) 可授予模拟服务帐号的权限,该权限允许外部身份访问 Google Cloud 资源。

如需为特定身份添加此绑定,请使用您映射到 google.subject 的值:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
  --role roles/iam.workloadIdentityUser \
  --member "principal://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/subject/subject"

如需为群组的所有成员添加此绑定,请运行以下命令:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
    --role roles/iam.workloadIdentityUser \
    --member "principalSet://iam.googleapis.com/project/project-number/workloadIdentityPools/pool-id/groups/group-name"

您还可以根据自定义特性授予访问权限。例如:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/attribute.custom-attribute-name/custom-attribute-value"

如需撤消访问权限,请将 add-iam-policy-binding 替换为 remove-iam-policy-binding

您还可以使用 REST API 或客户端库添加或撤消绑定。如需了解详情,请参阅授予、更改和撤消对资源的访问权限

将外部令牌交换为 Google 令牌

一旦外部身份能够模拟服务帐号,您就可以将其凭据交换为 Google 凭据。

如需交换凭据,请执行以下操作:

  1. 从身份提供商获取 OIDC ID 令牌(如需了解详细说明,请参阅身份提供商的文档)。

  2. 将 OIDC ID 令牌传递给 Security Token Service token() 方法,以获取联合访问令牌:

    REST API

    token 方法可将第三方令牌交换为 Google 令牌。

    在使用下面的请求数据之前,请先进行以下替换:

    • project-id:您的 Google Cloud 项目 ID。
    • pool-id:您在本教程前面创建的工作负载身份池的 ID。
    • provider-id:您在本教程前面配置的身份提供商的 ID。

    HTTP 方法和网址:

    POST https://sts.googleapis.com/v1beta/token

    请求 JSON 正文:

    {
      "audience": "https://iam.googleapis.com/projects/project-id/locations/global/workloadIdentityPools/pool-id/providers/provider-id",
      "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
      "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
      "scope": "https://www.googleapis.com/auth/cloud-platform",
      "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
      "subject_token": "oidc-id-token"
    }
    

    如需发送您的请求,请展开以下选项之一:

     

    该方法会返回联合令牌。

  3. 通过调用 generateAccessToken() 将联合令牌交换为 OAuth 2.0 访问令牌:

    REST API

    curl -X POST -H "Authorization: Bearer federated-token \
      https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/service-account-email:generateAccessToken
    

拥有服务帐号的访问令牌后,您可以通过在请求的 Authorization 标头中添加该令牌来使用它调用 Google Cloud API:

Authorization: Bearer service-account-access-token

该请求会以服务帐号的身份获得授权。

后续步骤