本页面介绍如何解决与 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 进行身份验证,请确保正确配置以下设置:
检查您是否已在包含 GKE 集群的项目中启用 IAM Service Account Credentials API。
通过验证集群是否设置了工作负载身份池,确认是否已在集群上启用了适用于 GKE 的工作负载身份联合:
gcloud container clusters describe CLUSTER_NAME \ --format="value(workloadIdentityConfig.workloadPool)"
将
CLUSTER_NAME
替换为 GKE 集群的名称。如果您尚未指定
gcloud
的默认可用区或区域,则您还可能需要在运行此命令时指定--region
或--zone
标志。确保已在运行应用的节点池上配置 GKE 元数据服务器:
gcloud container node-pools describe NODEPOOL_NAME \ --cluster=CLUSTER_NAME \ --format="value(config.workloadMetadataConfig.mode)"
替换以下内容:
- 将
NODEPOOL_NAME
替换为您的节点池名称。 - 将
CLUSTER_NAME
替换为您的 GKE 集群的名称。
- 将
确认已正确注解 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
- 将
检查 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
如果您制定了集群网络政策,则对于运行 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 库:
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 身份验证失败
当应用启动并尝试与端点通信时,您可能会看到类似于以下内容的错误:
Connection refused (169.254.169.254:80)
Connection timeout
如果应用在 istio-proxy
容器准备就绪之前尝试建立网络连接,可能会出现这些错误。默认情况下,Istio 和 Cloud Service Mesh 允许工作负载在启动后立即发送请求,无论拦截和重定向流量的服务网格代理工作负载是否正在运行。对于使用适用于 GKE 的工作负载身份联合的 Pod,代理启动之前发生的这些初始请求可能无法到达 GKE 元数据服务器。因此,向 Google Cloud API 进行身份验证会失败。如果您未将应用配置为重试请求,您的工作负载可能会失败。
如需确认此问题是导致错误的原因,请查看日志并检查 istio-proxy
容器是否已成功启动:
在 Google Cloud 控制台中,转到日志浏览器页面。
在查询窗格中,输入以下查询:
(resource.type="k8s_container" resource.labels.pod_name="POD_NAME" textPayload:"Envoy proxy is ready" OR textPayload:"ERROR_MESSAGE") OR (resource.type="k8s_pod" logName:"events" jsonPayload.involvedObject.name="POD_NAME")
替换以下内容:
POD_NAME
:包含受影响工作负载的 Pod 的名称。ERROR_MESSAGE
:应用收到的错误(connection timeout
或connection refused
)。
点击运行查询。
查看输出,并检查
istio-proxy
容器何时准备就绪。在以下示例中,应用尝试发出 gRPC 调用。但是,由于
istio-proxy
容器仍在初始化,应用收到了Connection refused
错误。Envoy proxy is ready
消息旁边的时间戳表示istio-proxy
容器何时准备好处理连接请求:2024-11-11T18:37:03Z started container istio-init 2024-11-11T18:37:12Z started container gcs-fetch 2024-11-11T18:37:42Z Initializing environment 2024-11-11T18:37:55Z Started container istio-proxy 2024-11-11T18:38:06Z StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: Connection refused (169.254.169.254:80) 2024-11-11T18:38:13Z Envoy proxy is ready
如需解决此问题并防止其再次出现,请尝试以下任一按工作负载配置选项:
在代理工作负载准备就绪之前,阻止应用发送请求。将以下注解添加到 Pod 规范中的
metadata.annotations
字段:proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
配置 Istio 或 Cloud Service Mesh,将 GKE 元数据服务器的 IP 地址从重定向中排除。将以下注解添加到 Pod 规范的
metadata.annotations
字段中:traffic.sidecar.istio.io/excludeOutboundIPRanges: 169.254.169.254/32
在开源 Istio 中,您可以选择通过设置以下全局配置选项之一来缓解所有 Pod 存在的这个问题:
将 GKE 元数据服务器 IP 地址从重定向中排除:更新
global.proxy.excludeIPRanges
全局配置选项以添加169.254.169.254/32
IP 地址范围。在代理启动之前阻止应用发送请求:将值为
true
的global.proxy.holdApplicationUntilProxyStarts
全局配置选项添加到 Istio 配置中。
gke-metadata-server
Pod 崩溃
gke-metadata-server
系统 DaemonSet Pod 有助于在您的节点上实现适用于 GKE 的工作负载身份联合。Pod 的内存资源用量与集群中的 Kubernetes 服务账号数量成正比。
当 gke-metadata-server
Pod 的资源用量超出其限制时,会出现以下问题。kubelet 逐出 Pod 并报告内存不足错误。如果您的集群具有超过 3,000 个 Kubernetes 服务账号,则可能会出现此问题。
如需找出此问题,请执行以下操作:
在
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
执行以下命令获取发生崩溃的 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
如需解决此问题,请尝试执行以下步骤:
检查项目中是否存在服务代理,以及配置是否正确:
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 角色。 如需授予此角色,请完成以下步骤。
获取 Google Cloud 项目编号:
gcloud projects describe PROJECT_ID \ --format="value(projectNumber)"
输出类似于以下内容:
123456789012
向该服务代理授予角色:
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 项目编号。尝试再次启用适用于 GKE 的工作负载身份联合。