gke-workload-identity
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGKE Workload Identity Federation Troubleshooting Skill
GKE Workload Identity Federation 故障排查 Skill
Use this skill to systematically diagnose why a Pod using Workload Identity
Federation for GKE cannot authenticate to Google Cloud APIs. Typical symptoms:
HTTP/403 ... Permission 'iam.serviceAccounts.getAccessToken' denied on resource- /
google.auth.exceptions ... could not find default credentialsComputeEngineCredentials cannot find the metadata server - API calls that unexpectedly use the node's default Compute Engine service account instead of the workload's identity.
使用此 skill 系统地诊断为什么使用 Workload Identity Federation for GKE 的 Pod 无法向 Google Cloud API 进行身份验证。典型症状:
HTTP/403 ... Permission 'iam.serviceAccounts.getAccessToken' denied on resource- /
google.auth.exceptions ... could not find default credentialsComputeEngineCredentials cannot find the metadata server - API 调用意外使用节点的默认 Compute Engine service account,而不是工作负载的身份。
Read-only boundary
只读边界
This skill is diagnostic and non-interactive. It only reads cluster,
IAM, and logging state and proposes fixes as commands or GitOps manifest
changes for a human to apply. It must never create or modify IAM bindings,
KSA annotations, node pools, or clusters automatically. When evidence is missing
or the fix requires a privileged change, summarize findings and hand off to a
human (see Step 7).
此 skill 是诊断性、非交互式的。它只读取集群、IAM 和日志状态,并将修复方案作为命令或 GitOps manifest 变更建议给人工执行。它绝不自动创建或修改 IAM 绑定、KSA 注解、节点池或集群。当证据缺失或修复需要特权变更时,汇总发现并交给人工(参见步骤 7)。
Output discipline (apply to every conclusion)
输出纪律(适用于每个结论)
When you report a diagnosis, always:
- Name the single most-likely root cause (not an open-ended list of possibilities).
- Explicitly rule out the other plausible causes, citing the evidence that excludes them. In particular, when the cause is node-pool configuration, state plainly that it is not a KSA annotation or IAM binding problem; when the cause is a missing role on a target resource, state that Workload Identity itself is not misconfigured.
- Give the exact remediation as a proposed change for a human — a concrete
command (or GitOps manifest edit) with the real identifiers filled in — and never apply it automatically.
gcloud
报告诊断时,始终:
- 指出最可能的单一根因(而不是开放式的可能性列表)。
- 明确排除其他可能的诱因,并引用排除它们的证据。特别是当原因是节点池配置时,明确说明它不是 KSA 注解或 IAM 绑定问题;当原因是目标资源缺少角色时,说明 Workload Identity 本身没有配置错误。
- 给出供人工执行的精确修复建议 —— 带有真实标识符的具体 命令(或 GitOps manifest 编辑),且绝不自动应用。
gcloud
Diagnostic Workflow
诊断工作流
Step 0: Context discovery & time window
步骤 0:上下文发现与时间窗口
Collect (from the user or the failing resource): , ,
, cluster , , the KSA the Pod runs as, the
node and node pool the Pod is scheduled on (used in Step 2), the target
resource / API being called, and the exact error string. Define a time
window around the first observed failure for log queries.
PROJECT_IDPROJECT_NUMBERCLUSTERLOCATIONNAMESPACEbash
undefined从用户或失败资源收集:、、、集群 、、Pod 运行所用的 KSA、Pod 调度到的节点和节点池(步骤 2 中使用)、被调用的目标资源 / API,以及确切的错误字符串。围绕首次观察到失败的时间定义一个时间窗口,用于日志查询。
PROJECT_IDPROJECT_NUMBERCLUSTERLOCATIONNAMESPACEbash
undefinedResolve the project number (used in the direct-binding principal identifier).
Resolve the project number (used in the direct-binding principal identifier).
gcloud projects describe "{PROJECT_ID}" --format="value(projectNumber)"
gcloud projects describe "{PROJECT_ID}" --format="value(projectNumber)"
Confirm which KSA the workload runs as.
Confirm which KSA the workload runs as.
kubectl get pod "{pod_name}" -n "{namespace}"
-o jsonpath='{.spec.serviceAccountName}'
-o jsonpath='{.spec.serviceAccountName}'
kubectl get pod "{pod_name}" -n "{namespace}"
-o jsonpath='{.spec.serviceAccountName}'
-o jsonpath='{.spec.serviceAccountName}'
Identify the node the Pod runs on, then the node pool that node belongs to
Identify the node the Pod runs on, then the node pool that node belongs to
(Step 2 checks the node pool's Workload Identity mode).
(Step 2 checks the node pool's Workload Identity mode).
NODE=$(kubectl get pod "{pod_name}" -n "{namespace}" -o jsonpath='{.spec.nodeName}')
kubectl get node "$NODE"
-o jsonpath='{.metadata.labels.cloud.google.com/gke-nodepool}'
-o jsonpath='{.metadata.labels.cloud.google.com/gke-nodepool}'
--------------------------------------------------------------------------------NODE=$(kubectl get pod "{pod_name}" -n "{namespace}" -o jsonpath='{.spec.nodeName}')
kubectl get node "$NODE"
-o jsonpath='{.metadata.labels.cloud.google.com/gke-nodepool}'
-o jsonpath='{.metadata.labels.cloud.google.com/gke-nodepool}'
--------------------------------------------------------------------------------Step 1: Capture the exact error signature
步骤 1:捕获确切的错误特征
Read the workload's own logs and the logs to classify the
failure.
gke-metadata-serverbash
kubectl logs "{pod_name}" -n "{namespace}" --all-containers --prefix
kubectl describe pod "{pod_name}" -n "{namespace}"Equivalent via Cloud Logging (preferred for historical events). Open it as a
Logs Explorer deep link — URL-encode the query and append the project and
time window:
(encode as , or use for a rolling hour):
https://console.cloud.google.com/logs/query;query={URL_ENCODED_QUERY};timeRange={start}%2F{end}?project={project_id}/%2F;duration=PT1Hresource.type="k8s_container"
resource.labels.namespace_name="{namespace}"
resource.labels.pod_name="{pod_name}"
severity>=WARNINGClassify the signature:
- denied /
iam.serviceAccounts.getAccessToken→ the workload is using the GSA impersonation path. This is expected for the legacy setup, but if you intend to use direct binding, it means the KSA still carries a leftoverHTTP/403annotation (or the client SDK is configured to impersonate) and is unintentionally impersonating a GSA; go to Step 3.iam.gke.io/gcp-service-account - on the target API/resource (no
403 PERMISSION_DENIEDin the error) → the resolved identity lacks the required IAM role on that resource; go to Step 4.getAccessToken - /
could not find default credentials→ metadata-server connectivity or a startup race; go to Step 5.cannot find the metadata server - Calls succeed but as the node default service account → Workload Identity is not in effect for this node pool; go to Step 2.
读取工作负载自己的日志和 日志,对失败进行分类。
gke-metadata-serverbash
kubectl logs "{pod_name}" -n "{namespace}" --all-containers --prefix
kubectl describe pod "{pod_name}" -n "{namespace}"等效地通过 Cloud Logging(对于历史事件优先):以 Logs Explorer 深层链接打开 —— 对查询进行 URL 编码并附加项目和时间窗口:
(将 编码为 ,或使用 表示滚动一小时):
https://console.cloud.google.com/logs/query;query={URL_ENCODED_QUERY};timeRange={start}%2F{end}?project={project_id}/%2F;duration=PT1Hresource.type="k8s_container"
resource.labels.namespace_name="{namespace}"
resource.labels.pod_name="{pod_name}"
severity>=WARNING对特征签名进行分类:
- denied /
iam.serviceAccounts.getAccessToken→ 工作负载正在使用 GSA 模拟路径。这在旧版设置中是预期的;但如果你打算使用直接绑定,则意味着 KSA 仍带有遗留的HTTP/403注解(或客户端 SDK 被配置为模拟),并在无意中模拟一个 GSA;转至步骤 3。iam.gke.io/gcp-service-account - 在目标 API/资源上出现 (错误中没有
403 PERMISSION_DENIED)→ 解析后的身份缺少该资源上所需的 IAM 角色;转至步骤 4。getAccessToken - /
could not find default credentials→ metadata 服务器连通性或启动竞态;转至步骤 5。cannot find the metadata server - 调用成功但以节点默认 service account身份执行 → Workload Identity 未在该节点池上生效;转至步骤 2。
Step 2: Verify Workload Identity is enabled (cluster + node pool)
步骤 2:验证 Workload Identity 已启用(集群 + 节点池)
Both the cluster and the node pool the Pod runs on must have Workload
Identity enabled. A node pool with (instead of )
causes Pods to fall back to the node's default Compute Engine service account.
GCE_METADATAGKE_METADATAbash
undefined集群和 Pod 所在的节点池都必须启用 Workload Identity。节点池使用 (而不是 )会导致 Pod 回退到节点的默认 Compute Engine service account。
GCE_METADATAGKE_METADATAbash
undefinedCluster must have a workload identity pool (PROJECT_ID.svc.id.goog).
Cluster must have a workload identity pool (PROJECT_ID.svc.id.goog).
gcloud container clusters describe "{cluster}" --location "{location}"
--format="value(workloadIdentityConfig.workloadPool)"
--format="value(workloadIdentityConfig.workloadPool)"
gcloud container clusters describe "{cluster}" --location "{location}"
--format="value(workloadIdentityConfig.workloadPool)"
--format="value(workloadIdentityConfig.workloadPool)"
Node pool must have workloadMetadataConfig.mode = GKE_METADATA.
Node pool must have workloadMetadataConfig.mode = GKE_METADATA.
gcloud container node-pools describe "{node_pool}" --cluster "{cluster}"
--location "{location}"
--format="value(config.workloadMetadataConfig.mode)"
--location "{location}"
--format="value(config.workloadMetadataConfig.mode)"
- Empty workload pool → Workload Identity is **not enabled on the cluster**.
- Node-pool mode is `GCE_METADATA` (or empty) → the node pool is **not** using
the GKE metadata server; this is the usual cause of "runs as the node
default service account". Remediation: enable
`--workload-metadata=GKE_METADATA` on the node pool (propose to a human;
recreates nodes). This is a **node-pool configuration** problem — not a KSA
annotation or IAM binding problem — so do not change KSA annotations or IAM
bindings to fix it. When the symptom is "runs as the node default service
account", say so explicitly: the root cause is the node pool's
`workloadMetadataConfig.mode`, and the KSA annotation and IAM bindings are
**ruled out** as the cause. Propose the exact fix, e.g.:
```bash
gcloud container node-pools update "{node_pool}" --cluster "{cluster}" \
--location "{location}" --workload-metadata=GKE_METADATAgcloud container node-pools describe "{node_pool}" --cluster "{cluster}"
--location "{location}"
--format="value(config.workloadMetadataConfig.mode)"
--location "{location}"
--format="value(config.workloadMetadataConfig.mode)"
- 空的 workload pool → Workload Identity **未在集群上启用**。
- 节点池模式为 `GCE_METADATA`(或为空)→ 节点池**未**使用 GKE metadata 服务器;这通常是“以节点默认 service account 运行”的诱因。修复:在节点池上启用 `--workload-metadata=GKE_METADATA`(建议给人工;会重建节点)。这是一个**节点池配置**问题——不是 KSA 注解或 IAM 绑定问题——因此不要通过修改 KSA 注解或 IAM 绑定来修复它。当症状是“以节点默认 service account 运行”时,请明确说明:根因是节点池的 `workloadMetadataConfig.mode`,KSA 注解和 IAM 绑定**被排除**为诱因。建议精确修复,例如:
```bash
gcloud container node-pools update "{node_pool}" --cluster "{cluster}" \
--location "{location}" --workload-metadata=GKE_METADATAStep 3: Verify the KSA → identity binding
步骤 3:验证 KSA → 身份绑定
There are two supported models. Prefer direct binding (current default);
treat GSA impersonation as the legacy path.
How the two models fail differently: with direct binding the KSA principal accesses resources directly, so failures show up as a plainon the target API (fix in Step 4). A403 PERMISSION_DENIEDinstead means an impersonation attempt — intended under the legacy path, or unintended if a leftover403 iam.serviceAccounts.getAccessTokenannotation remains on a KSA that was meant to use direct binding.iam.gke.io/gcp-service-account
(a) Direct KSA binding (no GSA impersonation). The KSA principal is granted
roles directly. Construct the principal identifier and search for its bindings:
principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{PROJECT_ID}.svc.id.goog/subject/ns/{NAMESPACE}/sa/{KSA_NAME}(b) Legacy: KSA + GSA impersonation. The KSA must be annotated to point at a
GSA, and the KSA must hold on that GSA.
roles/iam.workloadIdentityUserbash
undefined有两种受支持的模型。优先使用直接绑定(当前默认);将 GSA 模拟视为旧版路径。
两种模型如何以不同方式失败: 使用直接绑定时,KSA 主体直接访问资源,因此失败表现为目标 API 上的普通(在步骤 4 修复)。出现403 PERMISSION_DENIED则意味着模拟尝试——在旧版路径下是有意的,或者如果原本应使用直接绑定的 KSA 上遗留有403 iam.serviceAccounts.getAccessToken注解,则是无意的。iam.gke.io/gcp-service-account
(a) 直接 KSA 绑定(无 GSA 模拟)。 KSA 主体被直接授予角色。构造主体标识符并搜索其绑定:
principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{PROJECT_ID}.svc.id.goog/subject/ns/{NAMESPACE}/sa/{KSA_NAME}(b) 旧版:KSA + GSA 模拟。 KSA 必须被注解以指向一个 GSA,并且 KSA 必须持有该 GSA 上的 。
roles/iam.workloadIdentityUserbash
undefinedThe KSA annotation must reference the intended GSA.
The KSA annotation must reference the intended GSA.
kubectl get serviceaccount "{ksa_name}" -n "{namespace}"
-o jsonpath='{.metadata.annotations.iam.gke.io/gcp-service-account}'
-o jsonpath='{.metadata.annotations.iam.gke.io/gcp-service-account}'
kubectl get serviceaccount "{ksa_name}" -n "{namespace}"
-o jsonpath='{.metadata.annotations.iam.gke.io/gcp-service-account}'
-o jsonpath='{.metadata.annotations.iam.gke.io/gcp-service-account}'
The GSA's IAM policy must bind the KSA member to workloadIdentityUser.
The GSA's IAM policy must bind the KSA member to workloadIdentityUser.
gcloud iam service-accounts get-iam-policy
"{gsa_name}@{project_id}.iam.gserviceaccount.com"
--format=json
"{gsa_name}@{project_id}.iam.gserviceaccount.com"
--format=json
gcloud iam service-accounts get-iam-policy
"{gsa_name}@{project_id}.iam.gserviceaccount.com"
--format=json
"{gsa_name}@{project_id}.iam.gserviceaccount.com"
--format=json
Expect a binding: role roles/iam.workloadIdentityUser,
Expect a binding: role roles/iam.workloadIdentityUser,
member serviceAccount:{PROJECT_ID}.svc.id.goog[{NAMESPACE}/{KSA_NAME}]
member serviceAccount:{PROJECT_ID}.svc.id.goog[{NAMESPACE}/{KSA_NAME}]
> If the annotation is present but the binding is missing, the binding was
> likely removed — check the `setIamPolicy` audit logs around the failure time
> to find the responsible principal.
--------------------------------------------------------------------------------
> 如果注解存在但绑定缺失,则绑定很可能已被移除——检查失败时间附近的 `setIamPolicy` 审计日志,以找到负责的主体。
--------------------------------------------------------------------------------Step 4: Verify IAM permissions on the target resource
步骤 4:验证目标资源上的 IAM 权限
Even with a correct binding, the identity (the KSA principal for direct binding,
or the GSA for legacy) must hold the role required by the API call (for example
). The standard IAM Policy Troubleshooter has
limited support for Workload Identity principals; use Cloud Asset Inventory to
search all IAM policies for the principal instead.
roles/storage.objectViewerbash
undefined即使绑定正确,身份(直接绑定为 KSA 主体,旧版为 GSA)也必须持有 API 调用所需的角色(例如 )。标准 IAM Policy Troubleshooter 对 Workload Identity 主体支持有限;请改用 Cloud Asset Inventory 搜索所有 IAM 策略中该主体的绑定。
roles/storage.objectViewerbash
undefinedDirect binding: search for the KSA principal's bindings across the project.
Direct binding: search for the KSA principal's bindings across the project.
gcloud asset search-all-iam-policies
--scope="projects/{PROJECT_ID}"
--query='policy:"{PROJECT_ID}.svc.id.goog"'
--scope="projects/{PROJECT_ID}"
--query='policy:"{PROJECT_ID}.svc.id.goog"'
gcloud asset search-all-iam-policies
--scope="projects/{PROJECT_ID}"
--query='policy:"{PROJECT_ID}.svc.id.goog"'
--scope="projects/{PROJECT_ID}"
--query='policy:"{PROJECT_ID}.svc.id.goog"'
Legacy: search for the GSA's bindings on the target resource's project.
Legacy: search for the GSA's bindings on the target resource's project.
gcloud asset search-all-iam-policies
--scope="projects/{TARGET_PROJECT_ID}"
--query='policy:"{gsa_name}@{project_id}.iam.gserviceaccount.com"'
--scope="projects/{TARGET_PROJECT_ID}"
--query='policy:"{gsa_name}@{project_id}.iam.gserviceaccount.com"'
If no binding grants the required role on the target resource, **that missing
role is the root cause** (and Workload Identity itself is **not**
misconfigured). Present the fix as a **proposed change for a human to apply** —
the exact `add-iam-policy-binding` with the real principal and role — never
applying it automatically. For example, for direct binding on a project-level
resource:
```bash
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}" # e.g. roles/storage.objectViewergcloud asset search-all-iam-policies
--scope="projects/{TARGET_PROJECT_ID}"
--query='policy:"{gsa_name}@{project_id}.iam.gserviceaccount.com"'
--scope="projects/{TARGET_PROJECT_ID}"
--query='policy:"{gsa_name}@{project_id}.iam.gserviceaccount.com"'
如果没有绑定在目标资源上授予所需角色,**缺失的角色就是根因**(并且 Workload Identity 本身**没有**配置错误)。将修复作为**供人工执行的建议变更**呈现 —— 带有真实主体和角色的精确 `add-iam-policy-binding` —— 绝不自动应用。例如,对于项目级资源上的直接绑定:
```bash
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}" # e.g. roles/storage.objectViewerStep 5: GKE metadata server & connectivity
步骤 5:GKE metadata 服务器与连通性
Applies when the signature is , , or a connection/timeout error. The
DaemonSet (in ) brokers the token exchange on each node; requests
to are redirected to it, so a Pod fails closed if it cannot
reach a healthy metadata-server Pod on its node.
could not find the metadata servercannot find the metadata servergke-metadata-serverkube-system169.254.169.254(a) Check gke-metadata-server Pod health on the workload's node.
bash
undefined当特征为 、 或连接/超时错误时适用。 DaemonSet(位于 )在每个节点上代理 token 交换;对 的请求被重定向到它,因此如果 Pod 无法到达其节点上健康的 metadata-server Pod,就会 fail closed(无法访问时安全失败)。
could not find the metadata servercannot find the metadata servergke-metadata-serverkube-system169.254.169.254(a) 检查工作负载节点上的 gke-metadata-server Pod 健康状况。
bash
undefinedThe DaemonSet Pods must be healthy on the workload's node.
The DaemonSet Pods must be healthy on the workload's node.
kubectl get pods -n kube-system -l k8s-app=gke-metadata-server -o wide
kubectl get pods -n kube-system -l k8s-app=gke-metadata-server -o wide
A gke-metadata-server Pod can be OOM-evicted when the cluster has many
A gke-metadata-server Pod can be OOM-evicted when the cluster has many
(>3,000) Kubernetes service accounts. Look for CrashLoopBackOff, then confirm
(>3,000) Kubernetes service accounts. Look for CrashLoopBackOff, then confirm
the eviction was OOMKilled.
the eviction was OOMKilled.
kubectl get pods -n kube-system | grep CrashLoopBackOff
kubectl describe pod {gke_metadata_server_pod} --namespace=kube-system | grep OOMKilled
**(b) Inspect the `gke-metadata-server` logs** (historical, via Cloud Logging;
open as a Logs Explorer deep link, see Step 1):
resource.type="k8s_container"
resource.labels.namespace_name="kube-system"
labels."k8s-pod/k8s-app"="gke-metadata-server"
severity>=WARNING
**(c) Connectivity test** from the affected Pod — it must reach the metadata
server and (for some client libraries) resolve its DNS name:
```bashkubectl get pods -n kube-system | grep CrashLoopBackOff
kubectl describe pod {gke_metadata_server_pod} --namespace=kube-system | grep OOMKilled
**(b) 检查 `gke-metadata-server` 日志**(历史日志通过 Cloud Logging;打开为 Logs Explorer 深层链接,参见步骤 1):
resource.type="k8s_container"
resource.labels.namespace_name="kube-system"
labels."k8s-pod/k8s-app"="gke-metadata-server"
severity>=WARNING
**(c) 从受影响的 Pod 进行连通性测试** —— 它必须能到达 metadata 服务器,并且(对于某些客户端库)解析其 DNS 名称:
```bashToken endpoint via the hardcoded metadata IP (a healthy path returns a token).
Token endpoint via the hardcoded metadata IP (a healthy path returns a token).
kubectl exec {pod_name} -n {namespace} --
curl -sS -H 'Metadata-Flavor: Google'
'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
curl -sS -H 'Metadata-Flavor: Google'
'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
Possible causes:
- **Startup race**: the metadata server needs a few seconds after a Pod
starts. Applications that authenticate immediately may fail; the fix is
application-side retries or an `initContainer` that waits for the metadata
server, not a cluster change.
- **DNS**: some client libraries resolve `metadata.google.internal`; broken
in-cluster DNS surfaces as `cannot find the metadata server`. As a
workaround, set `GCE_METADATA_HOST=169.254.169.254` to skip DNS resolution.
- **Network policy / egress**: a cluster network policy must allow egress to
`169.254.169.254/32` on port `80` (GKE Dataplane V2), or
`169.254.169.252/32` on port `988`. A default-deny egress rule that blocks
HTTPS to the public Security Token Service (`sts.googleapis.com:443`)
produces `504 Gateway Timeout` or `context deadline exceeded`.
- **`gke-metadata-server` crashing / high restarts**: see (a) — reduce the
number of Kubernetes service accounts (<3,000) to restore functionality.
--------------------------------------------------------------------------------kubectl exec {pod_name} -n {namespace} --
curl -sS -H 'Metadata-Flavor: Google'
'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
curl -sS -H 'Metadata-Flavor: Google'
'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
可能的原因:
- **启动竞态**:Pod 启动后 metadata 服务器需要几秒钟。立即进行身份验证的应用可能会失败;修复方式是应用侧重试或一个等待 metadata 服务器的 `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` 崩溃 / 频繁重启**:参见 (a) —— 减少 Kubernetes service account 的数量(<3,000)以恢复功能。
--------------------------------------------------------------------------------Step 6: "Invalid form of account ID" edge case (legacy GSA impersonation)
步骤 6:“Invalid form of account ID” 边缘情况(旧版 GSA 模拟)
Applies only to the legacy GSA impersonation setup (a KSA annotated with), not to direct principal binding.iam.gke.io/gcp-service-account
Signature: an operation that requires an IAM service account email (for
example, manually creating a Cloud Storage signed URL) fails with:
ERROR: Invalid form of account ID SERVICEACCOUNT_NAME.svc.id.goog.
Should be [Gaia ID | Email | Unique ID | ] of the accountCause: for a KSA linked to a GSA via annotation, the GKE metadata server by
default returns as the identifier, which is
not a valid IAM service account email. This is not a missing IAM binding and
does not require reverting the setup.
SERVICEACCOUNT_NAME.svc.id.googFix (propose to a human): add the
annotation to the Pod's KSA so
the metadata server returns the identity in the expected form:
iam.gke.io/return-principal-id-as-email="true"bash
kubectl annotate serviceaccount "{ksa_name}" --namespace "{namespace}" \
iam.gke.io/return-principal-id-as-email="true"仅适用于旧版 GSA 模拟设置(KSA 带有注解),不适用于直接主体绑定。iam.gke.io/gcp-service-account
特征:需要 IAM service account email 的操作(例如手动创建 Cloud Storage signed URL)失败并报:
ERROR: Invalid form of account ID SERVICEACCOUNT_NAME.svc.id.goog.
Should be [Gaia ID | Email | Unique ID | ] of the account原因:对于通过注解链接到 GSA 的 KSA,GKE metadata 服务器默认返回 作为标识符,而这不是有效的 IAM service account email。这不是缺少 IAM 绑定,也不需要回退该设置。
SERVICEACCOUNT_NAME.svc.id.goog修复(建议给人工):在 Pod 的 KSA 上添加 注解,使 metadata 服务器以预期形式返回身份:
iam.gke.io/return-principal-id-as-email="true"bash
kubectl annotate serviceaccount "{ksa_name}" --namespace "{namespace}" \
iam.gke.io/return-principal-id-as-email="true"Step 7: Remediation boundary & escalation
步骤 7:修复边界与升级
- Present the root cause + evidence (the exact error, the missing binding / annotation / node-pool mode, or the metadata-server state). Include a Cloud Logging deep link (see Step 1) to the supporting entries.
- Propose the fix as a command or GitOps manifest change for a human to apply — never modify IAM, KSAs, or node pools automatically.
Escalate (instead of proposing more self-service diagnostics) when either:
- the relevant logs are unavailable (excluded by a filter, or past the log bucket's retention); or
- the identity/binding is correct, the target-resource IAM is correct, and the metadata server is healthy, yet the failure persists (undetermined root cause).
In those cases: state the limitation plainly, summarize the findings gathered
(cluster/node-pool config, bindings, annotations, metadata-server state, and any
audit logs), and route to GKE support / engineering escalation.
Do not fabricate a diagnosis when evidence is missing.
setIamPolicy- 呈现根因 + 证据(确切的错误、缺失的绑定 / 注解 / 节点池模式,或 metadata-server 状态)。包含指向支持性日志条目的 Cloud Logging 深层链接(参见步骤 1)。
- 将修复作为供人工执行的命令或 GitOps manifest 变更提出——绝不自动修改 IAM、KSA 或节点池。
升级(而不是提出更多自助诊断)当出现以下任一情况:
- 相关日志不可用(被过滤器排除,或已超过日志桶保留期);或
- 身份/绑定正确、目标资源 IAM 正确、metadata 服务器健康,但失败仍然持续(根因未确定)。
在这些情况下:明确说明限制,汇总已收集的发现(集群/节点池配置、绑定、注解、metadata-server 状态,以及任何 审计日志),并转交 GKE 支持 / 工程升级。当证据缺失时不要编造诊断。
setIamPolicyReferences
参考文档
This skill is derived from public Google Cloud documentation:
- Troubleshoot GKE authentication issues
— the Workload Identity Federation section: WI-enabled check, KSA
annotation, ,
roles/iam.workloadIdentityUser403,iam.serviceAccounts.getAccessToken, metadata-server DNS and theiam.gke.io/return-principal-id-as-emailPod is crashing guidance.gke-metadata-server - About Workload Identity Federation for GKE — identities, the GKE metadata server, and why Pods don't inherit the node identity.
- Configure applications to use Workload Identity Federation for GKE
— node-pool , the direct-binding
--workload-metadata=GKE_METADATAidentifier, and the legacyprincipal://...member format.serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME] - Search IAM policies (Cloud Asset Inventory)
— for auditing a principal's bindings.
gcloud asset search-all-iam-policies - View GKE logs — Cloud Logging queries for workload and system logs.
此 skill 源自 Google Cloud 公开文档:
- Troubleshoot GKE authentication issues —— Workload Identity Federation 部分:WI 启用检查、KSA 注解、、
roles/iam.workloadIdentityUser403、iam.serviceAccounts.getAccessToken、metadata-server DNS,以及iam.gke.io/return-principal-id-as-emailPod 崩溃 的指引。gke-metadata-server - About Workload Identity Federation for GKE —— 身份、GKE metadata 服务器,以及 Pod 为何不继承节点身份。
- Configure applications to use Workload Identity Federation for GKE —— 节点池 、直接绑定的
--workload-metadata=GKE_METADATA标识符,以及旧版principal://...成员格式。serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME] - Search IAM policies (Cloud Asset Inventory) —— 使用 审计一个主体的绑定。
gcloud asset search-all-iam-policies - View GKE logs —— 用于工作负载和系统日志的 Cloud Logging 查询。