使用 Identity Service for GKE 从 Cloud Build 专用池访问专用 Google Kubernetes Engine 集群


本教程介绍如何使用 Cloud Build 专用池访问专用 Google Kubernetes Engine (GKE) 集群的控制平面。此访问权限使您可以使用 Cloud Build 在专用 GKE 集群上部署应用和管理资源。本教程适用于平台管理员、集群管理员和开发者。本文假定您熟悉 GKE、Cloud Build、OpenID Connectgcloud 命令行工具。

Cloud Build 专用池和 GKE 集群控制平面均在 Google 自有的 Virtual Private Cloud (VPC) 网络中运行。这些 VPC 网络与您在 Google Cloud 上的 VPC 网络对等互连。但是,VPC 网络对等互连不支持传递对等互连,这可能会在使用 Cloud Build 专用池时受到限制。本教程展示了一个解决方案,该解决方案使用 Identity Service for GKE 来使 Cloud Build 专用池中的工作器能够访问专用 GKE 集群的控制平面。

架构概览

Identity Service for GKE 是 GKE 集群控制平面的身份验证代理。它会将请求代理到 API 服务器,并验证由 OpenID Connect (OIDC) 身份提供方发出的 ID 令牌。在代理成功验证 ID 令牌后,代理会将用户模拟 HTTP 标头添加到原始请求中,并将其转发到 API 服务器。该代理作为 Kubernetes 服务帐号运行,该帐号有权模拟用户和群组。

Identity Service for GKE 代理在集群节点上以 Pod 的形式运行。LoadBalancer 类型的 Kubernetes 服务会在集群外部公开该代理。如果在专用集群上启用了 Identity Service for GKE,则安装程序会向 Kubernetes 服务添加注解,以预配内部直通式网络负载平衡器。您可以通过 VPC 网络对等互连连接(例如从 Cloud Build 专用池)通过负载均衡器访问代理,因为代理在 VPC 网络中的集群节点上运行。

您可以在 Identity Service for GKE 中将 Google 配置为 OpenID Connect 身份提供方,因为 Google 的 OAuth 2.0 身份验证系统符合 OpenID Connect 规范。要获取 Google 服务帐号的 ID 令牌,您可以使用 Service Account Credentials API APIgenerateIdToken 方法。ID 令牌由 Google 颁发并签名。

总而言之,此解决方案通过使用 Identity Service for GKE 代理支持访问专用 GKE 集群控制平面。在 Cloud Build 专用池中运行的构建通过 VPC 网络对等互连连接来连接到代理。在 Cloud Build 专用池中运行的构建以 Google 服务帐号的身份运行。此 Google 服务帐号可以从 Service Account Credentials API 获取 ID 令牌以向代理进行身份验证。

下图展示了前文中介绍的架构:

使用 Identity Service for GKE 访问专用 GKE 集群

此解决方案中的所有通信都通过内部 IP 地址空间进行。专用池中的工作器不需要公共互联网连接。

当用户账号和 Google 服务账号使用 Identity Service for GKE 进行身份验证时,向其授予的 Identity and Access Management (IAM) 权限不适用。您可以改用 Kubernetes 基于角色的访问权限控制 (RBAC) 来管理这些帐号的集群权限。

准备工作

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 安装 Google Cloud CLI。
  3. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  4. 创建或选择 Google Cloud 项目

    • 创建 Google Cloud 项目:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替换为您要创建的 Google Cloud 项目的名称。

    • 选择您创建的 Google Cloud 项目:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替换为您的 Google Cloud 项目 名称。

  5. 确保您的 Google Cloud 项目已启用结算功能

  6. Enable the Cloud Build, GKE, Identity-Aware Proxy (IAP), and Service Networking APIs APIs:

    gcloud services enable cloudbuild.googleapis.com container.googleapis.com iap.googleapis.com servicenetworking.googleapis.com
  7. 安装 Google Cloud CLI。
  8. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  9. 创建或选择 Google Cloud 项目

    • 创建 Google Cloud 项目:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替换为您要创建的 Google Cloud 项目的名称。

    • 选择您创建的 Google Cloud 项目:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替换为您的 Google Cloud 项目 名称。

  10. 确保您的 Google Cloud 项目已启用结算功能

  11. Enable the Cloud Build, GKE, Identity-Aware Proxy (IAP), and Service Networking APIs APIs:

    gcloud services enable cloudbuild.googleapis.com container.googleapis.com iap.googleapis.com servicenetworking.googleapis.com

创建专用 GKE 集群

  1. 在 Cloud Shell 中,创建一个 GKE 集群,该集群没有客户端访问控制平面公共端点的权限,并且安装了 Identity Service for GKE:

    gcloud container clusters create CLUSTER  \
      --enable-identity-service \
      --enable-ip-alias \
      --enable-master-authorized-networks \
      --enable-private-endpoint \
      --enable-private-nodes \
      --master-ipv4-cidr CONTROL_PANE_CIDR \
      --network NETWORK\
      --release-channel regular \
      --scopes cloud-platform \
      --subnetwork SUBNET \
      --tags NODE_TAGS \
      --workload-pool PROJECT_ID.svc.id.goog \
      --zone ZONE
    

    替换以下内容:

    • CLUSTER:集群的名称。 在本教程中,请使用 private-cluster
    • CONTROL_PANE_CIDR:控制平面的 IP 地址范围。它必须具有 /28 前缀。在本教程中,您可以使用 172.16.0.32/28
    • NETWORK:控制平面所连接的 VPC 网络。在本教程中,请使用 default
    • SUBNET:GKE 集群控制平面连接到的子网。该子网必须属于 NETWORK 指定的 VPC 网络。在本教程中,请使用 default
    • NODE_TAGS:要应用于节点的网络标记的逗号分隔列表。在本教程中,请使用 private-cluster-node
    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • ZONE:GKE 集群的区域。在本教程中,请使用 us-central1-f

    对于该命令,请注意以下事项:

    • --enable-identity-service 标志用于对集群启用 Identity Service for GKE。在您自己的环境中,您可以对现有集群启用 Identity Service for GKE

    • --enable-private-endpoint 标志用于将控制平面配置为只能通过内部 IP 地址访问。

    • --enable-private-nodes 标志将集群节点配置为仅包含内部 IP 地址。

    • --enable-master-authorized-networks--enable-private-nodes 标志仅允许从 --network 标志指定的专用网络访问 API 服务器。

    • 可选的 --workload-pool 标志用于启用 Workload Identity。本教程不需要这样做。

  2. 添加防火墙规则,以允许 GKE 集群控制平面连接到 ClientConfig 资源的验证准入 webhook:

    gcloud compute firewall-rules create allow-control-plane-clientconfig-webhook \
      --allow tcp:15000 \
      --network NETWORK\
      --source-ranges CONTROL_PANE_CIDR\
      --target-tags NODE_TAGS
    

    ClientConfig 是一种 Kubernetes 自定义资源类型 (CRD),Identity Service for GKE 使用它来配置如何与身份提供方进行交互。

将 Identity Service for GKE 注册为 OAuth 2.0 客户端应用

在本部分中,您将使用 Google 的 OAuth 2.0 身份验证系统将 Identity Service for GKE 注册为客户端应用。

  1. 在 Google Cloud 控制台中打开凭据页面。

    打开“凭据”页面

  2. 点击创建凭据

  3. 选择 OAuth 客户端 ID

    如果尚未为 Google Cloud 项目配置同意屏幕,请点击配置同意屏幕。按照关于配置同意屏幕的文档进行操作。在本教程中,请设置以下值:

    • “用户类型”可以是“内部”或“外部”。在本教程中,您可以选择“内部”。
    • 应用名称用户支持电子邮件地址开发者联系信息为必需值,可以是任意值。
    • 您无需为此教程添加任何范围。

    配置完同意屏幕后,点击“Back to Dashboard”(返回信息中心),然后从当前流程的第 1 步重新开始。

  4. 应用类型列表中,选择 Web 应用

  5. 名称字段中,输入客户端 ID 的名称。在本教程中,请使用 Identity Service for GKE

  6. 点击创建

    系统会显示一个对话框。复制您的客户端 ID 的值;此过程稍后会用到。

  7. 点击 OK 关闭对话框。

  8. 在 Cloud Shell 中,在主目录下创建一个名为 cloud-build-private-pools-gke-tutorial 的目录,然后转到该目录:

    mkdir -p ~/cloud-build-private-pools-gke-tutorial cd ~/cloud-build-private-pools-gke-tutorial

  9. 在新目录中,创建一个名为 client-config-patch.yaml 的 YAML 文件,该文件包含稍后用于修补 Identity Service for GKE ClientConfig 资源的值:

    cat << EOF > client-config-patch.yaml
    spec:
      authentication:
      - name: google-oidc
        oidc:
          clientID: CLIENT_ID
          cloudConsoleRedirectURI: https://console.cloud.google.com/kubernetes/oidc
          extraParams: prompt=consent,access_type=offline
          issuerURI: https://accounts.google.com
          kubectlRedirectURI: http://localhost:10000/callback
          scopes: email
          userClaim: email
          userPrefix: '-'
    EOF
    

    CLIENT_ID 替换为上一步中的 OAuth 客户端 ID。

    请注意有关该补丁的以下事项:

    • 由 Google 的 OAuth 2.0 身份验证系统发放的 ID 令牌在子(主题)声明中包含唯一的数字标识符。在角色绑定中使用以下不透明标识符会导致难以确定角色绑定的主题。因此,此补丁会将 Identity Service for GKE 配置为使用 ID 令牌中的电子邮件声明来识别用户,而不是使用默认的子声明。

    • 添加电子邮件范围,使颁发的 ID 令牌包含电子邮件声明。

    • 开发者使用 Identity Service for GKE 向集群进行身份验证时,会使用 cloudConsoleRedirectURIextraParamskubectlRedirectURI 和范围字段。Google 服务帐号向集群进行身份验证时不使用它们。kubectlRedirectURI 字段是必填项。

    • userPrefix 字段是使用配置的身份提供方进行身份验证的用户的前缀。值 '-' 表示无前缀。

    • spec.authentication 字段是一个数组。您可以将多个 OpenID Connect 身份提供方与 Identity Service for GKE 搭配使用。例如,您可以使用 Google 作为身份提供方来对 Google 服务帐号进行身份验证,并使用另一个身份提供方对开发者进行身份验证。

    如需详细了解此配置中的字段,请参阅使用外部身份提供方向 GKE 进行身份验证

创建 Google 服务帐号以配置 Identity Service for GKE

  1. 在 Cloud Shell 中,创建一个 Google 服务账号:

    gcloud iam service-accounts create ISG_GSA \
      --display-name "Configure Identity Service for GKE"
    

    ISG_GSA 替换为您要用于 Google 服务帐号的名称。在本教程中,请使用 identity-service-for-gke

    您可以将此 Google 服务帐号分配给 Compute Engine 虚拟机实例,以便在集群上配置 Identity Service for GKE 和 Kubernetes 基于角色的访问权限控制。

  2. 将项目的 Kubernetes Engine Admin 角色授予 Google 服务帐号:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --role roles/container.admin
    

    此角色提供执行本教程中的以下任务所需的权限:

    • 在项目中的集群上配置 Identity Service for GKE 设置。
    • 在集群中创建角色绑定和集群角色绑定。

配置 Identity Service for GKE

如需配置 Identity Service for GKE,您必须有权访问集群控制平面。在本教程中,您将创建一个 Compute Engine 虚拟机实例来访问控制平面。

您需要通过 SSH 访问虚拟机实例。如需启用经过身份验证和授权的从 VPC 网络外部到虚拟机实例的 SSH 访问,请将 TCP 转发与 Identity-Aware Proxy (IAP) 搭配使用。此功能可启用 SSH 访问,而无需虚拟机实例具有公共 IP 地址。

  1. 在 Cloud Shell 中,创建一条防火墙规则,以允许使用 IAP TCP 转发进行 SSH 访问,从而访问具有 ssh-iap 网络标记的任何虚拟机实例:

    gcloud compute firewall-rules create allow-ssh-ingress-from-iap \
      --allow tcp:22 \
      --description "Allow SSH tunneling using Identity-Aware Proxy" \
      --network NETWORK \
      --source-ranges 35.235.240.0/20 \
      --target-tags ssh-iap
    

    来源范围包含 IAP 用于 TCP 转发的 IP 地址。

  2. 在 GKE 集群所在的 VPC 网络中创建一个 Compute Engine 虚拟机实例:

    gcloud compute instances create VM \
      --metadata enable-oslogin=TRUE \
      --network NETWORK \
      --no-address \
      --scopes cloud-platform,userinfo-email \
      --service-account ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --subnet SUBNET  \
      --tags ssh-iap \
      --zone ZONE
    

    VM 替换为您要用于虚拟机实例的名称。在本教程中,请使用 identity-service-for-gke-configuration

    请注意关于上述命令的以下事项:

    • --service-account 标志用于将 Google 服务帐号附加到虚拟机实例。

    • 必须提供 cloud-platform 范围才能访问 Service Account Credentials API。

    • userinfo-email 范围在创建用于管理 Kubernetes 基于角色的访问权限控制的虚拟机实例时很有用。对于本教程,这是可选的。

    • --no-address 标志表示在没有外部 IP 地址的情况下创建虚拟机实例。

    • 可选的 enable-oslogin 实例元数据值会在虚拟机实例上启用 OS Login。借助 OS Login,您可以使用 IAM 管理对虚拟机实例的 SSH 访问权限。

  3. 将 ClientConfig 补丁文件复制到虚拟机实例:

    gcloud compute scp client-config-patch.yaml VM:~ --tunnel-through-iap --zone ZONE
    

    --tunnel-through-iap 标志指示 gcloud 通过 IAP 建立隧道连接。

  4. 使用 SSH 连接到虚拟机实例:

    gcloud compute ssh VM --tunnel-through-iap --zone ZONE
    

    您将通过 SSH 会话运行本部分中的其余命令。

  5. 在虚拟机实例中安装 kubectl 命令行工具和 gke-gcloud-auth-plugin 二进制文件

    sudo apt-get install -y kubectl google-cloud-sdk-gke-gcloud-auth-plugin
    
  6. 提取 GKE 集群的凭据:

    export USE_GKE_GCLOUD_AUTH_PLUGIN=True
    gcloud container clusters get-credentials CLUSTER --zone ZONE
    
  7. 修补默认的 ClientConfig 资源:

    kubectl patch clientconfig default \
        --namespace kube-public \
        --patch-file client-config-patch.yaml \
        --type merge
    
  8. 从修补后的默认 ClientConfig 资源中提取 certificateAuthorityData 字段,并将其存储在名为 certificateAuthorityData.pem 的文件中:

    kubectl get clientconfig default \
         --namespace kube-public \
         --output jsonpath='{.spec.certificateAuthorityData}' \
         | base64 --decode > certificateAuthorityData.pem
    
  9. 从修补后的默认 ClientConfig 资源中提取服务器字段,并将其存储在名为 server.txt 的文件中:

    kubectl get clientconfig default \
         --namespace kube-public \
         --output jsonpath='{.spec.server}' > server.txt
    
  10. 退出 SSH 会话:

    exit
    

(可选)验证集群配置

在继续之前,您可以验证已在集群上正确设置 Identity Service for GKE。如需验证设置,您可以使用附加到虚拟机实例的 Google 服务帐号,通过 Identity Service for GKE 向集群进行身份验证。

  1. 在 Cloud Shell 中,将 Google 服务帐号上的 Service Account OpenID Connect Identity Token Creator 授予服务帐号本身:

    gcloud iam service-accounts add-iam-policy-binding \
      ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --role roles/iam.serviceAccountOpenIdTokenCreator
    

    此角色提供 iam.serviceAccounts.getOpenIdToken 权限,若要向 Service Account Credentials API 请求服务帐号的 ID 令牌,必须具有此权限。

  2. 使用 SSH 连接到虚拟机实例:

    gcloud compute ssh VM --tunnel-through-iap --zone ZONE
    

    您将通过 SSH 会话运行本部分中的其余命令。

  3. 使用 OAuth 客户端 ID 作为请求的 aud(受众群体)声明,从元数据服务器为附加到虚拟机实例的 Google 服务帐号请求 OAuth 2.0 访问令牌

    ACCESS_TOKEN=$(curl --silent --header "Metadata-Flavor: Google" \
    http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token \
           | python3 -c 'import json, sys; print(json.load(sys.stdin).get("access_token"))')
    

    来自元数据服务器的响应正文是一个 JSON 文档。该命令使用内嵌 Python 脚本从响应正文中提取 access_token 字段。

  4. 向附加到虚拟机实例的 Google 服务帐号的 Service Account Credentials API 请求 ID 令牌

    ID_TOKEN=$(curl --silent --request POST \
        --data '{"audience": "CLIENT_ID", "includeEmail": true}' \
        --header "Authorization: Bearer $ACCESS_TOKEN" \
        --header "Content-Type: application/json; charset=utf-8" \
    "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/ISG_GSA@PROJECT_ID.iam.gserviceaccount.com:generateIdToken" \
           | python3 -c 'import json, sys; print(json.load(sys.stdin).get("token"))')
    

    请注意关于上述命令的以下事项:

    • 请求正文 JSON 中的 audience 字段用于指定所请求的 ID 令牌的 aud(目标设备)声明。
    • 上一步中的访问令牌用于向 API 进行身份验证。
  5. 查看 ID 令牌中的声明:

    echo $ID_TOKEN \
        | cut -d. -f2 \
        | base64 --decode --ignore-garbage 2> /dev/null \
        | python3 -m json.tool
    

    验证 email 声明是否包含 Google 服务帐号的电子邮件地址。

  6. 借助 Identity Service for GKE,使用 ID 令牌向控制平面进行身份验证:

    kubectl get namespaces \
        --certificate-authority certificateAuthorityData.pem \
        --server $(cat server.txt) \
        --token $ID_TOKEN
    

    输出类似以下内容:

      Error from server (Forbidden): namespaces is forbidden: User "ISG_GSA@PROJECT_ID.iam.gserviceaccount.com" cannot list resource "namespaces" in API group "" at the cluster scope
    

    这是意料之中的错误。虽然已向 Google 服务帐号授予了项目中 GKE 集群的 IAM 权限,但当您使用 Identity Service for GKE 进行身份验证时,IAM 权限并不适用。请改用 Kubernetes 基于角色的访问权限控制 (RBAC) 来配置访问权限。

  7. 创建一个集群角色绑定,在服务帐号使用 Google 的 OpenID Connect 提供方向集群进行身份验证时,向 Google 服务帐号授予 view 集群角色:

    kubectl create clusterrolebinding ISG_GSA-cluster-view \
        --clusterrole view \
        --user ISG_GSA@PROJECT_ID.iam.gserviceaccount.com
    

    如果您在自己的环境中的 ClientConfig 中设置了除 - 以外的 userPrefix 值,请将前缀添加到此命令中的 --user 标志的值中。

  8. 使用 Identity Service for GKE 访问 GKE 集群:

    kubectl get namespaces \
        --certificate-authority certificateAuthorityData.pem \
        --server $(cat server.txt) \
        --token $ID_TOKEN
    

    输出类似以下内容:

    NAME                      STATUS   AGE
    anthos-identity-service   Active   1h
    default                   Active   1h
    kube-node-lease           Active   1h
    kube-public               Active   1h
    kube-system               Active   1h
    
  9. 退出 SSH 会话:

    exit
    

kubectl 工具创建上下文

kubectl 命令可以使用 kubeconfig 文件配置对集群的访问权限。kubeconfig 文件包含一个或多个上下文。每个上下文都有一个名称,并且可以选择包含集群连接信息、用于向集群进行身份验证的凭据,以及默认命名空间。

在本部分中,您将创建一个具有上下文的 kubeconfig 文件。上下文包含集群的 Identity Service for GKE 代理的连接详细信息。请勿向 kubeconfig 文件添加任何用户凭据。

  1. 在 Cloud Shell 中,将包含证书授权机构数据和服务器网址的文件从虚拟机实例复制到当前目录:

    gcloud compute scp VM:~/certificateAuthorityData.pem VM:~/server.txt . \
        --tunnel-through-iap --zone ZONE
    
  2. 创建上下文和集群配置,稍后您将用其从 Cloud Build 连接到 GKE 集群:

    kubectl config set-context private-cluster \
        --cluster private-cluster \
        --kubeconfig kubeconfig
    

    --kubeconfig 标志会在当前目录中名为 kubeconfig 的新文件中创建上下文和集群配置。

    此命令使用 GKE 集群名称作为上下文的集群配置名称。在您自己的环境中,您可以在上下文中使用不同的集群配置名称。

  3. 在集群配置中设置 certificateAuthorityData 字段:

    kubectl config set-cluster private-cluster \
        --certificate-authority certificateAuthorityData.pem \
        --embed-certs \
        --kubeconfig kubeconfig
    
  4. 在集群配置中设置 server 字段:

    kubectl config set-cluster private-cluster \
        --kubeconfig kubeconfig \
        --server $(cat server.txt)
    

为 Cloud Build 创建 Google 服务帐号

  1. 在 Cloud Shell 中,创建一个 Google 服务帐号,以在 Cloud Build 专用池上运行构建:

    gcloud iam service-accounts create CB_GSA \
      --description "Runs builds on Cloud Build private pools" \
      --display-name "Cloud Build private pool"
    

    CB_GSA 替换为您要用于 Google 服务帐号的名称。在本教程中,请使用 cloud-build-private-pool

  2. 将项目的 Cloud Build 服务帐号角色授予 Google 服务帐号:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/cloudbuild.builds.builder
    

    此角色提供 Google 管理的 Cloud Build 服务帐号的默认权限

  3. 将 Google 服务帐号上的 Service Account OpenID Connect Identity Token Creator 授予服务帐号本身:

    gcloud iam service-accounts add-iam-policy-binding \
        CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.serviceAccountOpenIdTokenCreator
    

    此角色提供 iam.serviceAccounts.getOpenIdToken 权限,若要向 Service Account Credentials API 请求服务帐号的 ID 令牌,必须具有此权限。

  4. 使用 SSH 连接到虚拟机实例:

    gcloud compute ssh VM --tunnel-through-iap --zone ZONE
    

    您将通过 SSH 会话运行本部分中的其余命令。

  5. 在 SSH 会话中,创建一个 Kubernetes 集群角色绑定,在服务帐号使用 Google 的 OpenID Connect 提供方向集群进行身份验证时,向 Google 服务帐号授予 cluster-admin 集群角色:

    kubectl create clusterrolebinding CB_GSA-cluster-admin \
        --clusterrole cluster-admin \
        --user CB_GSA@PROJECT_ID.iam.gserviceaccount.com
    

    cluster-admin 集群角色可授予广泛的集群范围权限。在您自己的环境中,您可以使用一个集群角色,该角色仅提供 Cloud Build 执行任务所需的权限。您还可以使用角色绑定仅向特定命名空间授予权限。

    如果您在自己的环境中的 ClientConfig 中设置 userPrefix,则必须将该前缀添加到此命令中 --user 标志的值中。

  6. 退出 SSH 会话:

    exit
    

创建 Cloud Build 专用池

  1. 在 Cloud Shell 中,在 VPC 网络中为与专用池的连接分配一个 IP 地址范围:

    gcloud compute addresses create RESERVED_RANGE_NAME \
    --addresses RESERVED_RANGE_START_IP\
        --description "Cloud Build private pool reserved range" \
        --global \
        --network NETWORK \
        --prefix-length RESERVED_RANGE_PREFIX_LENGTH \
        --purpose VPC_PEERING
    

    替换以下内容:

    • RESERVED_RANGE_NAME:托管 Cloud Build 专用池的已分配 IP 地址范围的名称。在本教程中,请使用 cloud-build-private-pool
    • RESERVED_RANGE_START_IP:已分配的 IP 地址范围中的第一个 IP 地址。在本教程中,请使用 192.168.12.0
    • RESERVED_RANGE_PREFIX_LENGTH:已分配的 IP 地址范围的前缀长度(子网掩码)。前缀长度必须为 /23 或更小的数字,例如 /22/21。数字越小表示地址范围越大。在本教程中,请使用 23,且不要输入前导 /(正斜线)。
  2. 创建防火墙规则,以允许从预留 IP 地址范围流向 VPC 网络中的其他资源的入站流量:

    gcloud compute firewall-rules create allow-private-pools-ingress \
        --allow all \
        --network NETWORK \
        --source-ranges RESERVED_RANGE_START_IP/RESERVED_RANGE_PREFIX_LENGTH
    
  3. 创建专用服务连接,以将您的 VPC 网络连接到 Service Networking 服务:

    gcloud services vpc-peerings connect \
        --network NETWORK \
        --ranges RESERVED_RANGE_NAME \
        --service servicenetworking.googleapis.com
    

    Cloud Build 专用池使用 Service Networking 运行工作器。借助专用服务连接,您的 VPC 网络可以使用 VPC 网络对等互连连接与已分配的内部 IP 地址范围上的专用池进行通信。

    创建专用服务连接可能需要几分钟时间。

    如果您在自己的环境中使用共享 VPC,如需了解创建专用服务连接的其他步骤,请参阅设置您的环境

  4. 在 Google 拥有的与您的 VPC 网络对等互连的 VPC 网络中创建 Cloud Build 专用池:

    gcloud builds worker-pools create PRIVATE_POOL_NAME \
       --no-public-egress \
       --peered-network projects/PROJECT_ID/global/networks/NETWORK \
       --region REGION
    

    替换以下内容:

    • PRIVATE_POOL_NAME:专用池的名称。在本教程中,请使用 private-pool
    • REGION:用于专用池的区域。在本教程中,请使用 us-central1

    --no-public-egress 标志表示专用池中的工作器没有公共 IP 地址。在您自己的环境中,如果您希望专用池中的工作器使用公共 IP 地址进行互联网连接,可以移除此标志。

    如需了解其他配置选项(例如专用池中工作器的机器类型和磁盘大小),请参阅创建和管理专用池

验证解决方案

在本部分中,您将通过在 Cloud Build 专用池上运行构建来验证解决方案。构建访问专用 GKE 集群。

  1. 在 Cloud Shell 中,创建一个 Cloud Storage 存储桶,以存储来自 Cloud Build 的构建日志:

    gsutil mb -l REGION gs://PROJECT_ID-build-logs
    
  2. 为 Cloud Build 创建build 配置文件

    cat << "EOF" > cloudbuild.yaml
    steps:
    - id: list-services
      name: gcr.io/google.com/cloudsdktool/google-cloud-cli
      entrypoint: bash
      args:
      - -eEuo
      - pipefail
      - -c
      - |-
        kubectl config use-context $_KUBECTL_CONTEXT
    
        ACCESS_TOKEN=$$(curl --silent \
            --header "Metadata-Flavor: Google" \
            http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token \
            | python3 -c 'import json, sys; print(json.load(sys.stdin).get("access_token"))')
    
        ID_TOKEN=$$(curl --silent --request POST \
            --data '{"audience": "CLIENT_ID", "includeEmail": true}' \
            --header "Authorization: Bearer $$ACCESS_TOKEN" \
            --header "Content-Type: application/json; charset=utf-8" \
            "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$_SERVICE_ACCOUNT:generateIdToken" \
            | python3 -c 'import json, sys; print(json.load(sys.stdin).get("token"))')
    
        kubectl get services --namespace $_NAMESPACE --token $$ID_TOKEN
    
    logsBucket: gs://PROJECT_ID-build-logs
    
    options:
      env:
      - KUBECONFIG=/workspace/$_KUBECONFIG
    
    substitutions:
      _KUBECONFIG: kubeconfig
      _KUBECTL_CONTEXT: private-cluster
      _NAMESPACE: default
    
    serviceAccount: projects/$PROJECT_ID/serviceAccounts/$_SERVICE_ACCOUNT
    EOF
    

    build 配置文件中的步骤将执行以下操作:

    1. 切换到由 _KUBECTL_CONTEXT 替代变量指定的 kubectl 上下文。默认替换值为 private-cluster

    2. 从元数据服务器检索访问令牌。访问令牌将发放给运行构建的 Google 服务帐号。

    3. 使用 Service Account Credentials API 生成 ID 令牌。使用访问令牌对生成 ID 令牌的请求进行身份验证。所请求的 ID 令牌的 aud(目标设备)声明是由 _CLIENT_ID 替代项指定的 OAuth 2.0 客户端 ID。

    4. 列出由 _NAMESPACE 替代项指定的命名空间中的 Kubernetes 服务。默认替换值为 default。使用上一个命令中生成的 ID 令牌对请求进行身份验证。

    请注意有关 build 配置文件的以下事项:

    • $ 字符是替换的前缀。$$ 用于 bash 参数扩展和命令替换。

    • 使用 _KUBECONFIG_KUBECTL_CONTEXT 替代变量,可以在运行构建时指定不同的 kubeconfig 文件和不同的上下文。借助这些替代方法,您可以使用具有多个上下文的单个 kubeconfig 文件或使用多个 kubeconfig 文件,以便管理多个集群配置。

    • 替代变量 _SERVICE_ACCOUNT 没有默认值。运行构建时,您必须为此替换提供一个值。

    • options 代码块用于为构建中的所有步骤设置 KUBECONFIG 环境变量。

    • 构建步骤使用 gcr.io/google.com/cloudsdktool/google-cloud-cli 构建器映像。这是一个大型容器映像,需要一些时间才能将其从注册表中拉取到专用池工作器。为了缩短拉取构建器映像所需的时间,您可以创建自定义构建器映像,该映像仅包含构建步骤所需的工具,例如 curlkubectl 和 Python。

    如需详细了解 build 配置文件中的内嵌 Shell 脚本,请参阅运行 bash 脚本

  3. 使用 build 配置文件和当前目录中的文件运行 build:

    gcloud builds submit \
        --config cloudbuild.yaml \
        --region REGION \
        --substitutions _SERVICE_ACCOUNT=CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --worker-pool projects/PROJECT_ID/locations/REGION/workerPools/PRIVATE_POOL_NAME
    

    该命令会将当前目录中的所有文件上传到 Cloud Storage,以供 Cloud Build 使用。构建步骤使用 kubeconfig 文件连接到 GKE 集群。

    在输出内容的末尾附近,您会看到类似于以下内容的行:

    NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   2h
    

    此输出显示专用池工作器已使用 Identity Service for GKE 身份验证代理连接到集群控制平面。

问题排查

如果您无法使用 SSH 连接到虚拟机实例,请添加 --troubleshoot 标志以帮助发现连接问题的原因:

gcloud compute ssh VM --tunnel-through-iap --zone ZONE --troubleshoot

如果您在 GKE 集群上修补默认 ClientConfig 时收到 Error from server (NotFound): clientconfigs.authentication.gke.io "default" not found 消息,请确保您已按照创建专用 GKE 集群部分中的说明创建了防火墙规则。验证防火墙规则是否存在:

gcloud compute firewall-rules describe allow-control-plane-clientconfig-webhook

如果您无法向 Identity Service for GKE 代理进行身份验证,请在 gke-oidc-service 部署的 Pod 日志中查找错误:

gcloud compute ssh VM --tunnel-through-iap --zone ZONE --command \
    'kubectl logs deployment/gke-oidc-service \
         --namespace anthos-identity-service --all-containers'

如果您在使用本教程时遇到其他问题,建议您查看以下文档:

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

    删除 Google Cloud 项目:

    gcloud projects delete PROJECT_ID

删除资源

如果您希望保留在本教程中使用的项目,请删除各个资源:

  1. 在 Cloud Shell 中,删除 Cloud Build 专用池:

    gcloud builds worker-pools delete PRIVATE_POOL_NAME --region REGION --quiet
    
  2. 删除与 Service Networking 的专用服务连接:

    gcloud services vpc-peerings delete --network NETWORK \
      --service servicenetworking.googleapis.com --quiet --async
    
  3. 删除分配给 Cloud Build 专用池的 IP 地址范围:

    gcloud compute addresses delete RESERVED_RANGE_NAME --global --quiet
    
  4. 删除 Cloud Storage 存储桶及其所有内容:

    gsutil rm -r gs://PROJECT_ID-build-logs
    
  5. 删除 GKE 集群:

    gcloud container clusters delete CLUSTER --zone ZONE --quiet --async
    
  6. 删除 Compute Engine 虚拟机实例:

    gcloud compute instances delete VM --zone ZONE --quiet
    
  7. 删除防火墙规则:

    gcloud compute firewall-rules delete allow-private-pools-ingress --quiet
    
    gcloud compute firewall-rules delete allow-ssh-ingress-from-iap --quiet
    
    gcloud compute firewall-rules delete allow-control-plane-clientconfig-webhook --quiet
    
  8. 移除 IAM 角色绑定:

    gcloud projects remove-iam-policy-binding PROJECT_ID \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/cloudbuild.builds.builder
    
    gcloud projects remove-iam-policy-binding PROJECT_ID \
        --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/container.admin
    
    gcloud iam service-accounts remove-iam-policy-binding \
        CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.serviceAccountOpenIdTokenCreator
    
    gcloud iam service-accounts remove-iam-policy-binding \
        ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.serviceAccountOpenIdTokenCreator
    
  9. 删除 Google 服务账号:

    gcloud iam service-accounts delete CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
       --quiet
    
    gcloud iam service-accounts delete ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
       --quiet
    

删除 OAuth 2.0 客户端 ID

  1. 前往 Google Cloud 控制台中的凭据页面:

    打开“凭据”页面

  2. 从项目选择器列表中选择您的项目。

  3. OAuth 2.0 客户端 ID 表格中,找到 Identity Service for GKE 行,然后点击删除 OAuth 客户端图标。

  4. 在该对话框中,点击删除

后续步骤