工作负载身份联合

本文档简要介绍了外部工作负载的身份联合。借助身份联合,您可以授予本地或多云端工作负载对 Google Cloud 资源的访问权限,而无需使用服务账号密钥。

您可以将身份联合与 Amazon Web Services (AWS) 或任何支持 OpenID Connect (OIDC) 的身份提供方 (IdP) 搭配使用,例如 Microsoft Azure 或 SAML 2.0。

为何选择身份联合?

传统上,在 Google Cloud 外部运行的应用可以使用服务账号密钥来访问 Google Cloud 资源。但是,服务账号密钥是强大的凭据,如果管理不当,则可能会带来安全风险。

借助身份联合,您可以使用 Identity and Access Management (IAM) 授予外部身份 IAM 角色,包括模拟服务账号的功能。此方法可消除与服务账号密钥相关的维护和安全负担。

工作负载身份池

工作负载身份池是允许您管理外部身份的实体。

通常,我们建议为需要访问 Google Cloud 资源的每个非 Google Cloud 环境(例如开发环境、预演环境或生产环境)创建一个新池。

工作负载身份池提供方

工作负载身份提供方是描述 Google Cloud 和您的 IdP 之间关系的实体,包括:

  • AWS
  • Azure Active Directory
  • 本地 Active Directory Federation Services (AD FS)
  • Okta
  • Kubernetes 集群

工作负载身份联合遵循 OAuth 2.0 令牌交换规范。您可以将 IdP 的凭据提供给 Security Token Service,该服务会验证凭据的身份,然后返回联合令牌进行交换。

具有本地 JWK 的 OIDC 提供方

如需联合没有公共 OIDC 端点的工作负载,您可以直接将 OIDC JSON Web 密钥集 (JWKS) 上传到池中。如果您在自己的环境中托管 Terraform 或 GitHub Enterprise,或者有一些法规要求不公开公共网址,则这种做法很常见。如需了解详情,请参阅管理 OIDC JWK(可选)

特性映射

您的外部身份提供方颁发的令牌包含一个或多个特性。一些身份提供方将这些特性称为声明

Google STS 令牌还包含一个或多个特性,如下表所列:

属性 说明
google.subject 必需。用户的唯一标识符。此特性用于 IAM principal:// 角色绑定中,并显示在 Cloud Logging 日志中。 该值必须是唯一的,不能超过 127 个字符。
google.groups 可选。身份所属的一组群组。此特性在 IAM principalSet:// 角色绑定中使用,用于向群组的所有成员授予访问权限。
attribute.NAME 可选。您最多可以定义 50 个自定义特性,并在 IAM principalSet:// 角色绑定中使用这些特性,以授予对具有特定特性的所有身份的访问权限。

特性映射定义如何从外部令牌派生 Google STS 令牌特性的值。您可以为每个 Google STS 令牌特性定义一个特性映射,格式如下:

TARGET_ATTRIBUTE=SOURCE_EXPRESSION

请替换以下内容:

  • TARGET_ATTRIBUTE 是 Google STS 令牌的一个特性
  • SOURCE_EXPRESSION 是一种通用表达式语言 (CEL) 表达式,用于转换外部身份提供方颁发的令牌中的一个或多个特性

以下列表提供了特性映射示例:

  • 将断言特性 sub 分配给 google.subject

    google.subject=assertion.sub
    
  • 串联多个断言特性:

    google.subject="myprovider::" + assertion.aud + "::" + assertion.sub
    
  • 将 GUID 值的断言特性 workload_id 映射到名称,并将结果分配给名为 attribute.my_display_name 的自定义特性:

    attribute.my_display_name={
      "8bb39bdb-1cc5-4447-b7db-a19e920eb111": "Workload1",
      "55d36609-9bcf-48e0-a366-a3cf19027d2a": "Workload2"
    }[assertion.workload_id]
    
  • 使用 CEL 逻辑运算符和函数,将名为 attribute.environment 的自定义特性设置为 prodtest,具体取决于身份的 Amazon 资源名称 (ARN):

    attribute.environment=assertion.arn.contains(":instance-profile/Production") ? "prod" : "test"
    
  • 使用 extract 函数填充自定义特性 aws_role,该角色使用假设角色的名称,或者假设没有角色使用身份的 ARN。

    attribute.aws_role=assertion.arn.contains('assumed-role') ? assertion.arn.extract('{account_arn}assumed-role/') + 'assumed-role/' + assertion.arn.extract('assumed-role/{role_name}/') : assertion.arn
    
  • split 函数按指定的分隔符值拆分字符串。例如,如需通过在电子邮件地址属性中的 @ 位置处拆分其值并使用第一个字符串,来提取 username 属性,请使用以下属性映射:

    attribute.username=assertion.email.split("@")[0]
    

  • join 函数按指定的分隔符值联接字符串列表。例如,如需通过以 . 作为分隔符串联字符串列表来填充自定义属性 department,请使用以下属性映射:

    attribute.department=assertion.department.join(".")
    

对于 AWS,Google 提供了可涵盖大多数常见场景的默认映射。您还可以提供自定义映射。

对于 OIDC 提供商,您需要提供映射。如需构建映射,请参阅提供商的文档,查看其凭据的特性列表。

如需了解详情,请参阅 attributeMapping 字段的 API 文档。

特性条件

特性条件是可以检查断言特性和目标特性的 CEL 表达式。如果给定凭据的特性条件评估结果为 true,则接受凭据。否则,凭据会被拒绝。

您可以使用特性条件来限制哪些身份可以使用工作负载身份池进行身份验证。

特性条件在如下情况下非常有用:

  • 如果您的工作负载使用向公众公开的身份提供商,您可以限制访问权限,以便只有您选择的身份才能访问您的工作负载身份池。

  • 如果您将一个身份提供商用于多个云端平台,则可以防止将预期用于其他平台的凭据用于 Google Cloud,反之亦然。这有助于避免混淆代理问题

工作负载身份池提供商的特性条件可以使用 assertion 关键字,该关键字是指一个映射,该映射代表由身份提供商签发的身份验证凭据。您可以使用点表示法来访问该映射的值。例如,AWS 凭据包含 arn 值,您可以以 assertion.arn 的形式访问该值。此外,特性条件可以使用提供商的特性映射中定义的任何特性。

以下示例仅接受来自具有特定 AWS 角色的身份的请求:

attribute.aws_role == "ROLE_MAPPING"

如需了解详情,请参阅 attributeCondition 字段的 API 文档。

服务账号模拟

令牌交换流程会返回联合访问令牌。您可以使用此令牌模拟服务账号并获取短期有效的 OAuth 2.0 访问令牌。短期有效的访问令牌可让您调用服务账号有权访问的任何 Google Cloud API。

如需模拟服务账号,请向您的外部身份授予服务账号的 Workload Identity User 角色 (roles/iam.workloadIdentityUser),以及您的工作负载所需的角色。您可以向工作负载身份池中的所有身份授予角色,也可以根据身份的特性向特定外部身份授予角色。

下表介绍了授予角色的常见场景:

身份 标识符格式
单一身份 principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE
群组中的所有身份 principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/group/GROUP_ID
具有特定特性值的所有身份 principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.ATTRIBUTE_NAME/ATTRIBUTE_VALUE

后续步骤