本文档介绍如何使用身份联合从 Microsoft Azure 访问 Google Cloud 资源。
传统上,在 Google Cloud 外部运行的应用使用服务帐号密钥来访问 Google Cloud 资源。通过使用身份联合,您可以让 Azure 资源的代管式身份模拟服务帐号。这样一来,您的工作负载便可以使用短期有效的访问令牌直接访问 Google Cloud 资源,而与服务帐号密钥相关联的维护和安全负担也得以消除。
准备工作
确保您具有 Workload Identity Pool Admin 角色 (
roles/iam.workloadIdentityPoolAdmin
)。此外,IAM Owner (
roles/owner
) 基本角色还具有配置身份联合的权限。您不应在生产环境中授予基本角色,但可以在开发或测试环境中授予这些角色。为您的组织更新组织政策以允许来自 Azure 的联合。
创建工作负载身份池
工作负载身份池是外部身份集合的容器。工作负载身份池彼此隔离,但是单个池可以模拟任意数量的服务帐号。一般说来,我们建议为您的每个环境(例如开发环境、预演环境或生产环境)创建一个新池。
如需创建新的工作负载身份池,您需要提供一个 ID。您还可以提供可选的说明和显示名。 ID 不能以 gcp-
开头;此前缀已预留给 Google 使用。
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" }
将 Azure 添加为身份提供商
如需将 Azure 配置为工作负载身份池的身份提供商,请至少提供以下内容:
提供商的 ID。
本文档上一部分中的工作负载身份池 ID。
您的 Azure 租户 ID。
特性映射列表,用于将 Azure 管理的身份的令牌上的声明映射到 Google 令牌上的特性。您可以使用
assertion
来引用 Azure 令牌,使用google
来表示 Google 特性,使用attribute
来表示自定义特性。Google 特性有两个:
google.subject
和google.groups
。您可以在 IAM 角色绑定中引用这些特性。google.subject
也会显示在 Cloud Logging 日志条目中。您必须为
google.subject
提供映射。通常,我们建议将其映射到assertion.sub
,其中包含您将在下一部分中创建的代管式身份的对象 ID。这样可以提供在 IAM 角色绑定中使用的固定标识符。映射如下所示:google.subject=assertion.sub
对于更复杂的断言,您可以使用通用表达式语言。例如,如果工作负载身份池包含多个身份提供商,则您可以附加前缀来区分它们:
google.subject="azure::" + assertion.tid + "::" + assertion.sub
google.subject
字段不能超过 127 个字符。您还可以指定自定义特性。例如,以下代码将
assertion.tid
映射到attribute.tid
:attribute.tid=assertion.tid
以下示例根据
assertion.oid
的值分配显示名:attribute.managed_identity_name={ "8bb39bdb-1cc5-4447-b7db-a19e920eb111":"workload1", "55d36609-9bcf-48e0-a366-a3cf19027d2a":"workload2" }[assertion.oid]
如需获取您可以引用的声明的完整列表,请获取工作负载中 Azure 虚拟机的访问令牌。在您的请求中,请将
resource
参数替换为工作负载身份池的完整资源名称。例如:
curl
curl -s \ 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id&object_id=managed-identity-object-id' \ -H Metadata:true -H "Cache-Control: no-cache"
PowerShell
Invoke-WebRequest \ -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id&object_id=managed-identity-object-id' \ -Headers @{Metadata="true"}
该响应是一个带有
access_token
字段的 JSON 对象,其中包含 Azure 虚拟机的访问令牌。要解码访问令牌并查看可用的声明,请按以下步骤操作:- 复制完整的访问令牌。
- 在网络浏览器中,转到 https://jwt.ms/。
- 将访问令牌粘贴到文本框中。
- 点击声明。
如需在表达式中引用声明的特定部分,请使用 CEL
extract()
函数,该函数会根据您提供的模板从声明中提取值。如需详细了解extract()
,请参阅从特性中提取值。如需检查凭据是否包含声明,请使用
has()
函数。
您还可以提供几个可选参数:
显示名和说明。
指定主帐号必须提供的特性的条件。该条件可以应用于 Azure 凭据上的声明或 Google 凭据上的特性。任何不符合该条件的请求都会被拒绝。
条件的格式为返回布尔值的 CEL 表达式。例如,以下代码会拒绝来自非特定群组成员的任何身份的请求:
"e968c2ef-047c-498d-8d79-16ca1b61e77e" in assertion.groups
如需详细了解条件的常见用例,请参阅工作负载身份联合概览。
以下示例演示了如何将 Azure 添加为身份提供商:
gcloud
执行 gcloud beta iam workload-identity-pools providers create-oidc
命令以将 Azure 添加为身份提供商:
gcloud beta iam workload-identity-pools providers create-oidc provider-id \ --workload-identity-pool="pool-id" \ --issuer-uri="https://sts.windows.net/azure-tenant-id" \ --location="global" \ --attribute-mapping="google.subject=assertion.sub"
响应如下所示:
Created workload identity pool provider [provider-id].
REST
projects.locations.workloadIdentityPools.providers.create
方法会将 Azure 添加为提供商。
HTTP 方法和网址:
POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools/pool-id/providers?workloadIdentityPoolProviderId=provider-id
请求 JSON 正文:
{ "attributeMapping": { "google.subject": "assertion.sub" }, "oidc": { "issuerUri": "https://sts.windows.net/azure-tenant-id" } }
如需发送您的请求,请展开以下选项之一:
该方法会返回长时间运行的 Operation
,类似于以下内容:
{ "name": "projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id/operations/operation-id" }
为身份联合配置 Azure 租户
如需为身份联合准备 Azure 租户,请执行以下操作:
创建一个 Azure AD 应用和服务主帐号,并将其应用 ID URI 设置为您在上一部分创建的提供商的完整资源名称:
https://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
创建一个代管式身份,并记下其对象 ID。
授予模拟服务帐号的权限
外部身份无法直接访问大多数 Google Cloud 资源。而是让这些身份为服务帐号授予 Workload Identity User 角色 (roles/iam.workloadIdentityUser
) 来模拟服务帐号。
如需为特定的代管式身份添加此角色绑定,请运行以下命令:
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/managed-identity-object-id"
如需为池中的所有身份添加此绑定,请运行以下命令:
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/group/azure-tenant-id"
您还可以根据自定义特性授予访问权限。例如:
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 或客户端库添加或撤消绑定。如需了解详情,请参阅授予、更改和撤消对资源的访问权限。
将 Azure 令牌交换为 Google 令牌
一旦 Azure 代管式身份能够模拟服务帐号,您就可以将其凭据交换为 Google 凭据。
如需交换凭据,请执行以下操作:
使用 Azure Instance Metadata Service (IMDS) 来获取 Azure 访问令牌。
将
resource
查询参数设置为以下值:https://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
将
object_id
查询参数设置为您之前创建的代管式身份的对象 ID。将 Azure 访问令牌传递给 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": "azure-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
该请求会以服务帐号的身份获得授权。
后续步骤
使用身份联合访问 AWS 的资源或访问 OIDC 提供商的资源。