为 GKE 配置托管式工作负载身份验证

本文档介绍了如何在 GKE 舰队管理的集群中为 Google Kubernetes Engine (GKE) 配置托管式工作负载身份。还介绍了如何部署工作负载,以及如何验证工作负载的身份和证书。

为 GKE 设置和使用托管式工作负载身份涉及以下步骤:

  1. 配置 Certificate Authority Service 以便为托管式工作负载身份颁发证书

  2. 将 CA 绑定到工作负载身份池

  3. 授权托管式工作负载身份从 CA 池请求证书

  4. 部署具有托管式工作负载身份的工作负载

Google 管理的工作负载身份池

将集群添加到 GKE 舰队时,舰队会自动创建一个 Google 管理的工作负载身份池,该池充当信任网域的根。Google 管理的工作负载身份池具有以下限制条件:

  • Google 会完全管理该池,因此您无法创建任何子资源,例如命名空间、身份或身份提供方。

  • 该池只能用于 GKE 工作负载。您无法向该池中添加其他类型的工作负载,例如 Compute Engine 虚拟机。

  • 该池中的所有集群都遵循标准的 Kubernetes 命名空间相同性模型。这意味着该池中的所有集群都具有同等权限。在该池中任何集群上运行的工作负载都可以使用该池中的任何身份。

多项目配置

您在本文档中使用的Trusted Cloud 资源(例如 GKE 集群、根 CA 和从属 CA)可以位于不同的项目中。在引用这些资源时,请使用 --project 标志为每种资源指定正确的项目。

准备工作

  1. Create or select a Trusted Cloud project.

    • Create a Trusted Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Trusted Cloud project you are creating.

    • Select the Trusted Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Trusted Cloud project name.

  2. 了解托管式工作负载身份

  3. 确保您至少有一个 GKE 集群。确保您的集群运行的是 1.33.0-gke.2248000 或更高版本。

  4. 将集群添加到 GKE 舰队。如果您的集群是 Autopilot 集群,请省略 --enable-workload-identity。舰队会自动创建一个 Google 管理的工作负载身份池,该池充当信任网域

    运行以下命令以启用 GKE 舰队:

    gcloud container clusters update CLUSTER_NAME \
        --workload-pool=PROJECT_ID.svc.id.goog \
        --enable-fleet \
        --fleet-project=PROJECT_ID
    

    替换以下内容:

    • CLUSTER_NAME:您要向 GKE 舰队注册的 GKE 集群的名称
    • PROJECT_ID:GKE 舰队宿主项目 ID
  5. Enable the IAM and Certificate Authority Service APIs:

    gcloud services enable cloudresourcemanager.googleapis.com iam.googleapis.com privateca.googleapis.com

  6. 配置 Google Cloud CLI 以使用结算和配额项目。

    gcloud config set billing/quota_project PROJECT_ID
    

    PROJECT_ID 替换为舰队项目的 ID。

所需的角色

如需获得创建托管式工作负载身份和预配托管式工作负载身份证书所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:

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

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

配置 CA Service,以便为托管式工作负载身份颁发证书

如需为 GKE 配置托管式工作负载身份,您首先需要配置一个证书授权机构 (CA) 以及一个或多个从属 CA。此配置称为 CA 层次结构

您可以使用 CA Service 池来设置此层次结构。在此层次结构中,从属 CA 池会向您的工作负载颁发 X.509 工作负载身份证书。

配置根 CA 池

如需创建根 CA 池,请执行以下操作:

使用 gcloud privateca pools createEnterprise 层级中创建根 CA 池。此层级用于颁发长期、少量的证书。

gcloud privateca pools create ROOT_CA_POOL_ID \
    --location=REGION \
    --project=CA_PROJECT_ID \
    --tier=enterprise

替换以下内容:

  • ROOT_CA_POOL_ID:根 CA 池的唯一 ID。ID 不得超过 64 个字符,并且只能包含小写和大写字母数字字符、下划线或连字符。池 ID 在区域内必须是唯一的。

  • REGION:根 CA 池所在的区域。

  • CA_PROJECT_ID:您要在其中创建根 CA 的项目的 ID。

如需详细了解 CA 池、层级和区域,请参阅创建 CA 池

配置根 CA

使用 gcloud privateca roots create 在根 CA 池中创建根 CA。如果这是根 CA 池中的唯一 CA,系统可能会提示您启用根 CA

如需创建根 CA,请运行以下命令:

gcloud privateca roots create ROOT_CA_ID \
    --pool=ROOT_CA_POOL_ID \
    --subject="CN=ROOT_CA_CN, O=ROOT_CA_ORGANIZATION" \
    --key-algorithm="KEY_ALGORITHM" \
    --max-chain-length=1 \
    --location=REGION \
    --project=CA_PROJECT_ID \
    --auto-enable

替换以下内容:

  • ROOT_CA_ID:根 CA 的唯一名称。CA 名称不得超过 64 个字符,并且只能包含小写和大写字母数字字符、下划线或连字符。CA 名称在区域内必须是唯一的。
  • ROOT_CA_POOL_ID:根 CA 池的 ID。
  • ROOT_CA_CN:根 CA 的通用名称。
  • ROOT_CA_ORGANIZATION:根 CA 的组织。
  • KEY_ALGORITHM:密钥算法,例如 ec-p256-sha256
  • REGION:根 CA 池所在的区域。
  • CA_PROJECT_ID:您在其中创建根 CA 的项目的 ID。

如需详细了解 CA 的 subject 字段,请参阅主体

您可以选择在根 CA 池中创建其他根 CA。这样做对根 CA 变换可能非常有用。

配置从属 CA

您可以选择配置从属 CA。配置从属 CA 可帮助实现以下目标:

  • 多个证书颁发场景:如果您有多个证书颁发场景,则可以为每个场景创建一个从属 CA。

  • 更好的负载均衡:在 CA 池中添加多个从属 CA 有助于您更好地对证书请求进行负载均衡。

如需创建从属 CA 池和从属 CA,请执行以下操作:

  1. DevOps 层级创建从属 CA 池,用于颁发大量、短期的证书。

    gcloud privateca pools create SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --project=CA_PROJECT_ID \
        --tier=devops
    

    替换以下内容:

    • SUBORDINATE_CA_POOL_ID:从属 CA 池的唯一 ID。ID 不得超过 64 个字符,并且只能包含小写和大写字母数字字符、下划线或连字符。池 ID 在区域内必须是唯一的。
    • REGION:要在其中创建从属 CA 池的区域。
    • CA_PROJECT_ID:您在其中创建从属 CA 的项目的 ID。

    如需了解详情,请参阅创建 CA 池

  2. 在从属 CA 池中创建从属 CA。请勿更改默认的基于配置的颁发模式

    gcloud privateca subordinates create SUBORDINATE_CA_ID \
        --pool=SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --issuer-pool=ROOT_CA_POOL_ID \
        --issuer-location=REGION \
        --subject="CN=SUBORDINATE_CA_CN, O=SUBORDINATE_CA_ORGANIZATION" \
        --key-algorithm="KEY_ALGORITHM" \
        --use-preset-profile=subordinate_mtls_pathlen_0 \
        --project=CA_PROJECT_ID \
        --auto-enable
    

    替换以下内容:

    • SUBORDINATE_CA_ID:从属 CA 的唯一名称。名称不得超过 64 个字符,并且只能包含小写和大写字母数字字符、下划线或连字符。池名称在区域内必须是唯一的。
    • SUBORDINATE_CA_POOL_ID:从属 CA 池的名称。
    • REGION:从属 CA 池所在的区域。
    • ROOT_CA_POOL_ID:根 CA 池的 ID。
    • REGION:根 CA 池的区域。
    • SUBORDINATE_CA_CN:从属 CA 的通用名称。
    • SUBORDINATE_CA_ORGANIZATION:从属 CA 颁发组织的名称。
    • KEY_ALGORITHM:密钥算法,例如 ec-p256-sha256
    • CA_PROJECT_ID:您在其中创建从属 CA 的项目的 ID。

    如需详细了解 CA 的 subject 字段,请参阅主体

创建证书颁发配置文件

如需将 CA 绑定到工作负载身份池,CA 需要具有证书颁发配置。(可选)如果您需要工作负载跨多个信任网域进行身份验证,还可以使用信任配置更新池。

如需配置证书颁发配置,请创建证书颁发配置文件。该文件的格式类似于以下内容:

{
  "inlineCertificateIssuanceConfig": {
      "caPools": {
        "REGION1": "projects/CA_PROJECT_NUMBER1/locations/REGION1/caPools/SUBORDINATE_CA_POOL_ID1",
        "REGION2": "projects/CA_PROJECT_NUMBER2/locations/REGION2/caPools/SUBORDINATE_CA_POOL_ID2"
      },
      "lifetime": "DURATION",
      "rotationWindowPercentage": ROTATION_WINDOW_PERCENTAGE,
      "keyAlgorithm": "ALGORITHM"
  }
}

替换以下内容:

  • REGION:CA 所在的区域。

  • CA_PROJECT_NUMBER:您在其中创建从属 CA 池的项目的编号。如需从 CA_PROJECT_ID 项目获取项目编号,请运行以下命令:

    gcloud projects describe CA_PROJECT_ID --format="value(projectNumber)"
    
  • SUBORDINATE_CA_POOL_ID:从属 CA 池的名称。

  • ALGORITHM:可选。用于生成私钥的加密算法。有效值包括 ECDSA_P256(默认值)、ECDSA_P384RSA_2048RSA_3072RSA_4096

  • DURATION:可选。叶证书的有效期(以秒为单位)。该值必须介于 86400(1 天)到 2592000(30 天)之间。如果未指定,则系统会使用默认值 86400(1 天)。已颁发证书的实际有效性也取决于颁发证书的 CA,因为它可能会限制已颁发证书的生命周期。

  • ROTATION_WINDOW_PERCENTAGE:可选:触发续订时证书生命周期的百分比。值必须介于 50 到 80 之间。默认值为 50。

创建信任配置文件

默认情况下,同一信任网域中的工作负载可以使用托管式工作负载身份相互进行身份验证。如果您希望位于不同信任网域中的工作负载相互进行身份验证,则需要在工作负载身份池中明确声明信任关系。为此,您可以创建一个信任配置文件,其中包含为每个网域提供证书的 inlineTrustConfig

信任配置文件包含一组信任锚,托管式工作负载身份会使用这些信任锚来验证对等证书。信任配置文件会将 SPIFFE 信任网域映射到 CA 证书。

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

  1. 下载证书。

    gcloud privateca pools get-ca-certs ROOT_CA_POOL_ID \
        --output-file=CERTIFICATE_PATH \
        --location=REGION
    

    替换以下内容:

    • ROOT_CA_POOL_ID:根 CA 池的 ID
    • CERTIFICATE_PATH:要将 PEM 编码的证书输出到的路径
    • REGION:根 CA 池的区域

  2. 创建一个包含内嵌信任配置的文件,其中带有 PEM 格式的证书。该文件类似于以下内容:
    {
      "inlineTrustConfig": {
        "additionalTrustBundles": {
          "TRUST_DOMAIN_NAME1": {
            "trustAnchors": [
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL1\n-----END CERTIFICATE-----"
              },
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL2\n-----END CERTIFICATE-----"
              }
            ]
          },
          "TRUSTED_DOMAIN_NAME2": {
            "trustAnchors": [
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL3\n-----END CERTIFICATE-----"
              },
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL4\n-----END CERTIFICATE-----"
              }
            ]
          }
        }
      }
    }
    

    替换以下内容:

    • TRUST_DOMAIN_NAME:信任网域名称,格式如下:
      PROJECT_ID.svc.id.goog
      
    • CERTIFICATE_MATERIAL:一组 PEM 格式的 CA 证书,受信任可在信任网域中颁发证书。

将 CA 绑定到工作负载身份池

创建 CA 层次结构并为每个 CA 创建证书颁发配置后,您需要将 CA 绑定到工作负载身份池。如需将 CA 绑定到工作负载身份池,您可以使用 CA 的证书颁发配置来更新工作负载身份池。然后,您可以验证该池是否已更新。

更新工作负载身份池

如需更新池,请运行以下命令:

gcloud iam workload-identity-pools update TRUST_DOMAIN_NAME \
    --location="global" \
    --inline-certificate-issuance-config-file=CIC_JSON_FILE_PATH \
    --inline-trust-config-file=TC_JSON_FILE_PATH \
    --project=PROJECT_ID

替换以下内容:

  • TRUST_DOMAIN_NAME:信任网域的名称,格式如下:

    PROJECT_ID.svc.id.goog
    
  • CIC_JSON_FILE_PATH:您之前创建的 JSON 格式的证书颁发配置文件 (cic.json) 的路径。

  • TC_JSON_FILE_PATH:可选。您之前创建的 JSON 格式的信任配置文件 (tc.json) 的路径。如果您的工作负载跨不同信任网域进行身份验证,则必须指定此文件。否则,您可以省略 --inline-trust-config

验证工作负载身份池是否已更新

如需验证工作负载身份池是否已随证书颁发配置和信任配置一起更新,请运行以下命令:

gcloud iam workload-identity-pools describe TRUST_DOMAIN_NAME \
    --location="global" \
    --project=PROJECT_ID

TRUST_DOMAIN_NAME 替换为本文档前面部分用于更新工作负载身份池的信任网域名称。

命令输出类似于以下内容:

inlineCertificateIssuanceConfig:
    caPools:
      REGION1: projects/PROJECT_NUMBER1/locations/REGION1/caPools/SUBORDINATE_CA_POOL_ID1,
      REGION2: projects/PROJECT_NUMBER2/locations/REGION2/caPools/SUBORDINATE_CA_POOL_ID2
    keyAlgorithm: ALGORITHM
    lifetime: DURATION
    rotationWindowPercentage: ROTATION_WINDOW_PERCENTAGE
inlineTrustConfig:
    additionalTrustBundles:
      example.com:
          trustAnchors:
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL1
            -----END CERTIFICATE-----
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL2
            -----END CERTIFICATE-----
      myorg.com:
          trustAnchors:
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL3
            -----END CERTIFICATE-----
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL4
            -----END CERTIFICATE-----
name: PROJECT_ID.svc.id.goog
state: ACTIVE

如果命令输出中不存在 inlineCertificateIssuanceConfiginlineTrustConfig,请验证您是否已正确配置 gcloud CLI 以将正确的项目用于结算和配额。您可能需要更新到较新版本的 gcloud CLI。

授权托管式工作负载身份从 CA 池请求证书

将 CA 绑定到工作负载身份池后,您需要授权托管式工作负载身份从 CA 池请求证书。如需向这些身份授权,请执行以下操作:

  1. 将每个从属 CA 池的 CA Service Workload Certificate Requester (roles/privateca.workloadCertificateRequester) IAM 角色授予给信任网域。以下 gcloud privateca pools add-iam-policy-binding 命令会授权信任网域从 CA Service 证书链请求证书。

    gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --role=roles/privateca.workloadCertificateRequester \
        --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/name/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog" \
        --project=CA_PROJECT_ID
    

    替换以下内容:

    • SUBORDINATE_CA_POOL_ID:从属 CA 池的 ID。
    • REGION:从属 CA 池的区域。
    • PROJECT_NUMBER:包含 GKE 工作负载身份池的项目的项目编号。

      如需从 PROJECT_ID 获取 PROJECT_NUMBER,请运行以下命令:

      gcloud projects describe PROJECT_ID --format="value(projectNumber)"
      
    • PROJECT_ID:GKE 舰队宿主项目的项目 ID。

    • CA_PROJECT_ID:您在其中创建从属 CA 的项目的 ID。

  2. 将从属 CA 池的 CA Service Pool Reader (roles/privateca.poolReader) 角色授予给托管式工作负载身份。这将授权托管式工作负载身份从 CA 的证书链获取已签名的 X.509 证书。

    gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --role=roles/privateca.poolReader \
        --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/name/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog" \
        --project=CA_PROJECT_ID
    

    替换以下内容:

    • SUBORDINATE_CA_POOL_ID:从属 CA 池的 ID。
    • REGION:从属 CA 池的区域。
    • PROJECT_NUMBER:包含 GKE 工作负载身份池的项目的项目编号。
    • PROJECT_ID:GKE 舰队宿主项目的项目 ID。
    • CA_PROJECT_ID:您在其中创建从属 CA 的项目的 ID。

部署具有托管式工作负载身份的工作负载

将 CA 池配置为可为托管式工作负载身份颁发证书后,您可以部署具有托管式工作负载身份的工作负载。

本部分介绍如何部署具有托管式工作负载身份的测试工作负载。为此,您需要部署一个 Pod,检查是否已生成凭证,然后查看证书和 SPIFFE ID。

部署 Pod

如需在集群中部署测试 Pod,请执行以下操作:

  1. 获取集群凭证。

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CLUSTER_ZONE \
        --project=CLUSTER_PROJECT_ID
    
  2. 创建 Kubernetes 命名空间。

    kubectl create namespace KUBERNETES_NAMESPACE
    
  3. 部署测试 PodSpec。

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      namespace: KUBERNETES_NAMESPACE
      name: example-pod
    spec:
      containers:
      - name: main
        image: debian
        command: ['sleep', 'infinity']
        volumeMounts:
        - name: fleet-spiffe-credentials
          mountPath: /var/run/secrets/workload-spiffe-credentials
          readOnly: true
      nodeSelector:
        iam.gke.io/gke-metadata-server-enabled: "true"
      volumes:
      - name: fleet-spiffe-credentials
        csi:
          driver: podcertificate.gke.io
          volumeAttributes:
            signerName: spiffe.gke.io/fleet-svid
            trustDomain: fleet-project/svc.id.goog
    EOF
    

列出工作负载凭证

如需列出工作负载凭证,请运行以下命令。凭证可能需要几分钟才能创建完成。

kubectl exec -it example-pod -n KUBERNETES_NAMESPACE -- ls  /var/run/secrets/workload-spiffe-credentials

您应该会看到以下输出内容:

ca_certificates.pem
certificates.pem
private_key.pem
trust_bundles.json

查看证书

如需查看证书,请执行以下操作:

  1. 将证书导出到证书文件。

    kubectl exec -it example-pod --namespace=KUBERNETES_NAMESPACE -- cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -noout -text > certfile
    
  2. 查看证书文件。

    cat certfile
    

    在证书的 X509v3 Subject Alternative Name 属性中,您会看到 SPIFFE ID,其格式如下:spiffe://PROJECT_ID.svc.id.goog/ns/KUBERNETES_NAMESPACE/sa/default

    default 引用默认 Kubernetes ServiceAccount。

测试工作负载到工作负载身份验证

如需测试工作负载到工作负载身份验证,请参阅使用 Go 测试 mTLS 身份验证

代码库中的示例代码会创建客户端和服务器工作负载。您可以使用本文档前面部分生成的证书来测试工作负载之间的双向身份验证。

后续步骤