Help us learn about your current experience with the documentation. Take the survey.

使用 GCP Workload Identity Federation 配置 OpenID Connect

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

CI_JOB_JWT_V2GitLab 15.9 中已被弃用 并计划在 GitLab 17.0 中移除。请改用 ID tokens

本教程演示如何使用 JSON Web Token (JWT) 令牌和 Workload Identity Federation 从 GitLab CI/CD 作业 向 Google Cloud 进行身份验证。此配置会按需生成短期凭据,无需存储任何密钥。

首先,配置 GitLab 和 Google Cloud 之间的身份联合的 OpenID Connect (OIDC)。有关在 GitLab 中使用 OIDC 的更多信息, 请阅读 连接到云服务

本教程假设您拥有 Google Cloud 账户和 Google Cloud 项目。 您的账户必须在 Google Cloud 项目上至少拥有 workload identity pool Admin 权限。

如果您更喜欢使用 Terraform 模块和 CI/CD 模板而不是本教程, 请参阅 OIDC 如何简化 GitLab CI/CD 管道与 Google Cloud 的身份验证

完成本教程需要:

  1. 创建 Google Cloud workload identity pool
  2. 创建 workload identity provider
  3. 授予服务账户模拟权限
  4. 获取临时凭据

创建 Google Cloud workload identity pool

使用以下选项 创建新的 Google Cloud workload identity pool

  • 名称:workload identity pool 的友好名称,例如 GitLab
  • Pool ID:Google Cloud 项目中 workload identity pool 的唯一 ID, 例如 gitlab。此值用于引用池并出现在 URL 中。
  • 描述:可选。池的描述。
  • 启用池:确保此选项为 true

我们建议每个 GitLab 安装和每个 Google Cloud 项目创建一个池。如果您在同一 GitLab 实例上有多个 GitLab 仓库和 CI/CD 作业,它们可以使用不同的提供者对同一个池进行身份验证。

创建 workload identity provider

在上一步创建的 workload identity pool 中 创建新的 Google Cloud workload identity provider, 使用以下选项:

  • 提供者类型:OpenID Connect (OIDC)。
  • 提供者名称:workload identity provider 的友好名称,例如 gitlab/gitlab
  • 提供者 ID:池中 workload identity provider 的唯一 ID,例如 gitlab-gitlab。此值用于引用提供者,并出现在 URL 中。
  • 颁发者 (URL):您的 GitLab 实例地址,例如 https://gitlab.com/https://gitlab.example.com/
    • 地址必须使用 https:// 协议。
    • 地址必须以斜杠结尾。
  • 受众:将允许的受众列表手动设置为您的 GitLab 实例地址,例如 https://gitlab.comhttps://gitlab.example.com
    • 地址必须使用 https:// 协议。
    • 地址不能以斜杠结尾。
  • 提供者属性映射:创建以下映射,其中 attribute.X 是要作为声明包含在 Google 令牌中的属性名称,assertion.X 是要从 GitLab claim 中提取的值:
Attribute (on Google) Assertion (from GitLab)
google.subject assertion.sub
attribute.X assertion.X

您还可以使用通用表达式语言 (CEL) 构建复杂属性

您必须映射每个要用于权限授予的属性。例如,如果您想在下一步基于用户的电子邮件地址映射权限,您必须将 attribute.user_email 映射到 assertion.user_email

对于托管在 GitLab.com 上的项目,GCP 要求您 将访问权限限制为仅由您的 GitLab 组颁发的令牌

授予服务账户模拟权限

创建 workload identity pool 和 workload identity provider 定义了进入 Google Cloud 的身份验证。 此时,您可以从 GitLab CI/CD 作业向 Google Cloud 进行身份验证。 但是,您在 Google Cloud 上没有权限(授权)。

要授予您的 GitLab CI/CD 作业在 Google Cloud 上的权限,您必须:

  1. 创建 Google Cloud 服务账户。 您可以使用任何您喜欢的名称和 ID。
  2. 向您的服务账户授予 IAM 权限, 以访问 Google Cloud 资源。这些权限根据您的用例有很大差异。通常,授予此服务账户在您的 Google Cloud 项目和资源上的权限, 这些是您希望 GitLab CI/CD 作业能够使用的权限。例如,如果您需要在 GitLab CI/CD 作业中将文件上传到 Google Cloud Storage 存储桶, 您将授予此服务账户在 Cloud Storage 存储桶上的 roles/storage.objectCreator 角色。
  3. 授予外部身份权限 以模拟该服务账户。此步骤使 GitLab CI/CD 作业能够通过服务账户模拟授权到 Google Cloud。 此步骤授予服务账户本身的 IAM 权限,使外部身份能够充当该服务账户。 外部身份使用 principalSet:// 协议表示。

与上一步类似,此步骤很大程度上取决于您所需的配置。 例如,如果 GitLab CI/CD 作业是由用户名为 chris 的 GitLab 用户发起的, 要允许 GitLab CI/CD 作业模拟名为 my-service-account 的服务账户, 您将授予 my-service-account 上的外部身份 roles/iam.workloadIdentityUser IAM 角色。 外部身份采用以下格式:

principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.user_login/chris

其中 PROJECT_NUMBER 是您的 Google Cloud 项目编号,POOL_ID 是第一部分创建的 workload identity pool 的 ID(不是名称)。

此配置还假设您添加了 user_login 作为从上一部分的声明映射的属性。

获取临时凭据

配置 OIDC 和角色后,GitLab CI/CD 作业可以从 Google Cloud Security Token Service (STS) 获取临时凭据。

id_tokens 添加到您的 CI/CD 作业:

job:
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.example.com

使用 ID token 获取临时凭据:

PAYLOAD="$(cat <<EOF
{
  "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": "${GITLAB_OIDC_TOKEN}"
}
EOF
)"
FEDERATED_TOKEN="$(curl --fail "https://sts.googleapis.com/v1/token" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data "${PAYLOAD}" \
  | jq -r '.access_token'
)"

其中:

  • PROJECT_NUMBER 是您的 Google Cloud 项目编号(不是名称)。
  • POOL_ID 是第一部分创建的 workload identity pool 的 ID。
  • PROVIDER_ID 是第二部分创建的 workload identity provider 的 ID。
  • GITLAB_OIDC_TOKEN 是一个 OIDC ID token

然后,您可以使用生成的联合令牌来模拟上一部分创建的服务账户:

ACCESS_TOKEN="$(curl --fail "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateAccessToken" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer FEDERATED_TOKEN" \
  --data '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}' \
  | jq -r '.accessToken'
)"

其中:

  • SERVICE_ACCOUNT_EMAIL 是要模拟的服务账户的完整电子邮件地址,在上一部分创建。
  • FEDERATED_TOKEN 是从上一步检索到的联合令牌。

结果是 Google Cloud OAuth 2.0 访问令牌,当用作承载令牌时,您可以使用它来认证到大多数 Google Cloud API 和服务。 您还可以通过设置环境变量 CLOUDSDK_AUTH_ACCESS_TOKEN 将此值传递给 gcloud CLI。

工作示例

查看此 参考项目, 了解使用 Terraform 在 GCP 中配置 OIDC 和获取临时凭据的示例脚本。

故障排除

  • 调试 curl 响应时,安装最新版本的 curl。使用 --fail-with-body 而不是 -f。此命令会打印整个响应体,其中可能包含有用的错误消息。

  • 有关更多信息,请参阅 故障排除 Workload Identity Federation