配置使用 AWS 或 Azure 的工作负载身份联合

本指南介绍了如何使用工作负载身份联合,让 AWS 和 Azure 工作负载无需服务账号密钥即可向 Google Cloud 进行身份验证。

借助工作负载身份联合,在 AWS EC2 和 Azure 上运行的工作负载可以将其特定于环境的凭据交换为短期有效的 Google Cloud Security Token Service 令牌。

特定于环境的凭据包括:

  • AWS EC2 实例可以使用实例配置文件来请求临时凭据
  • Azure 虚拟机可以使用托管式身份来获取 Azure 访问令牌。

通过设置工作负载身份联合,您可以让这些工作负载将特定于环境的凭据交换为短期有效的 Google Cloud 凭据。工作负载可以使用这些短期有效的凭据访问 Google Cloud API。

准备工作

  • 设置身份验证。

    Select the tab for how you plan to use the samples on this page:

    Console

    When you use the Google Cloud console to access Google Cloud services and APIs, you don't need to set up authentication.

    gcloud

    In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

    Python

    如需在本地开发环境中使用本页面上的 Python 示例,请安装并初始化 gcloud CLI,然后使用您的用户凭据设置应用默认凭据。

    1. Install the Google Cloud CLI.
    2. To initialize the gcloud CLI, run the following command:

      gcloud init
    3. If you're using a local shell, then create local authentication credentials for your user account:

      gcloud auth application-default login

      You don't need to do this if you're using Cloud Shell.

    如需了解详情,请参阅 Google Cloud 身份验证文档中的为本地开发环境设置身份验证

准备外部身份提供方

您只需为每个 Microsoft Entra ID 租户或 AWS 账号执行一次这些步骤。

AWS

您无需在 AWS 账号中更改任何配置。

将工作负载身份池配置为信任您的 AWS 账号后,您可以让 AWS 用户AWS 角色使用永久性或临时 AWS 安全凭据来获取短期有效的 Google Cloud 凭据。

Azure

您必须在 Microsoft Entra ID 租户中创建新的 Microsoft Entra ID 应用并对其进行配置,以便将其用于工作负载身份联合。

将工作负载身份池配置为信任应用后,Azure 用户和服务主账号可以请求此应用的访问令牌,并将这些访问令牌交换为短期有效的 Google Cloud 凭据。

如需创建应用,请执行以下操作:

  1. 创建 Microsoft Entra ID 应用和服务主账号

  2. 设置应用的 应用 ID URI。 您可以使用默认应用 ID URI (APPID) 或指定自定义 URI。

    稍后配置工作负载身份池提供方时,您需要应用 ID URI。

如需让应用获取 Microsoft Entra ID 应用的访问令牌,您可以使用受控身份

  1. 创建代管式身份。记下托管身份的对象 ID。稍后您在配置模拟时需要用到它。

  2. 将托管式身份分配到运行应用的虚拟机或其他资源。

配置工作负载身份联合

您只需为每个 AWS 账号或 Microsoft Entra ID 租户执行一次这些步骤。然后,您可以为多个工作负载以及多个 Google Cloud 项目使用相同的工作负载身份池和提供方。

如需开始配置工作负载身份联合,请执行以下操作:

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. 最好使用专用项目来管理工作负载身份池和提供方
  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the IAM, Resource Manager, Service Account Credentials, and Security Token Service APIs.

    Enable the APIs

定义特性映射和条件

AWS 或 Azure 工作负载的特定于环境的凭据包含多个特性,您必须决定要在 Google Cloud 中用作主体标识符 (google.subject) 的特性。

Google Cloud 在 Cloud Audit Logs 和主账号标识符中使用主体标识符来唯一标识 AWS 或 Azure 用户或角色。

您也可以视需要映射其他特性。然后,您可以在授予对资源的访问权限时引用这些附加特性。

AWS

您的属性映射可以使用 GetCallerIdentity 的响应字段作为来源属性。这些字段包括:

  • account:AWS 账号。
  • arn:包含外部实体的 AWS ARN。
  • userid:调用实体的唯一标识符。

如果您的应用在附加角色的 Amazon Elastic Compute Cloud (EC2) 实例上运行,您可以使用以下特性映射:

google.subject=assertion.arn
attribute.account=assertion.account
attribute.aws_role=assertion.arn.extract('assumed-role/{role}/')
attribute.aws_ec2_instance=assertion.arn.extract('assumed-role/{role_and_session}').extract('/{session}')

映射会执行以下操作:

  • 使用 ARN 作为主体标识符,例如:"arn:aws:sts::000000000000:assumed-role/ec2-my-role/i-00000000000000000
  • 引入自定义属性 account 并为其分配 AWS 账号 ID
  • 引入自定义属性 aws_role 并为其分配 AWS 角色名称,例如:ec2-my-role
  • 引入自定义属性 aws_ec2_instance 并为其分配 EC2 实例 ID,例如:i-00000000000000000

使用此映射时,您可向以下对象授予访问权限:

  • 特定的 EC2 实例:

    principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.aws_ec2_instance/EC2_INSTANCE_ID
    

  • 一个角色中的所有用户和实例:

    principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.aws_role/ROLE_NAME
    

Azure

您的特性映射可以使用嵌入在 Azure 访问令牌中的声明(包括自定义声明)作为来源特性。 在大多数情况下,最好使用 sub 声明作为主体标识符:

google.subject=assertion.sub

对于发布到代管式身份的访问令牌,sub 声明包含代管式身份的对象 ID。如果您使用其他声明,请确保该声明是唯一的,并且无法重新分配。

如果您不确定可以引用的声明列表,请执行以下操作:

  1. 连接到具有已分配的代管式身份的 Azure 虚拟机。

  2. Azure Instance Metadata Service (IMDS) 获取访问令牌:

    Bash

    curl \
      "http://169.254.169.254/metadata/identity/oauth2/token?resource=APP_ID_URI&api-version=2018-02-01" \
      -H "Metadata: true" | jq -r .access_token
    

    此命令使用 jq 工具jq 默认在 Cloud Shell 中可用。

    PowerShell

    $SubjectTokenType = "urn:ietf:params:oauth:token-type:jwt"
    $SubjectToken = (Invoke-RestMethod `
      -Uri "http://169.254.169.254/metadata/identity/oauth2/token?resource=APP_ID_URI&api-version=2018-02-01" `
      -Headers @{Metadata="true"}).access_token
    Write-Host $SubjectToken
    

    APP_ID_URI 替换为您已为工作负载身份联合配置的应用的应用 ID URI

  3. 在网络浏览器中,访问 https://jwt.ms/ 并将访问令牌粘贴到字段中。

  4. 点击声明查看嵌入在访问令牌中的声明列表。

对于服务身份,通常不需要为 google.groups 或任何自定义特性创建映射。

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

AWS

您可以使用属性条件来限制哪些 IAM 用户和角色可以使用工作负载身份联合获取短期有效的 Google Cloud 令牌。

例如,以下条件将仅限 AWS 角色可以访问,不允许其他 IAM 标识符

assertion.arn.startsWith('arn:aws:sts::AWS_ACCOUNT_ID:assumed-role/')

Azure

您可以使用属性条件来限制哪些用户和服务主账号可以使用工作负载身份联合获取短期有效的 Google Cloud 令牌。或者,您也可以将 Microsoft Entra ID 应用配置为使用应用角色分配

创建工作负载身份池和提供方

所需的角色

如需获得配置工作负载身份联合所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:

如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

此外,IAM Owner (roles/owner) 基本角色还具有配置身份联合的权限。您不应在生产环境中授予基本角色,但可以在开发或测试环境中授予这些角色。

现在,您已经收集了创建工作负载身份池和提供方所需的全部信息:

控制台

  1. 在 Google Cloud 控制台中,前往新建工作负载提供方和池页面。

    转到“新建工作负载提供方和池”

  2. 创建身份池部分中,输入以下内容:

    • 名称:池的名称。该名称还用作池 ID。池 ID 创建后便无法更改。
    • 说明:描述池用途的文本。
  3. 点击继续

  4. 配置提供方设置:

    AWS

    配置以下提供方设置:

    • 选择提供方AWS
    • 提供方名称:提供方的名称。该名称还用作提供方 ID。提供方 ID 创建后便无法更改。

    Azure

    配置以下提供方设置:

    • 选择提供方OpenID Connect (OIDC)
    • 提供方名称:提供方的名称。该名称还用作提供方 ID。提供方 ID 创建后便无法更改。
    • 颁发者 URLhttps://sts.windows.net/TENANT_ID。 将 TENANT_ID 替换为 Microsoft Entra ID 租户的租户 ID (GUID)。
    • 允许的目标设备:您在 Microsoft Entra ID 中注册应用时使用的应用 ID URI
  5. 点击继续

  6. 配置提供方特性部分中,添加您之前识别的特性映射

  7. 特性条件部分中,输入您之前确定的特性条件。如果您没有特性条件,请将该字段留空。

  8. 点击保存以创建工作负载身份池和提供方。

gcloud

  1. 创建新的工作负载身份池:

    gcloud iam workload-identity-pools create POOL_ID \
        --location="global" \
        --description="DESCRIPTION" \
        --display-name="DISPLAY_NAME"
    

    请替换以下内容:

    • POOL_ID:池的唯一 ID。
    • DISPLAY_NAME:池的名称。
    • DESCRIPTION:池的说明。授予对池身份的访问权限时,系统会显示此说明。
  2. 添加工作负载身份池提供商:

    AWS

    如需为 AWS 创建工作负载身份池提供方,请执行以下命令:

    gcloud iam workload-identity-pools providers create-aws PROVIDER_ID \
      --location="global" \
      --workload-identity-pool="POOL_ID" \
      --account-id="ACCOUNT_ID" \
      --attribute-mapping="MAPPINGS" \
      --attribute-condition="CONDITIONS"
    

    请替换以下内容:

    示例:

    gcloud iam workload-identity-pools providers create-aws example-provider \
      --location="global" \
      --workload-identity-pool="pool-1" \
      --account-id="123456789000" \
      --attribute-mapping="google.subject=assertion.arn"

    Azure

    如需为 Azure 创建工作负载身份池提供方,请执行以下命令:

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="ISSUER_URI" \
        --allowed-audiences="APPLICATION_ID_URI" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS"
    

    替换以下内容:

    • PROVIDER_ID:提供方的唯一 ID。
    • POOL_ID:池的 ID。
    • ISSUER_URI:Microsoft Entra ID 租户的租户 ID (GUID),有时格式设置为 https://sts.windows.net/TENANT_ID。颁发者 URI 可能有所不同,如需查找颁发者 URI,您可以使用 JWT.io 调试 JWT。
    • APPLICATION_ID_URI:您在 Microsoft Entra ID 中注册应用时使用的应用 ID URI
    • MAPPINGS:您之前确定的以英文逗号分隔的属性映射列表。
    • CONDITIONS:(可选)您之前确定的属性条件

    示例:

    gcloud iam workload-identity-pools providers create-oidc example-provider \
        --location="global" \
        --workload-identity-pool="pool-1" \
        --issuer-uri="https://sts.windows.net/00000000-1111-2222-3333-444444444444" \
        --allowed-audiences="api://my-app" \
        --attribute-mapping="google.subject=assertion.sub,google.groups=assertion.groups"

对工作负载进行身份验证

您必须为每个工作负载执行一次这些步骤。

允许外部工作负载访问 Google Cloud 资源

为了向您的工作负载提供对 Google Cloud 资源的访问权限,我们建议您向该主账号授予直接资源访问权限。在本例中,主账号是联合身份用户。某些 Google Cloud 产品存在 Google Cloud API 限制。如果您的工作负载调用存在限制的 API 端点,您可以改用服务账号模拟。在这种情况下,主账号是 Google Cloud 服务账号,它充当身份。您可以向此服务账号授予资源的访问权限。

直接资源访问权限

您可以使用 Google Cloud 控制台或 gcloud CLI 向联合身份授予直接对资源的访问权限。

控制台

如需使用 Google Cloud 控制台授予直接对某个资源的 IAM 角色,您必须进入该资源的页面,然后授予该角色。以下示例展示了如何进入 Cloud Storage 页面,然后向联合身份授予直接对 Cloud Storage 存储桶的 Storage Object Viewer (roles/storage.objectViewer) 角色。

  1. 在 Google Cloud 控制台中,进入 Cloud Storage 存储桶页面。

    进入“存储桶”

  2. 在存储桶列表中,点击您要针对其授予角色的存储桶的名称。

  3. 选择页面顶部附近的权限标签。

  4. 点击 授予访问权限按钮。

    系统会显示“添加主账号”对话框。

  5. 新主账号字段中,输入需要访问您存储桶的一个或多个身份。

    按主体

    principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT
    

    替换以下内容:

    • PROJECT_NUMBER:项目编号
    • POOL_ID:工作负载池 ID
    • SUBJECT:从您的 IdP 映射的单个主体,例如 administrator@example.com

    按群组

    principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/group/GROUP
    

    替换以下内容:

    • PROJECT_NUMBER:项目编号
    • WORKLOAD_POOL_ID:工作负载池 ID
    • GROUP:从您的 IdP 映射的群组,例如:administrator-group@example.com

    按特性

    principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.ATTRIBUTE_NAME/ATTRIBUTE_VALUE
    

    替换以下内容:

    • PROJECT_NUMBER:项目编号
    • WORKLOAD_POOL_ID:工作负载池 ID
    • ATTRIBUTE_NAME:从您的 IdP 映射的属性之一
    • ATTRIBUTE_VALUE:属性的值
  6. 选择角色下拉菜单中选择一个或多个角色。 您选择的角色将显示在窗格中,其中包含对角色授予的权限的简短说明。

  7. 点击保存

gcloud

如需使用 gcloud CLI 针对项目中的资源授予 IAM 角色,请执行以下操作:

  1. 获取定义资源的项目的编号。

    gcloud projects describe $(gcloud config get-value core/project) --format=value\(projectNumber\)
    
  2. 授予对资源的访问权限。

    如需使用 gcloud CLI 向符合特定条件的外部身份授予 Storage Object Viewer 角色 (roles/storage.objectViewer),请运行以下命令。

    按主体

    gcloud storage buckets add-iam-policy-binding BUCKET_ID \
        --role=roles/storage.objectViewer \
        --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT"

    按群组

    gcloud storage buckets add-iam-policy-binding BUCKET_ID \
        --role=roles/storage.objectViewer \
        --member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/group/GROUP"

    按属性

    gcloud storage buckets add-iam-policy-binding BUCKET_ID \
        --role=roles/storage.objectViewer \
        --member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.ATTRIBUTE_NAME/ATTRIBUTE_VALUE"

    替换以下内容:

    • BUCKET_ID:要针对其授予访问权限的存储桶
    • PROJECT_NUMBER:包含工作负载身份池的项目的编号
    • POOL_ID:工作负载身份池的池 ID
    • SUBJECT已映射google.subject 的特性的预期值
    • GROUP已映射google.groups 的特性的预期值
    • ATTRIBUTE_NAME特性映射中的自定义特性的名称
    • ATTRIBUTE_VALUE:属性映射中的自定义属性的值

    您可以向支持 IAM 允许政策的任何 Google Cloud 资源授予角色。

服务账号模拟

  1. 如需为外部工作负载创建服务账号,请执行以下操作:

    1. Enable the IAM, Security Token Service, and Service Account Credentials APIs.

      Enable the APIs

    2. 创建一个服务账号以代表工作负载。我们建议您为每个工作负载使用专用服务账号。该服务账号不需要与工作负载身份池位于同一项目中,但您必须引用包含该服务账号的项目。

    3. 向服务账号授予对您希望外部身份访问的资源的访问权限

    4. 向服务账号授予 Workload Identity User 角色 (roles/iam.workloadIdentityUser)。

  2. 如需使用 Google Cloud 控制台或 gcloud CLI 通过服务账号模拟向联合身份授予访问权限,请执行以下操作:

控制台

如需使用 Google Cloud 控制台向具有服务账号的联合身份授予 IAM 角色,请执行以下操作:

同一项目中的服务账号

  1. 如需使用服务账号模拟为同一项目中的服务账号授予访问权限,请执行以下操作:

    1. 进入工作负载身份池页面。

      转到“工作负载身份池”

    2. 选择授予访问权限

    3. 向服务账号授予访问权限对话框中,选择使用服务账号模拟授予访问权限

    4. 服务账号列表中,选择要模拟的外部身份的服务账号,然后执行以下操作:

    5. 如需选择池中的哪些身份可以模拟服务账号,请执行以下操作之一:

      • 如需仅允许工作负载身份池的特定身份模拟服务账号,请选择仅限与过滤条件匹配的身份

      • 属性名称列表中,选择您要作为过滤依据的属性。

      • 属性值字段中,输入属性的预期值;例如,如果您使用属性映射 google.subject=assertion.sub,请将属性名称设置为 subject,并将属性值设置为外部身份提供方颁发的令牌中 sub 声明的值。

    6. 如需保存配置,请点击保存,然后点击关闭

另一个项目中的服务账号

  1. 如需向其他项目中的服务账号授予使用服务账号模拟的访问权限,请执行以下操作:

    1. 转到服务账号页面。

      转到“服务账号”

    2. 选择要模拟的服务账号。

    3. 点击管理访问权限

    4. 点击添加主账号

    5. 新主账号字段中,为要模拟服务账号的池中的身份输入以下主账号标识符之一。

      按主体

      principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT
      

      替换以下内容:

      • PROJECT_NUMBER:项目编号
      • POOL_ID:工作负载池 ID
      • SUBJECT:从您的 IdP 映射的单个主体,例如 administrator@example.com

      按群组

      principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/group/GROUP
      

      替换以下内容:

      • PROJECT_NUMBER:项目编号
      • WORKLOAD_POOL_ID:工作负载池 ID
      • GROUP:从您的 IdP 映射的群组,例如:administrator-group@example.com

      按特性

      principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.ATTRIBUTE_NAME/ATTRIBUTE_VALUE
      

      替换以下内容:

      • PROJECT_NUMBER:项目编号
      • WORKLOAD_POOL_ID:工作负载池 ID
      • ATTRIBUTE_NAME:从您的 IdP 映射的属性之一
      • ATTRIBUTE_VALUE:属性的值

      按池

      <principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*
      

      替换以下内容:

      • PROJECT_NUMBER:项目编号
      • WORKLOAD_POOL_ID:工作负载池 ID
    6. 选择角色中,选择 Workload Identity User 角色 (roles/iam.workloadIdentityUser)。

    7. 如需保存配置,请点击保存

gcloud

如需使用 gcloud CLI 向符合特定条件的外部身份授予 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/SUBJECT"

按群组

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/GROUP"

按属性

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.ATTRIBUTE_NAME/ATTRIBUTE_VALUE"

替换以下内容:

  • SERVICE_ACCOUNT_EMAIL:服务账号的电子邮件地址
  • PROJECT_NUMBER:包含工作负载身份池的项目的编号
  • POOL_ID:工作负载身份池的池 ID
  • SUBJECT已映射google.subject 的特性的预期值
  • GROUP已映射google.groups 的特性的预期值
  • ATTRIBUTE_NAME特性映射中的自定义特性的名称
  • ATTRIBUTE_VALUE:属性映射中的自定义属性的值

下载或创建凭据配置

Cloud 客户端库、gcloud CLI 和 Terraform 可以自动获取外部凭据,并使用这些凭据来模拟服务账号。为了让库和工具完成此过程,您必须提供凭据配置文件。此文件定义以下内容:

  • 从何处获取外部凭据
  • 要使用的工作负载身份池和提供商
  • 需要模拟的服务账号

如需创建凭据配置文件,请执行以下操作:

控制台

如需在 Google Cloud 控制台中下载凭据配置文件,请执行以下操作:

  1. 在 Google Cloud 控制台中,进入工作负载身份池页面。

    转到“工作负载身份池”

  2. 找到您要使用的 IdP 的工作负载身份池,然后点击它。

  3. 如果您选择使用直接资源访问权限,请执行以下操作:

    1. 点击授予访问权限

    2. 选择使用联合身份授予访问权限(推荐)

    3. 点击下载

    4. 在此过程后面,继续按照配置您的应用对话框的说明操作。

  4. 如果您选择使用服务账号模拟,请执行以下操作:

    1. 选择关联的服务账号

    2. 找到您要使用的服务账号,然后点击 下载

    3. 在此过程后面,继续按照配置您的应用对话框的说明操作。

  5. 配置您的应用对话框中,选择包含外部身份的提供方。

  6. 请提供以下额外设置:

    AWS

    无需进行其他设置。

    Azure

    应用 ID 网址:Azure 应用的应用 ID URI

  7. 选择 下载配置以下载凭据配置文件,然后点击关闭

gcloud

如需使用 gcloud iam workload-identity-pools create-cred-config 创建凭据配置文件,请执行以下操作:

AWS

如需创建允许库从 EC2 实例元数据中获取访问令牌的凭据库,请执行以下操作:

gcloud iam workload-identity-pools create-cred-config \
    projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \
    --service-account=SERVICE_ACCOUNT_EMAIL \
    --service-account-token-lifetime-seconds=SERVICE_ACCOUNT_TOKEN_LIFETIME \
    --aws \
    --output-file=FILEPATH.json

替换以下内容:

  • PROJECT_NUMBER:包含工作负载身份池的项目的编号
  • POOL_ID:工作负载身份池的 ID。
  • PROVIDER_ID:工作负载身份池提供方的 ID。
  • SERVICE_ACCOUNT_EMAIL:如果您使用服务账号模拟,请替换为服务账号的电子邮件地址。如果您不使用服务账号模拟,请忽略此标志。
  • SERVICE_ACCOUNT_TOKEN_LIFETIME:如果您使用服务账号模拟,请替换为服务账号访问令牌的生命周期(以秒为单位);如果未提供,则默认为一小时。如果您不使用服务账号模拟,请忽略此标志。如需指定超过一小时的生命周期,您必须配置 constraints/iam.allowServiceAccountCredentialLifetimeExtension 组织政策限制条件
  • FILEPATH:用于保存配置的文件。

如果您使用的是 AWS IMDSv2,则需要向 gcloud iam workload-identity-pools create-cred-config 命令添加一个额外的标志 --enable-imdsv2

gcloud iam workload-identity-pools create-cred-config \
    projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \
    --service-account=SERVICE_ACCOUNT_EMAIL \
    --aws \
    --enable-imdsv2 \
    --output-file=FILEPATH.json

如果无法选择使用 AWS 元数据服务器,您可以通过以下 AWS 环境变量提供 AWS 安全凭据:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_REGIONAWS_DEFAULT_REGION
  • 可选:AWS_SESSION_TOKEN

gcloud CLI 和库会在 AWS 元数据服务器不可用时使用这些 AWS 环境变量。

Azure

创建凭据配置文件,让库从 Azure Instance Metadata Service (IMDS) 获取访问令牌:

gcloud iam workload-identity-pools create-cred-config \
    projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \
    --service-account=SERVICE_ACCOUNT_EMAIL \
    --service-account-token-lifetime-seconds=SERVICE_ACCOUNT_TOKEN_LIFETIME \
    --azure \
    --app-id-uri APPLICATION_ID_URI \
    --output-file=FILEPATH.json

替换以下内容:

  • PROJECT_NUMBER:包含工作负载身份池的项目的编号。
  • POOL_ID:工作负载身份池的 ID。
  • PROVIDER_ID:工作负载身份池提供方的 ID。
  • SERVICE_ACCOUNT_EMAIL:如果您使用服务账号模拟,请替换为服务账号的电子邮件地址。如果您不使用服务账号模拟,请忽略此标志。
  • APPLICATION_ID_URI:Azure 应用的应用 ID URI。
  • SERVICE_ACCOUNT_TOKEN_LIFETIME:如果您使用服务账号模拟,请替换为服务账号访问令牌的生命周期(以秒为单位);如果未提供,则默认为一小时。如果您不使用服务账号模拟,请忽略此标志。如需指定超过一小时的生命周期,您必须配置 constraints/iam.allowServiceAccountCredentialLifetimeExtension 组织政策限制条件
  • FILEPATH:用于保存配置的文件。

使用凭据配置访问 Google Cloud

如需使工具和客户端库使用您的凭据配置,请在 AWS 或 Azure 环境中执行以下操作:

  1. 初始化环境变量 GOOGLE_APPLICATION_CREDENTIALS 并将其指向凭据配置文件:

    Bash

      export GOOGLE_APPLICATION_CREDENTIALS=`pwd`/FILEPATH.json
      
    其中,FILEPATH 是凭据配置文件的相对路径。

    PowerShell

      $env:GOOGLE_APPLICATION_CREDENTIALS = Resolve-Path 'FILEPATH.json'
      
    其中,FILEPATH 是凭据配置文件的相对路径。
  2. 使用支持工作负载身份联合并且可以自动查找凭据的客户端库或工具:

    C++

    v2.6.0 版开始,C++ 版 Google Cloud 客户端库支持工作负载身份联合。如需使用工作负载身份联合,您必须使用 1.36.0 版或更高版本的 gRPC 构建客户端库。

    Go

    如果 Go 客户端库使用 golang.org/x/oauth2 模块的 v0.0.0-20210218202405-ba52d332ba99 版本或更高版本,则客户端库支持工作负载身份联合。

    如要查看客户端库使用的模块版本,请运行以下命令:

    cd $GOPATH/src/cloud.google.com/go
    go list -m golang.org/x/oauth2
    

    Java

    如果 Java 客户端库使用 com.google.auth:google-auth-library-oauth2-http 工件的 0.24.0 版或更高版本,则客户端支持工作负载身份联合。

    如需查看该客户端库使用的工件版本,请在应用目录中运行以下 Maven 命令:

    mvn dependency:list -DincludeArtifactIds=google-auth-library-oauth2-http
    

    Node.js

    如果 Node.js 版客户端库使用 7.0.2 版或更高版本的 google-auth-library 软件包,则该客户端库支持工作负载身份联合。

    如要查看客户端库使用的软件包版本,请在应用目录中运行以下命令:

    npm list google-auth-library
    

    创建 GoogleAuth 对象时,您可以指定项目 ID,也可以允许 GoogleAuth 自动查找项目 ID。如要自动查找项目 ID,配置文件中的服务账号必须具有项目的 Browser 角色 (roles/browser) 或具有同等权限的角色。如需了解详情,请参阅 google-auth-library 软件包的 README

    Python

    如果 Python 客户端库使用 google-auth 软件包的 1.27.0 版本或更高版本,则客户端支持工作负载身份联合。

    如要检查客户端库使用的软件包版本,请在已安装该软件包的环境中运行以下命令:

    pip show google-auth
    

    如要为身份验证客户端指定项目 ID,您可以设置 GOOGLE_CLOUD_PROJECT 环境变量,也可以允许客户端自动查找项目 ID。如要自动查找项目 ID,配置文件中的服务账号必须具有项目的 Browser 角色 (roles/browser) 或具有同等权限的角色。如需了解详情,请参阅 google-auth 软件包用户指南

    gcloud

    如需使用工作负载身份联合进行身份验证,请使用 gcloud auth login 命令:

    gcloud auth login --cred-file=FILEPATH.json
    

    FILEPATH 替换为凭据配置文件的路径。

    版本 363.0.0 及更高版本的 gcloud CLI 支持 gcloud CLI 中的工作负载身份联合。

    Terraform

    如果您使用 3.61.0 版或更高版本,则 Google Cloud 提供方支持工作负载身份联合:

    terraform {
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = "~> 3.61.0"
        }
      }
    }
    

    bq

    如需使用工作负载身份联合进行身份验证,请使用 gcloud auth login 命令,如下所示:

    gcloud auth login --cred-file=FILEPATH.json
    

    FILEPATH 替换为凭据配置文件的路径。

    390.0.0 版及更高版本的 gcloud CLI 支持 bq 中的工作负载身份联合。

    如果您无法使用支持工作负载身份联合的客户端库,则可以使用 REST API 以程序化方式进行身份验证

高级场景

使用 REST API 对工作负载进行身份验证

如果您无法使用客户端库,可以按照以下步骤让外部工作负载使用 REST API 获取短期有效的访问令牌:

  1. 从外部 IdP 获取凭据:

    AWS

    创建一个 JSON 文档,其中包含您通常在向 AWS GetCallerIdentity() 端点发出的请求中包含的信息,包括有效的请求签名

    工作负载身份联合将此 JSON 文档称为 GetCallerIdentity 令牌。该令牌可让工作负载身份联合验证身份,而无需显示 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="
        }
      ]
    }
    

    该令牌包含以下字段:

    • urlGetCallerIdentity() 的 AWS STS 端点的网址,附加一个标准 GetCallerIdentity() 请求正文作为查询参数。例如:https://sts.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15。我们建议您使用区域级 STS 端点并为工作负载设计可靠的基础设施。 如需了解详情,请参阅区域级 AWS STS 端点
    • method:HTTP 请求方法:POST
    • headers:HTTP 请求标头,其中必须包含以下内容:
      • Authorization:请求签名。
      • hosturl 字段的主机名,例如 sts.amazonaws.com
      • x-amz-date:您将发送请求的时间,格式为 ISO 8601 Basic 字符串。此值通常设置为当前时间,可帮助防止重放攻击。
      • x-goog-cloud-target-resource:身份提供方的完整资源名称,不含 https: 前缀。例如:
        //iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID
        
      • x-amz-security-token:会话令牌。仅在使用临时安全凭据时才需要。

    以下示例会创建一个网址编码的 GetCallerIdentity 令牌。提取网址编码令牌以备后用。此外,它专门为您的参考创建了一个人类可读的令牌:

    import json
    import urllib
    
    import boto3
    from botocore.auth import SigV4Auth
    from botocore.awsrequest import AWSRequest
    
    
    def create_token_aws(project_number: str, pool_id: str, provider_id: str) -> None:
        # Prepare a GetCallerIdentity request.
        request = AWSRequest(
            method="POST",
            url="https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15",
            headers={
                "Host": "sts.amazonaws.com",
                "x-goog-cloud-target-resource": f"//iam.googleapis.com/projects/{project_number}/locations/global/workloadIdentityPools/{pool_id}/providers/{provider_id}",
            },
        )
    
        # Set the session credentials and Sign the request.
        # get_credentials loads the required credentials as environment variables.
        # Refer:
        # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html
        SigV4Auth(boto3.Session().get_credentials(), "sts", "us-east-1").add_auth(request)
    
        # Create token from signed request.
        token = {"url": request.url, "method": request.method, "headers": []}
        for key, value in request.headers.items():
            token["headers"].append({"key": key, "value": value})
    
        # The token lets workload identity federation verify the identity without revealing the AWS secret access key.
        print("Token:\n%s" % json.dumps(token, indent=2, sort_keys=True))
        print("URL encoded token:\n%s" % urllib.parse.quote(json.dumps(token)))
    
    
    def main() -> None:
        # TODO(Developer): Replace the below credentials.
        # project_number: Google Project number (not the project id)
        project_number = "my-project-number"
        pool_id = "my-pool-id"
        provider_id = "my-provider-id"
    
        create_token_aws(project_number, pool_id, provider_id)
    
    
    if __name__ == "__main__":
        main()

    初始化以下变量:

    Bash

    SUBJECT_TOKEN_TYPE="urn:ietf:params:aws:token-type:aws4_request"
    SUBJECT_TOKEN=TOKEN
    

    PowerShell

    $SubjectTokenType = "urn:ietf:params:aws:token-type:aws4_request"
    $SubjectToken = "TOKEN"
    

    其中 TOKEN 是由脚本生成的网址编码 GetCallerIdentity 令牌。

    Azure

    连接到具有已分配的托管式身份的 Azure 虚拟机,并从 Azure Instance Metadata Service (IMDS) 获取访问令牌

    Bash

    SUBJECT_TOKEN_TYPE="urn:ietf:params:oauth:token-type:jwt"
    SUBJECT_TOKEN=$(curl \
      "http://169.254.169.254/metadata/identity/oauth2/token?resource=APP_ID_URI&api-version=2018-02-01" \
      -H "Metadata: true" | jq -r .access_token)
    echo $SUBJECT_TOKEN
    

    此命令使用 jq 工具jq 默认在 Cloud Shell 中可用。

    PowerShell

    $SubjectTokenType = "urn:ietf:params:oauth:token-type:jwt"
    $SubjectToken = (Invoke-RestMethod `
      -Uri "http://169.254.169.254/metadata/identity/oauth2/token?resource=APP_ID_URI&api-version=2018-02-01" `
      -Headers @{Metadata="true"}).access_token
    Write-Host $SubjectToken
    

    其中,APP_ID_URI 是您已为工作负载身份联合配置的应用的应用 ID URI

  2. 使用 Security Token Service API 将凭据交换为短期有效的访问令牌:

    Bash

    STS_TOKEN=$(curl https://sts.googleapis.com/v1/token \
        --data-urlencode "audience=//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID" \
        --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
        --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
        --data-urlencode "scope=https://www.googleapis.com/auth/cloud-platform" \
        --data-urlencode "subject_token_type=$SUBJECT_TOKEN_TYPE" \
        --data-urlencode "subject_token=$SUBJECT_TOKEN" | jq -r .access_token)
    echo $STS_TOKEN
    

    PowerShell

    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
    $StsToken = (Invoke-RestMethod `
        -Method POST `
        -Uri "https://sts.googleapis.com/v1/token" `
        -ContentType "application/json" `
        -Body (@{
            "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"   = $SubjectTokenType
            "subjectToken"       = $SubjectToken
        } | ConvertTo-Json)).access_token
    Write-Host $StsToken
    

    替换以下值:

    • PROJECT_NUMBER:包含工作负载身份池的项目的项目编号
    • POOL_ID:工作负载身份池的 ID
    • PROVIDER_ID:工作负载身份池提供方的 ID
  3. 如果您使用服务账号模拟,请使用 Security Token Service 中的令牌调用 IAM Service Account Credentials APIgenerateAccessToken 方法来获取访问令牌。

Cloud Run 服务的令牌

访问 Cloud Run 服务时,您必须使用 ID 令牌。

Bash

TOKEN=$(curl -0 -X POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateIdToken \
    -H "Content-Type: text/json; charset=utf-8" \
    -H "Authorization: Bearer $STS_TOKEN" \
    -d @- <<EOF | jq -r .token
    {
        "audience": "SERVICE_URL"
    }
EOF
)
echo $TOKEN

PowerShell

$Token = (Invoke-RestMethod `
    -Method POST `
    -Uri "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateIdToken" `
    -Headers @{ "Authorization" = "Bearer $StsToken" } `
    -ContentType "application/json" `
    -Body (@{
        "audience" = "SERVICE_URL"
    } | ConvertTo-Json)).token
Write-Host $Token

请替换以下内容:

  • SERVICE_ACCOUNT_EMAIL:服务账号的电子邮件地址。
  • SERVICE_URL:服务的网址,例如 https://my-service-12345-us-central1.run.app。您也可以将其设置为自定义服务端点。如需了解详情,请参阅了解自定义受众群体

适用于其他平台的令牌

访问其他服务时,您必须使用访问令牌。

Bash

TOKEN=$(curl -0 -X POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateAccessToken \
    -H "Content-Type: text/json; charset=utf-8" \
    -H "Authorization: Bearer $STS_TOKEN" \
    -d @- <<EOF | jq -r .accessToken
    {
        "scope": [ "https://www.googleapis.com/auth/cloud-platform" ]
    }
EOF
)
echo $TOKEN

PowerShell

$Token = (Invoke-RestMethod `
    -Method POST `
    -Uri "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateAccessToken" `
    -Headers @{ "Authorization" = "Bearer $StsToken" } `
    -ContentType "application/json" `
    -Body (@{
        "scope" = , "https://www.googleapis.com/auth/cloud-platform"
    } | ConvertTo-Json)).accessToken
Write-Host $Token

请替换以下内容:

  • SERVICE_ACCOUNT_EMAIL:服务账号的电子邮件地址。

后续步骤