排查 GKE 身份验证问题


本页面介绍如何解决与 Google Kubernetes Engine (GKE) Autopilot 和标准集群中的安全配置相关的问题。

如果您需要其他帮助,请与 Cloud Customer Care 联系。

RBAC 和 IAM

经过身份验证的 IAM 账号无法执行集群内操作

如果您尝试在集群中执行操作,但 GKE 找不到授权该操作的 RBAC 政策,就会发生以下问题。GKE 会尝试查找授予相同权限的 IAM 允许政策。如果失败,您会看到类似于以下内容的错误消息:

Error from server (Forbidden): roles.rbac.authorization.k8s.io is forbidden:
User "example-account@example-project.iam.gserviceaccount.com" cannot list resource "roles" in
API group "rbac.authorization.k8s.io" in the namespace "kube-system": requires
one of ["container.roles.list"] permission(s).

如需解决此问题,请使用 RBAC 政策为尝试的操作授予权限。例如,如需解决上面示例中的问题,请授予一个对 kube-system 命名空间中的 roles 对象具有 list 权限的角色。如需了解相关说明,请参阅使用基于角色的访问权限控制向集群中的操作授权

Workload Identity Federation for GKE

Pod 无法向 Google Cloud 进行身份验证

如果您的应用无法向 Google Cloud 进行身份验证,请确保正确配置以下设置:

  1. 检查您是否已在包含 GKE 集群的项目中启用 IAM Service Account Credentials API。

    启用 IAM Credentials API

  2. 通过验证集群是否设置了工作负载身份池,确认是否已在集群上启用了适用于 GKE 的工作负载身份联合:

    gcloud container clusters describe CLUSTER_NAME \
        --format="value(workloadIdentityConfig.workloadPool)"
    

    CLUSTER_NAME 替换为 GKE 集群的名称。

    如果您尚未指定 gcloud 的默认可用区或区域,则您还可能需要在运行此命令时指定 --region--zone 标志。

  3. 确保已在运行应用的节点池上配置 GKE 元数据服务器:

    gcloud container node-pools describe NODEPOOL_NAME \
        --cluster=CLUSTER_NAME \
        --format="value(config.workloadMetadataConfig.mode)"
    

    替换以下内容:

    • NODEPOOL_NAME 替换为您的节点池的名称。
    • CLUSTER_NAME 替换为您的 GKE 集群的名称。
  4. 确认已正确注解 Kubernetes 服务账号:

    kubectl describe serviceaccount \
        --namespace NAMESPACE KSA_NAME
    

    替换以下内容:

    • NAMESPACE 替换为您的 GKE 集群的命名空间。
    • KSA 替换为您的 Kubernetes 服务账号的名称。

    预期输出包含类似于以下内容的注解:

    iam.gke.io/gcp-service-account: GSA_NAME@PROJECT_ID.iam.gserviceaccount.com
    
  5. 检查 IAM 服务账号是否已正确配置:

    gcloud iam service-accounts get-iam-policy \
        GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com
    

    预期输出包含类似于以下内容的绑定:

    - members:
      - serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]
      role: roles/iam.workloadIdentityUser
    
  6. 如果您制定了集群网络政策,则对于运行 1.21.0-gke.1000 之前的 GKE 版本的集群,您必须允许端口 988 上流向 127.0.0.1/32 的出站流量,或对于运行 GKE 1.21.0-gke.1000 及更高版本的集群,您必须允许端口 988 上流向 169.254.169.252/32 的出站流量。对于运行 GKE Dataplane V2 的集群,您必须允许端口 80 上流向 169.254.169.254/32 的出站流量。

    kubectl describe networkpolicy NETWORK_POLICY_NAME
    

    NETWORK_POLICY_NAME 替换为 GKE 网络政策的名称。

IAM 服务账号访问遭拒

在添加 IAM 角色绑定后,Pod 可能无法立即使用适用于 GKE 的工作负载身份联合访问资源。在部署流水线或声明式 Google Cloud 配置(其中会同时创建 IAM 允许政策、角色绑定和 Kubernetes Pod 等资源)中,更有可能发生访问失败。Pod 日志中会显示以下错误消息:

HTTP/403: generic::permission_denied: loading: GenerateAccessToken("SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com", ""): googleapi: Error 403: Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).

此错误可能是由 IAM 中的访问权限更改传播引起的,这意味着访问权限更改(如角色授予)需要一段时间才能传播到整个系统。对于角色授予,传播通常需要大约两分钟,但有时可能需要七分钟或更长时间。如需了解详情,请参阅访问权限更改传播

如需解决此错误,请考虑在创建后 Pod 尝试访问 Google Cloud 资源之前添加延迟。

DNS 解析问题

某些 Google Cloud 客户端库配置为通过解析 DNS 名称 metadata.google.internal 来连接到 GKE 和 Compute Engine 元数据服务器;对于这些库,运行状况良好的集群内 DNS 解析是工作负载向 Google Cloud 服务进行身份验证的关键依赖项。

如何检测此问题取决于所部署的应用的详细信息,包括其日志记录配置。查找符合以下条件的错误消息:

  • 告知您配置 GOOGLE_APPLICATION_CREDENTIALS,或者
  • 告知您对 Google Cloud 服务的请求被拒绝,因为请求没有凭据。

如果您在 metadata.google.internal 的 DNS 解析方面遇到问题,可以通过将环境变量 GCE_METADATA_HOST 设置为 169.254.169.254 来指示某些 Google Cloud 客户端库跳过 DNS 解析:

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
  namespace: default
spec:
  containers:
  - image: debian
    name: main
    command: ["sleep", "infinity"]
    env:
    - name: GCE_METADATA_HOST
      value: "169.254.169.254"

这是硬编码 IP 地址,始终可通过该地址在 Google Cloud 计算平台上访问元数据服务。

支持的 Google Cloud 库:

  • Python
  • Java
  • Node.js
  • Golang(但请注意,Golang 客户端库已首选通过 IP 地址而不是 DNS 名称进行连接)。

Pod 启动时发生超时错误

GKE 元数据服务器需要几秒钟的时间才能开始在 Pod 上接受新请求。对于配置了较短超时的应用和 Google Cloud 客户端库,尝试在 Pod 生命周期内的前几秒内使用适用于 GKE 的工作负载身份联合进行身份验证可能会失败。

如果您遇到超时错误,请尝试以下操作:

  • 更新工作负载使用的 Google Cloud 客户端库。
  • 更改应用代码,等待几秒钟,然后重试。
  • 部署 initContainer,等待 GKE 元数据服务器运行完毕,然后再运行 Pod 的主容器。

    例如,以下清单适用于具有 initContainer 的 Pod:

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-with-initcontainer
    spec:
      serviceAccountName: KSA_NAME
      initContainers:
      - image:  gcr.io/google.com/cloudsdktool/cloud-sdk:alpine
        name: workload-identity-initcontainer
        command:
        - '/bin/bash'
        - '-c'
        - |
          curl -sS -H 'Metadata-Flavor: Google' 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token' --retry 30 --retry-connrefused --retry-max-time 60 --connect-timeout 3 --fail --retry-all-errors > /dev/null && exit 0 || echo 'Retry limit exceeded. Failed to wait for metadata server to be available. Check if the gke-metadata-server Pod in the kube-system namespace is healthy.' >&2; exit 1
      containers:
      - image: gcr.io/your-project/your-image
        name: your-main-application-container
    

由于控制平面不可用,Workload Identity Federation for GKE 失败

当集群控制平面不可用时,元数据服务器无法返回 Workload Identity Federation for GKE。对元数据服务器的调用会返回状态代码 500。

日志条目在日志浏览器中可能类似于以下内容:

dial tcp 35.232.136.58:443: connect: connection refused

此行为会导致适用于 GKE 的工作负载身份联合不可用。

在集群维护(例如轮替 IP 地址、升级控制平面虚拟机或者调整集群或节点池的大小)期间,控制平面可能在可用区集群上无法使用。请参阅选择区域控制平面或可用区控制平面,以了解控制平面可用性。切换到区域级集群可以消除此问题。

在使用 Istio 的集群中,Workload Identity Federation for GKE 身份验证失败

如果 GKE 元数据服务器由于某种原因被阻止,则适用于 GKE 的工作负载身份联合身份验证会失败。

如果您使用的是 Istio 或 Cloud Service Mesh,请将以下 Pod 级注解添加到使用适用于 GKE 的工作负载身份联合的所有工作负载,以从重定向中排除该 IP 地址:

traffic.sidecar.istio.io/excludeOutboundIPRanges: 169.254.169.254/32

您可以更改 global.proxy.excludeIPRanges Istio ConfigMap 键来执行相同的操作。

或者,您也可以将以下 Pod 级注解添加到使用适用于 GKE 工作负载身份联合的所有工作负载,以延迟应用容器启动,直到辅助信息文件准备就绪:

proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'

您可以更改 global.proxy.holdApplicationUntilProxyStarts Istio ConfigMap 键来执行相同的操作。

gke-metadata-server Pod 崩溃

gke-metadata-server 系统 DaemonSet Pod 有助于在您的节点上实现适用于 GKE 的工作负载身份联合。Pod 的内存资源用量与集群中的 Kubernetes 服务账号数量成正比。

gke-metadata-server Pod 的资源用量超出其限制时,会出现以下问题。kubelet 逐出 Pod 并报告内存不足错误。如果您的集群具有超过 3,000 个 Kubernetes 服务账号,则可能会出现此问题。

如需找出此问题,请执行以下操作:

  1. kube-system 命名空间中找到发生崩溃的 gke-metadata-server Pod:

    kubectl get pods -n=kube-system | grep CrashLoopBackOff
    

    输出类似于以下内容:

    NAMESPACE     NAME                        READY     STATUS             RESTARTS   AGE
    kube-system   gke-metadata-server-8sm2l   0/1       CrashLoopBackOff   194        16h
    kube-system   gke-metadata-server-hfs6l   0/1       CrashLoopBackOff   1369       111d
    kube-system   gke-metadata-server-hvtzn   0/1       CrashLoopBackOff   669        111d
    kube-system   gke-metadata-server-swhbb   0/1       CrashLoopBackOff   30         136m
    kube-system   gke-metadata-server-x4bl4   0/1       CrashLoopBackOff   7          15m
    
  2. 执行以下命令获取发生崩溃的 Pod 的描述,确认崩溃是否由于发生内存不足逐出所导致:

    kubectl describe pod POD_NAME --namespace=kube-system | grep OOMKilled
    

    POD_NAME 替换为要检查的 Pod 的名称。

如需使 GKE 元数据服务器恢复正常工作,请将集群中的服务账号数量减少到小于 3,000 个。

Workload Identity Federation for GKE 无法启用,并显示 DeployPatch 失败的错误消息

GKE 使用 Google Cloud 管理的 Kubernetes Engine Service Agent 实现集群中适用于 GKE 的工作负载身份联合。启用 Google Kubernetes Engine API 时,Google Cloud 会自动就您的项目向此服务代理授予 Kubernetes Engine Service Agent 角色 (roles/container.serviceAgent)。

如果您尝试在服务代理没有 Kubernetes Engine Service Agent 角色的项目中对集群上启用适用于 GKE 的工作负载身份联合,操作将失败并显示类似于以下内容的错误消息:

Error waiting for updating GKE cluster workload identity config: DeployPatch failed

如需解决此问题,请尝试执行以下步骤:

  1. 检查项目中是否存在服务代理,以及配置是否正确:

    gcloud projects get-iam-policy PROJECT_ID \
        --flatten=bindings \
        --filter=bindings.role=roles/container.serviceAgent \
        --format="value[delimiter='\\n'](bindings.members)"
    

    PROJECT_ID 替换为您的 Google Cloud 项目 ID。

    如果服务代理配置正确,则输出会显示服务代理的完整身份:

    serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
    

    如果输出未显示服务代理,您必须向其授予 Kubernetes Engine Service Agent 角色。 如需授予此角色,请完成以下步骤。

  2. 获取 Google Cloud 项目编号:

    gcloud projects describe PROJECT_ID \
        --format="value(projectNumber)"
    

    输出类似于以下内容:

    123456789012
    
  3. 向该服务代理授予角色:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com \
        --role=roles/container.serviceAgent \
        --condition=None
    

    PROJECT_NUMBER 替换为您的 Google Cloud 项目编号。

  4. 尝试再次启用适用于 GKE 的工作负载身份联合。

后续步骤

如果您需要其他帮助,请与 Cloud Customer Care 联系。