Kubetier
← Permission Reference
T2

patch serviceaccounts

Annotations on a ServiceAccount are the join point between cluster identity and an external identity provider.

The annotation grants nothing on its own.

It takes effect only where the provider has already been configured to trust this namespace and ServiceAccount name, which RBAC cannot arrange.

Contextual upgrade to T0:

T0 if an external identity provider already trusts this namespace and ServiceAccount name. The annotation then binds pods to that identity and its permissions outside the cluster become reachable from inside it.

Establishing that trust is not a Kubernetes operation, so no RBAC grant can create this precondition; it is a property of the surrounding platform.

API Group
(core)
Scope
namespaced
Audit Level
RequestResponse

Escalation Paths

  1. With patch or update on a namespaced object, set metadata.ownerReferences to point at an owner that does not exist, using a resolvable apiVersion and kind with any name and UID.

  2. The garbage collector resolves the reference, confirms the owner is absent, and deletes the object within seconds on the next sync.

  3. No delete permission on the object is required, and no ownership check runs unless the OwnerReferencesPermissionEnforcement admission plugin is enabled, which it is not by default.

  4. Applies to any namespaced resource the principal can patch or update, turning patch rights into a deletion primitive for objects that delete access would otherwise gate.

Additional rights needed:

none

Note:

Distinct from CVE-2025-5187 (node self-patch to a cluster-scoped owner, patched).

This is intended behavior for namespaced objects, not a CVE, gated only by the OwnerReferencesPermissionEnforcement admission plugin, which is not enabled by default.

K8s docs ↗
  1. An IAM role must already exist whose trust policy names the cluster OIDC provider and conditions on sub system:serviceaccount:<namespace>:<name> plus aud sts.amazonaws.com

  2. The IAM role trusts the cluster OIDC provider and evaluates whatever token claims its trust policy names, most commonly the subject and the audience

  3. Those conditions are policy specific rather than built into IRSA, and the ServiceAccount annotation takes no part in the authorization decision

  4. A pod running under that ServiceAccount, projecting a serviceAccountToken with audience sts.amazonaws.com, receives an assertion STS accepts

  5. AssumeRoleWithWebIdentity is unauthenticated, so the exchange needs no AWS credentials and returns whatever the role itself grants

  6. create serviceaccounts/token mints the same assertion with no pod involved, and the credentials work from outside the cluster

  7. The eks.amazonaws.com/role-arn annotation only drives the pod-identity-webhook, which injects at admission and so never reaches running pods

  8. That annotation is also the discovery path, since it names the role and the ServiceAccount it trusts, and reading it needs only list serviceaccounts

Additional rights needed:

Note:

Not a defect and nothing to patch.

The IAM trust policy is the anchor, so an audit that looks only for the eks.amazonaws.com/role-arn annotation misses every variant that bypasses the webhook.

K8s docs ↗
  1. An IAM policy binding must already grant this namespace and ServiceAccount roles/iam.workloadIdentityUser on the target GCP service account

  2. Add the iam.gke.io/gcp-service-account annotation naming that service account.

    A raw PATCH needs patch alone.

    The get that kubectl sends first is a CLI artifact

  3. Already-running pods pick up the new identity within seconds with no restart, so no pod-level access is needed and recycling pods is not a mitigation

  4. Tokens then carry exactly that service account IAM roles, so its cloud permissions become reachable from inside the cluster

Additional rights needed:

none
K8s docs ↗
K8s docs ↗