使用 Kubernetes 配置工作负载身份联合

本指南介绍了如何使用工作负载身份联合,让 Azure Azure Service (AKS)、Amazon Elastic Kubernetes Service 或自托管的 Kubernetes 集群上运行的工作负载可以向 Google Cloud 进行身份验证。

Kubernetes 可让您配置集群,以便工作负载可以从预计卷获取 Kubernetes 服务账号令牌。通过设置工作负载身份联合,您可以让工作负载使用这些 Kubernetes 服务账号令牌向 Google Cloud 进行身份验证。

如果您使用的是 GKE,请使用 Workload Identity,而不是配置工作负载身份联合。

须知事项

在配置工作负载身份联合之前,请确保您的 Kubernetes 集群符合以下条件:

AKS

请确保您的集群符合以下要求:

  • 您已启用 OIDC 颁发者功能。

    您必须启用此功能,以便工作负载身份联合可以访问集群的 OpenID Connect 元数据和 JSON Web 密钥集 (JWKS)。

EKS

您无需对 EKS 配置进行任何更改。

Kubernetes

请确保您的集群符合以下要求:

  • 您正在运行 Kubernetes 1.20 或更高版本。

    以前版本的 Kubernetes 使用与本文档中的说明不兼容的其他服务账号令牌格式。

  • 您配置了 kube-apiserver,使其支持 ServiceAccount 令牌卷投影

集群无需通过互联网访问。

配置工作负载身份联合

您只需为每个 Kubernetes 集群执行一次这些步骤。然后,您可以为多个工作负载以及多个 Google Cloud 项目使用相同的工作负载身份池和提供方。

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

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

    转到“项目选择器”

  2. 我们建议您 使用专用项目管理工作负载身份池,并且提供商
  3. 确保您的 Google Cloud 项目已启用结算功能

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

    启用 API

定义特性映射和条件

Kubernetes 服务账号令牌包含多个声明,包括:

  • sub:包含服务账号的命名空间和名称,例如 system:serviceaccount:NAMESPACE:KSA_NAME,其中 NAMESPACE 是服务账号的命名空间,KSA_NAME 是服务账号的名称。
  • "kubernetes.io".namespace:包含服务账号的命名空间。
  • "kubernetes.io".serviceaccount.name:服务账号的名称
  • "kubernetes.io".pod.name:包含 Pod 的名称。

如需在 Google Cloud 中使用 sub 作为主题标识符 (google.subject),请使用以下映射:

google.subject=assertion.sub

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

google.subject=assertion.sub,
attribute.namespace=assertion['kubernetes.io']['namespace'],
attribute.service_account_name=assertion['kubernetes.io']['serviceaccount']['name'],
attribute.pod=assertion['kubernetes.io']['pod']['name']

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

您可以使用特性条件来限制哪些 Kubernetes 服务账号可以使用工作负载身份联合来获取短期 Google Cloud 令牌。例如,以下条件限制从 backendmonitoring 命名空间访问 Kubernetes 服务账号:

assertion['kubernetes.io']['namespace'] in ['backend', 'monitoring']

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

所需的角色

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

如需详细了解如何授予角色,请参阅管理访问权限

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

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

如需创建工作负载身份池和提供商,请执行以下操作:

AKS

  1. 确定 AKS 集群的颁发者网址:

    az aks show -n NAME -g RESOURCE_GROUP --query "oidcIssuerProfile.issuerUrl" -otsv
    

    替换以下内容:

    • NAME:集群的名称。
    • RESOURCE_GROUP:集群的资源组

    该命令会输出颁发者网址。执行以下步骤之一时需要颁发者网址。

    如果该命令未返回颁发者网址,请验证您是否已启用 OIDC 颁发者功能。

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

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

    替换以下内容:

    • POOL_ID:池的唯一 ID。
    • DISPLAY_NAME:池的名称。
    • DESCRIPTION:您选择的池的说明。当您授予对池身份的访问权限时,系统会显示此说明。
  3. 将 AKS 集群添加为工作负载身份池提供商:

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

    替换以下内容:

    • PROVIDER_ID:您选择的唯一工作负载身份池提供商 ID。
    • POOL_ID:您之前创建的工作负载身份池 ID。
    • ISSUER:您之前确定的颁发者 URI。
    • MAPPINGS:您在本指南前面部分中创建的以英文逗号分隔的属性映射列表。
    • CONDITIONS:您在本指南前面部分中创建的可选属性条件。如果您没有特性条件,请移除该参数。

EKS

  1. 确定 EKS 集群的颁发者网址:

    aws eks describe-cluster --name NAME --query "cluster.identity.oidc.issuer" --output text
    

    NAME 替换为您的集群的名称。

    该命令会输出颁发者网址。执行以下步骤之一时需要颁发者网址。

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

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

    替换以下内容:

    • POOL_ID:池的唯一 ID。
    • DISPLAY_NAME:池的名称。
    • DESCRIPTION:您选择的池的说明。当您授予对池身份的访问权限时,系统会显示此说明。
  3. 将 EKS 集群添加为工作负载身份池提供方:

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

    替换以下内容:

    • PROVIDER_ID:您选择的唯一工作负载身份池提供商 ID。
    • POOL_ID:您之前创建的工作负载身份池 ID。
    • ISSUER:您之前确定的颁发者 URI。
    • MAPPINGS:您在本指南前面部分中创建的以英文逗号分隔的属性映射列表。
    • CONDITIONS:您在本指南前面部分中创建的可选属性条件。如果您没有特性条件,请移除该参数。

Kubernetes

  1. 连接到您的 Kubernetes 集群并使用 kubectl 确定您集群的颁发者网址:

    kubectl get --raw /.well-known/openid-configuration | jq -r .issuer
    

    执行以下步骤之一时需要颁发者网址。

  2. 下载集群的 JSON Web 密钥集 (JWKS):

    kubectl get --raw /openid/v1/jwks > cluster-jwks.json
    

    在以下某个步骤中,您需要上传 JWKS,以便工作负载身份联合能够验证集群颁发的 Kubernetes 服务账号令牌的真实性。

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

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

    替换以下内容:

    • POOL_ID:池的唯一 ID。
    • DISPLAY_NAME:池的名称。
    • DESCRIPTION:您选择的池的说明。当您授予对池身份的访问权限时,系统会显示此说明。
  4. 将 Kubernetes 集群添加为工作负载身份池提供商,并上传集群的 JWKS:

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="ISSUER" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS" \
        --jwk-json-path="cluster-jwks.json"
    

    替换以下内容:

    • PROVIDER_ID:您选择的唯一工作负载身份池提供商 ID。
    • POOL_ID:您之前创建的工作负载身份池 ID。
    • ISSUER:您之前确定的颁发者 URI。
    • MAPPINGS:您在本指南前面部分中创建的以英文逗号分隔的属性映射列表。
    • CONDITIONS:您在本指南前面部分中创建的可选属性条件。如果您没有特性条件,请移除该参数。

对 Kubernetes 工作负载进行身份验证

本部分介绍如何配置 Kubernetes 工作负载以使用工作负载身份联合。

您必须对需要访问 Google Cloud 的每个 Kubernetes 工作负载执行一次这些步骤。

创建一对服务账号

要让 Kubernetes 工作负载向 Google Cloud 进行身份验证,您需要一对服务账号:

  • 您附加到 Kubernetes Pod 的 Kubernetes 服务账号。
  • Kubernetes 工作负载可以使用其关联的 Kubernetes 服务账号来模拟的 IAM 服务账号。

如需创建服务账号,请执行以下操作:

  1. 创建一个表示工作负载的 IAM 服务账号

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

    gcloud iam service-accounts create SA_NAME
    

    替换以下内容:

    • SA_NAME:服务账号的名称。
  2. 创建 Kubernetes 服务账号:

    kubectl create serviceaccount KSA_NAME --namespace NAMESPACE
    

    替换以下内容:

    • KSA_NAME:服务账号的名称。
    • NAMESPACE:要在其中创建服务账号的命名空间。
  3. 向 IAM 服务账号授予对您希望 Kubernetes 工作负载访问的资源的访问权限

  4. 将 Workload Identity User 角色 (roles/iam.workloadIdentityUser) 授予 Kubernetes 服务账号的外部身份:

    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"
    

    替换以下内容:

    • SERVICE_ACCOUNT_EMAIL:服务账号的电子邮件地址
    • PROJECT_NUMBER:包含工作负载身份池的项目的编号
    • POOL_ID:工作负载身份池的池 ID
    • SUBJECT已映射google.subject 的特性的预期值,例如 system:serviceaccount:NAMESPACE:KSA_NAME

部署 Kubernetes 工作负载

现在,您可以部署一个 Kubernetes 工作负载,并让它使用服务账号对:

  1. 创建凭据配置文件:

    gcloud iam workload-identity-pools create-cred-config \
        projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \
        --service-account=SERVICE_ACCOUNT_EMAIL \
        --credential-source-file=/var/run/service-account/token \
        --credential-source-type=text \
        --output-file=credential-configuration.json
    

    替换以下内容:

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

    凭据配置文件允许 Cloud 客户端库、gcloud CLI 和 Terraform 确定以下内容:

    • 从何处获取外部凭据
    • 要使用的工作负载身份池和提供商
    • 需要模拟的服务账号
  2. 将凭据配置文件作为 ConfigMap 导入:

    kubectl create configmap CONFIGMAP_NAME \
      --from-file credential-configuration.json \
      --namespace NAMESPACE
    

    替换以下内容:

    • CONFIGMAP_NAME:ConfigMap 的名称。
    • NAMESPACE:要在其中创建 ConfigMap 的命名空间。
  3. 部署工作负载并使其使用 Kubernetes 服务账号和 ConfigMap。

    创建清单并按如下方式配置:

    • 装载投影的令牌卷,以便工作负载可以从本地文件获取 Kubernetes 服务账号令牌。配置卷,以便 Kubernetes 服务账号令牌使用工作负载身份联合池提供方所需的目标设备。
    • 装载包含凭据配置文件的 ConfigMap,以便工作负载可以访问使用工作负载身份联合的必要配置。
    • 添加包含凭据配置文件的路径的环境变量 GOOGLE_APPLICATION_CREDENTIALS,以便工作负载可以找到该文件。

    以下是一个示例清单,它使用 Kubernetes 服务账号和 ConfigMap 让 Google Cloud CLI 向 Google Cloud 进行身份验证:

    apiVersion: v1
    kind: Pod
    metadata:
      name: example
      namespace: NAMESPACE
    spec:
      containers:
      - name: example
        image: google/cloud-sdk:alpine
        command: ["/bin/sh", "-c", "gcloud auth login --cred-file $GOOGLE_APPLICATION_CREDENTIALS && gcloud auth list && sleep 600"]
        volumeMounts:
        - name: token
          mountPath: "/var/run/service-account"
          readOnly: true
        - name: workload-identity-credential-configuration
          mountPath: "/etc/workload-identity"
          readOnly: true
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: "/etc/workload-identity/credential-configuration.json"
    
      serviceAccountName: KSA_NAME
      volumes:
      - name: token
        projected:
          sources:
          - serviceAccountToken:
              audience: https://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID
              expirationSeconds: 3600
              path: token
      - name: workload-identity-credential-configuration
        configMap:
          name: CONFIGMAP_NAME
    

    您可以按照相同的方法,让使用以下客户端库之一的工具和工作负载自动查找凭据

    C++

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

    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"
        }
      }
    }
    

    gsutil

    如需使用工作负载身份联合进行身份验证,请使用以下方法之一:

    将 gsutil 与 gcloud 结合使用时,请按正常方式登录:

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

    将 gsutil 用作独立的命令行应用时,请修改 .boto 文件以包含以下部分:

    [Credentials]
    gs_external_account_file = FILEPATH
    

    在这两种情况下,请将 FILEPATH 替换为凭据配置文件的文件路径。

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

    bq

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

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

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

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

  4. (可选)通过运行以下命令验证身份验证是否正常运行:

    kubectl exec example --namespace NAMESPACE -- gcloud auth print-access-token
    

后续步骤