排查集群安全问题


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

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

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

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

  1. 确保您已在包含 GKE 集群的项目中启用 IAM Service Account Credentials API。

    启用 IAM Credentials API

  2. 通过验证集群是否设置了工作负载身份池,确保已在集群上启用 Workload Identity。

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

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

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

    gcloud container node-pools describe NODEPOOL_NAME \
        --cluster=CLUSTER_NAME \
        --format="value(config.workloadMetadataConfig.mode)"
    
  4. 确保已正确注解 Kubernetes 服务账号:

    kubectl describe serviceaccount \
        --namespace NAMESPACE KSA_NAME
    

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

    iam.gke.io/gcp-service-account: GSA_NAME@PROJECT_ID.iam.gserviceaccount.com
    
  5. 确保 Google 服务账号正确配置:

    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 的集群,请确保允许传送至端口 80169.254.169.254/32 的出站流量。

    kubectl describe networkpolicy NETWORK_POLICY_NAME
    

Pod 启动时发生超时错误

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

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

  • 更新工作负载使用的 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 失败

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

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

dial tcp 35.232.136.58:443: connect: connection refused

这会导致 Workload Identity 不可用。

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

Workload Identity 失败

如果 GKE 元数据服务器由于某种原因被阻止,则 Workload Identity 将失败。

如果您使用的是 Istio,则应将以下应用级注解添加到使用 Workload Identity 的所有工作负载:

"traffic.sidecar.istio.io/excludeOutboundIPRanges=169.254.169.254/32"

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

gke-metadata-server Pod 崩溃

gke-metadata-server 系统的 DaemonSet Pod 有助于在节点上实现 Workload Identity。Pod 的内存资源用量与集群中的 Kubernetes 服务账号数量成正比。

gke-metadata-server Pod 的资源用量超出其限制时,会出现以下问题。kubelet 逐出 Pod 并报告内存不足错误。如果您的集群具有超过 3000 个 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
    

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

Workload Identity 未能启用,并显示 DeployPatch 失败的错误消息

GKE 使用 Google Cloud 管理的 Kubernetes Engine Service Agent 辅助集群中的 Workload Identity。启用 Google Kubernetes Engine API 时,Google Cloud 会自动就您的项目向此服务代理授予 Kubernetes Engine Service Agent 角色 (roles/container.serviceAgent)。

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

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 项目编号。

尝试再次启用 Workload Identity。