本文档介绍如何使用身份联合从支持 OpenID Connect (OIDC) 的身份提供商访问 Google Cloud 资源。
传统上,在 Google Cloud 外部运行的应用使用服务帐号密钥来访问 Google Cloud 资源。通过使用身份联合,您可以让外部身份模拟服务帐号。这样一来,您的工作负载便可以使用短期有效的访问令牌直接访问 Google Cloud 资源,而与服务帐号密钥相关联的维护和安全负担也得以消除。
准备工作
确保您具有 Workload Identity Pool Admin 角色 (
roles/iam.workloadIdentityPoolAdmin
)。此外,IAM Owner (
roles/owner
) 和 Editor (roles/editor
) 基本角色还具有配置身份联合的权限。您不应在生产环境中授予基本角色,但可以在开发或测试环境中授予这些角色。为您的组织更新组织政策,以允许来自身份提供商的联合身份服务。
创建工作负载身份池
工作负载身份池是外部身份集合的容器。工作负载身份池彼此隔离,但是单个池可以模拟任意数量的服务帐号。一般说来,我们建议为您的每个环境(例如开发环境、预演环境或生产环境)创建一个新池。
如需创建新的工作负载身份池,您需要提供一个 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"
响应如下所示:
Created workload identity pool [pool-id].
REST
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" }
如需发送您的请求,请展开以下选项之一:
该方法会返回长时间运行的 Operation
,类似于以下内容:
{ "name": "projects/project-number/locations/global/workloadIdentityPools/pool-id/operations/operation-id" }
添加 OIDC 身份提供商
如需为工作负载身份池配置 OIDC 身份提供商,请至少提供以下内容:
提供商的 ID。
本文档上一部分中的工作负载身份池 ID。
提供商的颁发者 URI。其格式通常为
https://example.com
。如需查找该 URI,请参阅提供商有关 OIDC 集成的文档。特性映射列表,用于将外部令牌上的声明映射到 Google 令牌上的特性。您可以使用
assertion
来引用外部凭据,使用google
来表示 Google 特性,使用attribute
来表示自定义特性。Google 特性有两个:
google.subject
和google.groups
。您可以在 IAM 角色绑定中引用这些特性。google.subject
也会显示在 Cloud Logging 日志条目中。您必须为
google.subject
提供映射。通常,我们建议将其映射到assertion.sub
,这样可提供在 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()
函数。允许的目标设备列表,用于指定外部凭据上的
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
无论是哪种情况,系统都会拒绝任何不包含某个允许值的令牌交换请求。
您还可以提供几个可选参数:
显示名和说明。
指定主帐号必须提供的特性的条件。该条件可以应用于外部凭据上的声明或 Google 凭据上的特性。任何不符合该条件的请求都会被拒绝。
条件的格式为返回布尔值的 CEL 表达式。例如,以下代码会拒绝来自非特定群组成员的任何身份的请求:
group in assertion.groups
如果身份提供商面向公众提供服务,则我们强烈建议您使用条件。如需详细了解条件的常见用例,请参阅工作负载身份联合概览。
以下示例演示了如何添加身份提供商:
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" \ --attribute-mapping="google.subject=assertion.sub"
响应如下所示:
Created workload identity pool provider [provider-id].
REST
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" }
如需发送您的请求,请展开以下选项之一:
该方法会返回长时间运行的 Operation
,类似于以下内容:
{ "name": "projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id/operations/operation-id" }
授予模拟服务帐号的权限
外部身份无法直接访问大多数 Google Cloud 资源。而是让这些身份为服务帐号授予 Workload Identity User 角色 (roles/iam.workloadIdentityUser
) 来模拟服务帐号。
如需为特定身份添加此绑定,请使用您映射到 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 凭据。
如需交换凭据,请执行以下操作:
从身份提供商获取 OIDC ID 令牌(如需了解详细说明,请参阅身份提供商的文档)。
将 OIDC ID 令牌传递给 Security Token Service
token()
方法,以获取联合访问令牌:REST
token
方法可将第三方令牌交换为 Google 令牌。在使用下面的请求数据之前,请先进行以下替换:
project-number
:您的 Google Cloud 项目编号。pool-id
:您在本教程前面创建的工作负载身份池的 ID。provider-id
:您在本教程前面配置的身份提供商的 ID。
HTTP 方法和网址:
POST https://sts.googleapis.com/v1beta/token
请求 JSON 正文:
{ "audience": "//iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id", "grantType": "urn:ietf:params:oauth:grant-type:token-exchange", "requestedTokenType": "urn:ietf:params:oauth:token-type:access_token", "scope": "https://www.googleapis.com/auth/cloud-platform", "subjectTokenType": "urn:ietf:params:oauth:token-type:jwt", "subjectToken": "oidc-id-token" }
如需发送您的请求,请展开以下选项之一:
该方法会返回联合令牌。
调用
generateAccessToken()
以将联合令牌交换为服务帐号访问令牌。有限数量的 Google Cloud API 支持联合令牌;所有 Google Cloud API 都支持服务帐号访问令牌。REST
Service Account Credentials API 的
serviceAccounts.generateAccessToken
方法为服务帐号生成 OAuth 2.0 访问令牌。在使用下面的请求数据之前,请先进行以下替换:
project-id
:您的 Google Cloud 项目 ID。sa-id
:您的服务帐号的 ID。此 ID 可以是服务帐号的电子邮件地址(格式为sa-name@project-id.iam.gserviceaccount.com
)或服务帐号的唯一数字 ID。token
:联合访问令牌。
HTTP 方法和网址:
POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-name@project-id.iam.gserviceaccount.com:generateAccessToken
请求 JSON 正文:
{ "scope": [ "https://www.googleapis.com/auth/cloud-platform" ] }
如需发送您的请求,请展开以下选项之一:
如果
generateAccessToken
请求成功,响应正文会包含一个 OAuth 2.0 访问令牌和一个到期时间。然后,便可以使用accessToken
代表服务帐号验证请求,直至到达expireTime
时限:{ "accessToken": "eyJ0eXAi...NiJ9", "expireTime": "2020-04-07T15:01:23.045123456Z" }
拥有服务帐号的访问令牌后,您可以通过在请求的 Authorization
标头中添加该令牌来使用它调用 Google Cloud API:
Authorization: Bearer service-account-access-token
该请求会以服务帐号的身份获得授权。