本文档介绍如何使用身份联合从 Amazon Web Services (AWS) 访问 Google Cloud 资源。
传统上,在 Google Cloud 外部运行的应用使用服务帐号密钥来访问 Google Cloud 资源。通过使用身份联合,您可以允许 AWS 用户或角色模拟服务帐号。这样一来,您的工作负载便可以使用短期有效的访问令牌直接访问 Google Cloud 资源,而与服务帐号密钥相关联的维护和安全负担也得以消除。
准备工作
确保您具有 Workload Identity Pool Admin 角色 (
roles/iam.workloadIdentityPoolAdmin
)。此外,IAM Owner (
roles/owner
) 和 Editor (roles/editor
) 基本角色还具有配置身份联合的权限。您不应在生产环境中授予基本角色,但可以在开发或测试环境中授予这些角色。为您的组织更新组织政策以允许来自 AWS 的联合。
创建 AWS 角色并记下其 Amazon 资源名称 (ARN)。
创建工作负载身份池
工作负载身份池是外部身份集合的容器。工作负载身份池彼此隔离,但是单个池可以模拟任意数量的服务帐号。一般说来,我们建议为您的每个环境(例如开发环境、预演环境或生产环境)创建一个新池,这通常意味着每个 AWS 帐号一个池。
如需创建新的工作负载身份池,您需要提供一个 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" }
将 AWS 添加为身份提供商
如需将 AWS 配置为工作负载身份池的身份提供商,请至少提供以下内容:
提供商的 ID。
本文档上一部分中的工作负载身份池 ID。
您的 AWS 帐号 ID。
您还可以提供几个可选参数:
显示名和说明。
特性映射列表,用于将 AWS 令牌上的特性映射到 Google 令牌上的特性。默认情况下,每个池都使用以下特性映射,这些映射涵盖了大多数常见场景:
Google AWS 说明 google.subject
assertion.arn
IAM 正在对其进行身份验证的主帐号。这也是显示在 Cloud Logging 日志条目中的主体。此映射会自动填充 ARN(采用 arn:aws:sts::account-id:assumed-role/aws-role/aws-session-name
格式)。attribute.aws_role
AWS 角色 AWS 角色(采用 arn:aws:sts::account-id:assumed-role/aws-role
格式)。您还可以指定能够在 IAM 绑定中引用的自定义映射。您可以使用
assertion
来引用 AWS 凭据,使用google
来表示 Google 特性,使用attribute
来表示自定义特性。例如,除了google.subject
的默认映射之外,以下代码将attribute.aws_account
映射到assertion.account
:google.subject=assertion.arn, attribute.aws_account=assertion.account
请参阅
GetCallerIdentity()
文档,以查看您可以引用的 AWS 令牌特性列表。 请注意,AWS 文档中的特性使用驼峰式大小写,而特性映射使用小写;例如,Account
变为assertion.account
。对于更复杂的断言,您可以使用通用表达式语言。例如:
attribute.environment=assertion.arn.contains(":instance-profile/Production") ? "prod" : "test"
如需在表达式中引用特性的特定部分,请使用 CEL
extract()
函数,该函数会根据您提供的模板从特性中提取值。如需详细了解extract()
,请参阅从特性中提取值。如需检查凭据是否包含特性,请使用
has()
函数。指定主帐号必须提供的特性的条件。该条件可以应用于外部凭据和 Google 凭据。任何不符合该条件的请求都会被拒绝。
条件的格式为返回布尔值的 CEL 表达式。例如,以下代码会拒绝来自没有特定 AWS 角色的任何身份的请求:
attribute.aws_role == "role-mapping"
如需详细了解条件的常见用例,请参阅工作负载身份联合概览。
以下示例演示了如何将 AWS 添加为身份提供商:
gcloud
执行 gcloud beta iam workload-identity-pools providers create-aws
命令可将 AWS 添加为身份提供商:
gcloud beta iam workload-identity-pools providers create-aws provider-id \ --workload-identity-pool="pool-id" --account-id="aws-account-id" --location="global"
响应如下所示:
Created workload identity pool provider [provider-id].
REST
projects.locations.workloadIdentityPools.providers.create
方法可将 AWS 添加为提供商。
HTTP 方法和网址:
POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools/pool-id/providers?workloadIdentityPoolProviderId=provider-id
请求 JSON 正文:
{ "aws": { "accountId": "aws-account-id" } }
如需发送您的请求,请展开以下选项之一:
该方法会返回长时间运行的 Operation
,类似于以下内容:
{ "name": "projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id/operations/operation-id" }
授予模拟服务帐号的权限
外部身份无法直接访问大多数 Google Cloud 资源。而是让这些身份为服务帐号授予 Workload Identity User 角色 (roles/iam.workloadIdentityUser
) 来模拟服务帐号。
如需为 AWS 角色添加此绑定,请使用以下格式:
attribute.aws_role/arn:aws:sts::aws-account-id:assumed-role/aws-role-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.aws_role/arn:aws:sts::aws-account-id:assumed-role/aws-role-name"
如需为 AWS 用户添加此绑定,请使用以下格式:
subject/arn:aws:sts::aws-account-id:assumed-role/aws-role-name/aws-session-name
如需了解如何从 AWS ARN 提取 AWS 角色会话,请参阅有关 IAM 标识符的 AWS 文档。
以下示例演示了如何为 AWS 用户添加绑定:
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/arn:aws:sts::aws-account-id:assumed-role/aws-role-name/aws-session-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/arn:aws:sts::aws-account-id:aws-role-name"
如需撤消访问权限,请将 add-iam-policy-binding
替换为 remove-iam-policy-binding
。
您还可以使用 REST API 或客户端库添加或撤消绑定。如需了解详情,请参阅授予、更改和撤消对资源的访问权限。
将 GetCallerIdentity 令牌交换为 Google 令牌
一旦 AWS 角色或用户能够模拟服务帐号,您就可以将其 AWS 凭据交换为 Google 凭据。
在交换过程中,您需要将 GetCallerIdentity
令牌传递给 Security Token Service。GetCallerIdentity
令牌包含您通常应在 AWS GetCallerIdentity()
方法的请求中包含的信息,以及一般针对请求生成的签名。Google Cloud 使用 GetCallerIdentity
令牌来验证 AWS 主帐号的身份,并确认主帐号是否有权模拟服务帐号。
如需交换凭据,请执行以下操作:
创建
GetCallerIdentity
令牌该令牌包含向 AWSGetCallerIdentity()
方法发出的请求的信息,以及请求信息的 AWS 签名。使用签名版本 4。该请求包含以下字段:
url
:GetCallerIdentity()
的 AWS STS 端点的网址,例如https://sts.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15
。地区端点也受支持。method
:HTTP 请求方法:POST
。headers
:HTTP 请求标头,其中必须包含以下内容:Authorization
:请求签名。host
:url
字段的主机名,例如sts.amazonaws.com
。x-amz-date
:您将发送请求的时间,格式为 ISO 8601 Basic 字符串。此值通常设置为当前时间,并可帮助防止重放攻击。x-goog-cloud-target-resource
:身份提供商的完整资源名称。例如:
//iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
x-amz-security-token
:仅在使用临时安全凭据时才需要。要包含的 AWS 会话令牌。
GetCallerIdentity
令牌类似于以下内容:{ "url": "https://sts.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15", "method": "POST", "headers": [ { "key": "Authorization", "value" : "AWS4-HMAC-SHA256 Credential=AKIASOZTBDV4D7ABCDEDF/20200228/us-east-1/sts/aws4_request, SignedHeaders=host;x-amz-date,Signature=abcedefdfedfd" }, { "key": "host", "value": "sts.amazonaws.com" }, { "key": "x-amz-date", "value": "20200228T225005Z" }, { "key": "x-goog-cloud-target-resource", "value": "//iam.googleapis.com/projects/12345678/locations/global/workloadIdentityPools/my-pool/providers/my-aws-provider" }, { "key": "x-amz-security-token", "value": "GizFWJTqYX...xJ55YoJ8E9HNU=" } ] }
如需将 AWS 凭据交换为联合访问令牌,请将
GetCallerIdentity
令牌传递给 Security Token Service 的token()
方法:REST
token
方法可将第三方令牌交换为 Google 令牌。在使用下面的请求数据之前,请先进行以下替换:
project-number
:您的 Google Cloud 项目编号。pool-id
:您在本教程前面创建的工作负载身份池的 ID。-
provider-id
:您在本教程前面配置的 AWS 身份提供商的 ID。 -
aws-request
:GetCallerIdentity
令牌,格式为网址转义的 JSON。
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:aws:token-type:aws4_request", "subjectToken": "aws-request" }
如需发送您的请求,请展开以下选项之一:
该方法会返回联合令牌。
要将联合令牌交换为服务帐号的访问令牌,请调用
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 access-token
该请求会以服务帐号的身份获得授权。