使用部署流水线配置工作负载身份联合

本指南介绍如何使用工作负载身份联合,让部署流水线向 Google Cloud 进行身份验证。

根据您使用的 CI/CD 系统,您的部署流水线可能会访问特定于环境的环境凭据。例如:

  • GitHub Actions 工作流可以获取 GitHub OIDC 令牌以唯一标识工作流及其代码库。
  • GitLab SaaS 允许 CI/CD 作业访问唯一标识作业及其项目、环境和代码库的 ID 令牌
  • Terraform Cloud 可以向您的 Terraform 配置提供 OIDC 令牌以唯一标识工作区和环境。

您可以通过使用工作负载身份联合,将部署流水线配置为使用这些凭据向 Google Cloud 进行身份验证。此方法可消除与服务账号密钥相关的维护和安全负担。

准备工作

设置身份验证

选择标签页以了解您打算如何使用本页面上的示例:

控制台

当您使用 Google Cloud 控制台访问 Google Cloud 服务和 API 时,无需设置身份验证。

gcloud

您可以从以下任一开发环境使用本页面上的 gcloud CLI 示例:

  • Cloud Shell:如需使用已设置 gcloud CLI 的在线终端,请激活 Cloud Shell。

    Cloud Shell 会话会在页面底部启动,并显示命令行提示符。该会话可能需要几秒钟来完成初始化。

  • 本地 shell:如需在本地开发环境中使用 gcloud CLI,请安装初始化 gcloud CLI。

Python

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

  1. 安装 Google Cloud CLI。
  2. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  3. 为您的 Google 账号创建本地身份验证凭据:

    gcloud auth application-default login

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

所需的角色

如需获得配置工作负载身份联合所需的权限,请让您的管理员为您授予项目的 Workload Identity Pool Admin (roles/iam.workloadIdentityPoolAdmin) IAM 角色。如需详细了解如何授予角色,请参阅管理访问权限

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

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

准备外部 IdP

GitHub Actions

您无需在 GitHub 账号中进行任何更改。

将工作负载身份池配置为信任您的 GitHub 代码库后,您可以让该代码库中的工作流使用其 GitHub OIDC 令牌来获取短期 Google Cloud 凭据。

GitLab SaaS

您无需在 GitLab 账号中进行任何更改。

将工作负载身份池配置为信任您的 GitLab 组后,您可以为各项 CI/CD 作业启用工作负载身份联合。

Terraform Cloud

您无需在 Terraform Cloud 账号中进行任何更改配置。

将工作负载身份池配置为信任 Terraform Cloud 后,您可以为各个工作区启用工作负载身份联合。

配置工作负载身份联合

您必须为每个 GitHub 组织、GitLab 群组或 Terraform Cloud 组织执行这些步骤。

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

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 最好使用专用项目来管理工作负载身份池和提供方
  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 启用 IAM, Resource Manager, Service Account Credentials, and Security Token Service API。

    启用 API

定义属性映射

部署流水线的特定于环境的凭据可以包含多个属性,您必须决定要在 Google Cloud 中用作主体标识符 (google.subject) 的属性。

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

GitHub Actions

属性映射可以使用 GitHub Actions OIDC 令牌中的任何声明。这些令牌声明密钥及其值由 GitHub 控制。您至少应将 google.subject 映射到 assertion.sub,该属性对应于 GitHub Actions OIDC 令牌主题:

google.subject=assertion.sub

GitHub Actions OIDC 令牌主题的值可能因来源事件而异。其他声明属性可能包括:

  • repository:包含所有者和代码库名称,例如 "google/guava"

  • repository_id:包含唯一代码库 ID,例如 "20300177"

  • repository_owner:包含所有者,可以是用户名或 GitHub 组织的名称,例如 "google"

  • repository_owner_id:包含唯一所有者 ID,例如 "1342004"

上述列表是部分可能的声明;如需查看完整列表,请参阅 GitHub 文档中有关示例声明的部分。请务必映射您计划用作属性条件或用作未来 principalSet 条件一部分的所有声明。

GitLab SaaS

您的属性映射可以使用嵌入在 GitLab ID 令牌中的声明作为来源属性,其中包括:

  • sub:项目名称和 Git 引用,例如 project_path:groupname/projectname:ref_type:branch:ref:main
  • namespace_id:唯一群组 ID。
  • project_id:唯一项目 ID。
  • user_id:唯一身份用户 ID。
  • environment:作业适用的环境。
  • ref_path:Git 引用,例如 refs/heads/main

以下属性映射会将 GitLab ID 令牌中的 google.subject 设置为 sub 声明。由于 sub 声明同时包含项目名称和 Git 引用,因此该映射可让您按代码库和分支控制访问权限:

google.subject=assertion.sub

如果某些分支(例如 main)需要与其他分支不同的资源访问权限(例如功能分支),则按代码库和分支控制访问权限非常有用。

在某些情况下,仅按项目或群组区分访问权限可能就足够了。因此,以下映射包含另外两个包含 GitLab project_idnamespace_id 的属性:

google.subject=assertion.sub
attribute.project_id=assertion.project_id
attribute.namespace_id=assertion.namespace_id

Terraform Cloud

您的特性映射可以使用在 Terraform Cloud OIDC 令牌中嵌入的声明,包括以下内容:

  • terraform_organization_id:包含组织的唯一 ID,例如 org-xxxxxxxxxxxxxxxx
  • terraform_workspace_id:包含工作区的唯一 ID,例如 ws-xxxxxxxxxxxxxxxx
  • terraform_workspace_name:包含工作区的显示名称
  • sub:包含组织、工作区和阶段的显示名称,例如 organization:example-org:workspace:example-workspace:run_phase:apply

以下特性映射会将 Terraform Cloud OIDC 令牌中的 google.subject 设置为 terraform_workspace_id 声明:

google.subject=assertion.terraform_workspace_id

通过此映射,您可以按工作区控制对 Google Cloud 资源的访问权限。

定义属性条件

属性条件是可以检查断言属性和目标属性的 CEL 表达式。如果给定凭据的属性条件评估结果为 true,则系统会接受凭据。否则,凭据会被拒绝。 您必须对所有属性条件字段使用属性映射。

GitHub Actions

使用以下属性条件来限制对 GitHub 组织颁发的令牌的访问权限:

assertion.repository_owner=='ORGANIZATION'

ORGANIZATION 替换为您的 GitHub 组织名称。

(可选)扩展特性条件,以限制对部分工作流或分支的访问权限。例如,以下条件限制了对使用 Git 分支 main 的工作流的访问权限:

assertion.repository_owner=='ORGANIZATION' && assertion.ref=='refs/heads/main'

GitLab SaaS

使用以下属性条件来限制对 GitLab 群组颁发的令牌的访问权限

assertion.namespace_id=='GROUP_ID'

GROUP_ID 替换为 GitLab 群组首页上显示的群组 ID。

(可选)扩展属性条件,以限制对部分项目、分支或环境的访问权限。例如,以下条件限制对使用环境 production 的作业的访问权限:

assertion.namespace_id=='GROUP_ID' && assertion.environment=='production'

Terraform Cloud

使用以下属性条件来限制对 Terraform Cloud 组织颁发的令牌的访问权限:

assertion.terraform_organization_id=='ORGANIZATION_ID'

ORGANIZATION_ID 替换为您的组织的唯一 ID,例如 org-xxxxxxxxxxxxxxxx。(可选)扩展特性条件,以限制对部分工作流或分支的访问权限。例如,以下属性条件限制对特定工作区的访问权限:

assertion.terraform_organization_id=='ORGANIZATION_ID' && terraform_workspace_id=='WORKSPACE_ID'

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

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

控制台

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

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

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

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

  4. 配置提供方设置:

    GitHub Actions

    • 选择提供方OpenID Connect (OIDC)
    • 提供方名称:提供方的名称。该名称还用作提供方 ID。提供商 ID 创建后便无法更改。
    • 颁发者网址https://token.actions.githubusercontent.com/
    • 受众群体默认受众群体

    GitLab SaaS

    • 选择提供方OpenID Connect (OIDC)
    • 提供方名称:提供方的名称。该名称还用作提供方 ID。提供商 ID 创建后便无法更改。
    • 颁发者网址https://gitlab.com
    • 受众群体默认受众群体

    Terraform Cloud

    • 选择提供方OpenID Connect (OIDC)
    • 提供方名称:提供方的名称。该名称还用作提供方 ID。提供商 ID 创建后便无法更改。
    • 颁发者网址https://app.terraform.io
    • 受众群体默认受众群体
  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. 添加工作负载身份池提供商:

    GitHub Actions

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="https://token.actions.githubusercontent.com/" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS"
    

    替换以下值:

    GitLab SaaS

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="https://gitlab.com" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS"
    

    替换以下值:

    Terraform Cloud

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="https://app.terraform.io" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS"
    

    替换以下值:

更新工作负载身份提供方的属性条件

本部分介绍了如何更新现有工作负载身份池提供方的属性条件,以限制对 GitHub 组织、GitLab 群组或 Terraform Cloud 组织颁发的令牌的访问权限。

如需找到建议用于流水线的属性条件,请参阅定义属性条件

控制台

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

    转到“工作负载身份池”

  2. 找到包含提供方的工作负载身份池,然后点击池对应的 展开节点图标。

  3. 找到您要修改的工作负载身份池提供方,然后点击 修改

  4. 属性条件中,输入您之前确定的属性条件

  5. 如需更新工作负载身份池和提供方,请点击保存

gcloud

如需更新工作负载身份池提供方,请运行以下命令:

gcloud iam workload-identity-pools providers update-oidc PROVIDER_ID \\
    --location="global" \\
    --workload-identity-pool="POOL_ID" \\
    --attribute-condition="CONDITIONS"

替换以下值:

对部署流水线进行身份验证

您必须为每个 GitHub Actions 工作流或 Terraform Cloud 工作区执行这些步骤。

为部署流水线创建服务账号

  1. 启用 IAM, Security Token Service, and Service Account Credentials API。

    启用 API

  2. 创建一个服务账号以代表工作负载。我们建议您为每个部署流水线使用专用服务账号

    该服务账号不需要与工作负载身份池位于同一项目中。

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

允许部署流水线模拟服务账号

如需允许外部身份模拟服务账号,请向其授予服务账号的 Workload Identity User 角色 (roles/iam.workloadIdentityUser)。您可以向特定外部身份或多个外部身份授予该角色:

  • 对于特定的外部身份,请编写一个检查 google.subject 特性的特性条件。
  • 对于一组外部身份,编写一个检查 google.groups 特性或自定义属性 attribute.NAME 的特性条件。

控制台

如需使用 Google Cloud 控制台允许外部身份模拟服务账号,请执行以下操作:

  1. 在 Google Cloud 控制台中,转到 Workload Identity 池页面。

    转到“工作负载身份池”

  2. 找到您要更新的工作负载身份池并选择它。

  3. 如需授予对所选工作负载身份池的访问权限,请点击 授予访问权限

  4. 服务账号列表中,选择您要模拟的外部身份的服务账号。

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

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

      特性名称列表中,选择过滤根据的特性。

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

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

gcloud

如需使用 gcloud CLI 允许外部身份模拟服务账号,请执行以下操作:

  1. 如需获取当前项目的编号,请执行以下命令:

    gcloud projects describe $(gcloud config get-value core/project) --format=value\(projectNumber\)
    
  2. 如需向符合特定条件的外部身份授予 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特性映射中的自定义特性的名称

配置部署流水线

您现在可以在部署流水线中使用工作负载身份联合了。

GitHub Actions

借助 google-github-actions/auth 操作,您可以在工作流执行期间自动生成凭据配置文件。然后,客户端库和工具(例如 terraform)可以使用此凭据配置文件自动获取 Google 凭据。

修改 GitHub Actions YAML 文件并添加以下内容:

  • 通过添加以下配置,允许作业提取 GitHub ID 令牌:

    permissions:
      id-token: write
      contents: read
    
  • 添加步骤以创建凭据配置文件:

    - id: 'auth'
      name: 'Authenticate to Google Cloud'
      uses: 'google-github-actions/auth@v1'
      with:
        create_credentials_file: true
        workload_identity_provider: 'projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID'
        service_account: 'SERVICE_ACCOUNT_EMAIL'
    

替换以下值:

  • PROJECT_NUMBER:包含工作负载身份池的项目的编号
  • POOL_ID:工作负载身份池的 ID
  • PROVIDER_ID:工作负载身份池提供方的 ID
  • SERVICE_ACCOUNT_EMAIL:服务账号的电子邮件地址

示例:

jobs:
  build:
    # Allow the job to fetch a GitHub ID token
    permissions:
      id-token: write
      contents: read

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - id: 'auth'
        name: 'Authenticate to Google Cloud'
        uses: 'google-github-actions/auth@v1'
        with:
          create_credentials_file: true
          workload_identity_provider: 'projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID'
          service_account: 'SERVICE_ACCOUNT_EMAIL'

如需详细了解如何使用 google-github-actions/auth 操作,请参阅设置工作负载身份联合

GitLab SaaS

修改 .gitlab-ci.yml 文件并将以下内容添加到作业配置中:

job:
  variables:
    WORKLOAD_IDENTITY_PROJECT_NUMBER: PROJECT_NUMBER
    WORKLOAD_IDENTITY_POOL: POOL_ID
    WORKLOAD_IDENTITY_PROVIDER: PROVIDER_ID
    SERVICE_ACCOUNT: SERVICE_ACCOUNT_EMAIL
    GOOGLE_APPLICATION_CREDENTIALS: $CI_BUILDS_DIR/.workload_identity.wlconfig

  id_tokens:
    WORKLOAD_IDENTITY_TOKEN:
      aud: https://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID

  script:
    - |-
      echo $WORKLOAD_IDENTITY_TOKEN > $CI_BUILDS_DIR/.workload_identity.jwt
      cat << EOF > $GOOGLE_APPLICATION_CREDENTIALS
      {
        "type": "external_account",
        "audience": "//iam.googleapis.com/projects/$WORKLOAD_IDENTITY_PROJECT_NUMBER/locations/global/workloadIdentityPools/$WORKLOAD_IDENTITY_POOL/providers/$WORKLOAD_IDENTITY_PROVIDER",
        "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
        "token_url": "https://sts.googleapis.com/v1/token",
        "credential_source": {
          "file": "$CI_BUILDS_DIR/.workload_identity.jwt"
        },
        "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$SERVICE_ACCOUNT:generateAccessToken"
      }
      EOF

替换以下值:

  • PROJECT_NUMBER:包含工作负载身份池的项目的编号
  • POOL_ID:工作负载身份池的 ID
  • PROVIDER_ID:工作负载身份池提供方的 ID
  • SERVICE_ACCOUNT_EMAIL:服务账号的电子邮件地址

配置会执行以下操作:

  1. 指示 GitLab 颁发 ID 令牌,并在名为 WORKLOAD_IDENTITY_TOKEN 的环境变量中提供该令牌。ID 令牌使用工作负载身份池提供方作为受众群体。
  2. 将 ID 令牌保存到名为 .workload_identity.jwt 的临时文件中。
  3. 创建凭据配置文件,用于指示客户端库从 .workload_identity.jwt 读取 ID 令牌并使用它来模拟服务账号。
  4. 设置环境变量 GOOGLE_APPLICATION_CREDENTIALS 以指向凭据配置文件。

Terraform Cloud

配置 Terraform Cloud 工作区,以便它使用工作负载身份联合向 Google Cloud 进行身份验证:

  1. 在 Terraform Cloud 中,打开工作区,然后转至变量

  2. 添加以下变量:

    变量类别
    环境变量 TFC_GCP_PROVIDER_AUTH true
    环境变量 TFC_GCP_RUN_SERVICE_ACCOUNT_EMAIL 服务账号的电子邮件地址,例如 terraform@my-project-123.iam.gserviceaccount.com
    环境变量 TFC_GCP_PROJECT_NUMBER 包含工作负载身份池的项目的编号
    环境变量 TFC_GCP_WORKLOAD_POOL_ID 工作负载身份池的 ID
    环境变量 TFC_GCP_WORKLOAD_PROVIDER_ID 工作负载身份池提供方的 ID

    (可选)您可以添加其他环境变量,让 Terrform Cloud 为 planapply 阶段使用不同的服务账号。如需了解详情,请参阅可选环境变量

  3. 在变量列表中,验证您在上一步中添加的五个变量的类别是否设置为 env

  4. 验证 Terraform 配置是否使用 4.48.0 或更高版本的 Google Cloud 提供程序,并根据需要进行更新,如下所示:

    terraform {
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = "~> 4.48.0"
        }
      }
    }
    
  5. 将更改提交到源代码库。

后续步骤