运维部署
GKE Pod 无法认证 Google Cloud API…
当 GKE Pod 使用 Workload Identity Federation 却无法认证 Google Cloud API(403 getAccessToken、找不到默认凭据、metadata server 不可达)时,系统性诊断根因并给出人工执行的修复方案。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
GKE Pod 无法认证 Google 特定
解决思路
- 先做上下文发现与时间窗口界定:收集 PROJECT_ID、PROJECT_NUMBER、CLUSTER、集群 LOCATION、NAMESPACE、Pod 使用的 KSA、Pod 所在节点与节点池、被调用的目标资源/API 以及确切错误字符串,并围绕首次故障时间定义日志查询窗口;用 gcloud projects describe "{PROJECT_ID}" --format="value(projectNumber)" 解析项目编号,用 kubectl get pod "{pod_name}" -n "{namespace}" -o jsonpath='{.spec.serviceAccountName}' 确认 KSA,用 kubectl get pod ... -o jsonpath='{.spec.nodeName}' 取节点再用 kubectl get node "$NODE" -o jsonpath='{.metadata.labels.cloud\.google\.com/gke-nodepool}' 取节点池。
- 捕获确切错误签名:用 kubectl logs "{pod_name}" -n "{namespace}" --all-containers --prefix 和 kubectl describe pod 读取工作负载日志,并查看 gke-metadata-server 日志;历史事件优先用 Cloud Logging,构造 Logs Explorer 深链 https://console.cloud.google.com/logs/query;query={URL_ENCODED_QUERY};timeRange={start}%2F{end}?project={project_id}(/ 编码为 %2F,或用 ;duration=PT1H),查询 resource.type="k8s_container" resource.labels.namespace_name="{namespace}" resource.labels.pod_name="{pod_name}" severity>=WARNING。
- 按签名分类故障:出现 iam.serviceAccounts.getAccessToken 被拒 / HTTP/403 说明走的是 GSA 模拟路径,若本意是直接绑定则说明 KSA 上残留了 iam.gke.io/gcp-service-account 注解(或客户端 SDK 配置为模拟),转 Step 3;目标 API/资源上的 403 PERMISSION_DENIED(错误中无 getAccessToken)说明解析出的身份缺少该资源所需 IAM 角色,转 Step 4;could not find default credentials / cannot find the metadata server 说明 metadata server 连通性或启动竞态问题,转 Step 5;调用成功但用的是节点默认服务账号,说明该节点池未生效 Workload Identity,转 Step 2。
- 验证集群与节点池是否启用 Workload Identity:用 gcloud container clusters describe "{cluster}" --location "{location}" --format="value(workloadIdentityConfig.workloadPool)" 检查集群是否有 workload identity pool(PROJECT_ID.svc.id.goog);用 gcloud container node-pools describe "{node_pool}" --cluster "{cluster}" --location "{location}" --format="value(config.workloadMetadataConfig.mode)" 检查节点池模式是否为 GKE_METADATA。若 workload pool 为空则集群未启用;若节点池模式为 GCE_METADATA 或为空,则节点池未使用 GKE metadata server,这是“以节点默认服务账号运行”的常见原因,属于节点池配置问题而非 KSA 注解或 IAM 绑定问题,不要改 KSA 注解或 IAM 绑定,向人工提议执行 gcloud container node-pools update "{node_pool}" --cluster "{cluster}" --location "{location}" --workload-metadata=GKE_METADATA(会重建节点)。
- 验证 KSA 到身份的绑定,区分两种模型并优先直接绑定(当前默认),把 GSA 模拟视为遗留路径:直接绑定下 KSA principal 直接访问资源,失败表现为目标 API 上的普通 403 PERMISSION_DENIED(在 Step 4 修复);若出现 403 iam.serviceAccounts.getAccessToken 则说明发生了模拟——遗留路径下属预期,但若本意是直接绑定则说明 KSA 上残留了 iam.gke.io/gcp-service-account 注解。
- 对直接 KSA 绑定,构造 principal 标识 principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{PROJECT_ID}.svc.id.goog/subject/ns/{NAMESPACE}/sa/{KSA_NAME} 并搜索其绑定。
- 对遗留的 KSA + GSA 模拟,用 kubectl get serviceaccount "{ksa_name}" -n "{namespace}" -o jsonpath='{.metadata.annotations.iam\.gke\.io/gcp-service-account}' 确认 KSA 注解指向预期的 GSA,并用 gcloud iam service-accounts get-iam-policy "{gsa_name}@{project_id}.iam.gserviceaccount.com" --format=json 检查 GSA 的 IAM policy 是否把 KSA 成员绑定到 roles/iam.workloadIdentityUser(期望 member 为 serviceAccount:{PROJECT_ID}.svc.id.goog[{NAMESPACE}/{KSA_NAME}]);若注解存在但绑定缺失,绑定可能被移除,检查故障时间附近的 setIamPolicy 审计日志找出责任主体。
- 验证目标资源上的 IAM 权限:即使绑定正确,身份(直接绑定为 KSA principal,遗留为 GSA)也必须持有 API 调用所需的角色(如 roles/storage.objectViewer)。标准 IAM Policy Troubleshooter 对 Workload Identity principal 支持有限,改用 Cloud Asset Inventory 搜索:直接绑定用 gcloud asset search-all-iam-policies --scope="projects/{PROJECT_ID}" --query='policy:"{PROJECT_ID}.svc.id.goog"';遗留用 gcloud asset search-all-iam-policies --scope="projects/{TARGET_PROJECT_ID}" --query='policy:"{gsa_name}@{project_id}.iam.gserviceaccount.com"'。若无绑定授予所需角色,则缺失角色即根因(Workload Identity 本身未配置错误),把修复作为人工执行的提议变更给出,例如直接绑定在项目级资源上执行 gcloud projects add-iam-policy-binding "{TARGET_PROJECT_ID}" --member="principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{PROJECT_ID}.svc.id.goog/subject/ns/{NAMESPACE}/sa/{KSA_NAME}" --role="{REQUIRED_ROLE}",绝不自动应用。
- 处理 GKE metadata server 与连通性问题(签名为 could not find the metadata server、cannot find the metadata server 或连接/超时错误):用 kubectl get pods -n kube-system -l k8s-app=gke-metadata-server -o wide 检查工作负载所在节点上的 DaemonSet Pod 是否健康;集群 KSA 数量超过 3000 时 gke-metadata-server Pod 可能被 OOM 驱逐,用 kubectl get pods -n kube-system | grep CrashLoopBackOff 查找,再用 kubectl describe pod {gke_metadata_server_pod} --namespace=kube-system | grep OOMKilled 确认驱逐原因为 OOMKilled。
- 用 Cloud Logging 检查 gke-metadata-server 日志(历史,Logs Explorer 深链见 Step 1),查询 resource.type="k8s_container" resource.labels.namespace_name="kube-system" labels."k8s-pod/k8s-app"="gke-metadata-server" severity>=WARNING。
- 从受影响 Pod 做连通性测试:kubectl exec {pod_name} -n {namespace} -- curl -sS -H 'Metadata-Flavor: Google' 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token',必须能到达 metadata server,某些客户端库还需能解析其 DNS 名。可能原因:启动竞态(metadata server 在 Pod 启动后需数秒,立即认证的应用会失败,修复方式是应用侧重试或加等待 metadata server 的 initContainer,而非改集群);DNS(部分客户端库解析 metadata.google.internal,集群内 DNS 故障表现为 cannot find the metadata server,可设 GCE_METADATA_HOST=169.254.169.254 绕过 DNS);网络策略/出站(集群网络策略必须允许到 169.254.169.254/32 端口 80(GKE Dataplane V2)或 169.254.169.252/32 端口 988 的出站,默认拒绝出站若阻断到公共 Security Token Service sts.googleapis.com:443 的 HTTPS 会产生 504 Gateway Timeout 或 context deadline exceeded);gke-metadata-server 崩溃/重启过多(见前,减少 KSA 数量至 3000 以下以恢复)。
- 处理“Invalid form of account ID”边界情况(仅适用于遗留 GSA 模拟,即 KSA 带 iam.gke.io/gcp-service-account 注解,不适用于直接 principal 绑定):当需要 IAM 服务账号邮箱的操作(如手动创建 Cloud Storage 签名 URL)失败并报 ERROR: Invalid form of account ID SERVICEACCOUNT_NAME.svc.id.goog. Should be [Gaia ID | Email | Unique ID | ] of the account 时,原因是 GKE metadata server 默认返回 SERVICEACCOUNT_NAME.svc.id.goog 作为标识,不是合法的 IAM 服务账号邮箱;这不是缺少 IAM 绑定,也不需要回退配置。修复(向人工提议):给 Pod 的 KSA 添加注解 kubectl annotate serviceaccount "{ksa_name}" --namespace "{namespace}" iam.gke.io/return-principal-id-as-email="true",让 metadata server 返回预期形式的身份。
- 遵守修复边界与升级:给出根因 + 证据(确切错误、缺失的绑定/注解/节点池模式或 metadata server 状态),附上支撑日志条目的 Cloud Logging 深链;把修复作为命令或 GitOps manifest 变更提议给人工执行,绝不自动修改 IAM、KSA 或节点池。当相关日志不可用(被过滤器排除或超出日志桶保留期),或身份/绑定正确、目标资源 IAM 正确、metadata server 健康但故障依旧(根因未定)时,应升级:明确说明限制,汇总已收集的发现(集群/节点池配置、绑定、注解、metadata server 状态及任何 setIamPolicy 审计日志),转交 GKE 支持/工程升级;证据缺失时不要编造诊断。
- 对每个结论遵守输出纪律:只指出单一最可能的根因(而非开放式罗列可能性);明确排除其他可能原因并引用排除证据,尤其当根因是节点池配置时明确说明不是 KSA 注解或 IAM 绑定问题,当根因是目标资源缺少角色时明确说明 Workload Identity 本身未配置错误;把确切修复作为提议变更交给人工,给出填好真实标识的具体 gcloud 命令(或 GitOps manifest 修改),绝不自动应用。
- 保持只读边界:本流程仅诊断、非交互,只读取集群、IAM 和日志状态,并以命令或 GitOps manifest 变更的形式提议修复供人工应用,绝不自动创建或修改 IAM 绑定、KSA 注解、节点池或集群;证据缺失或修复需要特权变更时,汇总发现并转交人工。
适用边界 · 注意事项
- 不适用于集群内 Kubernetes RBAC 错误(API server 授权问题)。
- 不适用于一般工作负载崩溃(应使用 gke-workload-troubleshooting)。
- 不适用于 Workload Identity 的初始设置与加固(应使用 gke-workload-security)。