Kubetier
← Permission Reference
T2

create serviceaccounts

A new ServiceAccount carries no permissions, so the risk is not the object but what can be annotated onto it.

Where an external identity provider already trusts a namespace and ServiceAccount name, creating that exact name claims the identity.

Contextual upgrade to T0:

T0 if an external identity provider already trusts this namespace and ServiceAccount name. Pods then run with that identity, and its permissions outside the cluster become reachable from inside it. The link can be an annotation or a policy naming the namespace and name directly.

Establishing that trust is not a Kubernetes operation, so no RBAC grant can create this precondition.

API Group
(core)
Scope
namespaced
Audit Level
RequestResponse

Escalation Paths

  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:

  • · any one; running a pod under the bound ServiceAccount claims the role, and setting serviceAccountName needs no permission on the object

  • · any one; mints the assertion directly, with no pod and no node

  • · scoped to a trust policy whose subject names a ServiceAccount that does not exist yet

    · squatting the bound name, then running under it

  • · scoped to using the webhook rather than a hand-built projection

    · patch alone is not enough on EKS, since injection happens at pod admission

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 ↗
  1. A federated identity credential must already exist on the managed identity, naming the cluster OIDC issuer and system:serviceaccount:<namespace>:<name> as its subject

  2. Entra matches that credential on issuer and subject alone, so the ServiceAccount name is the whole secret and no annotation takes part in the trust decision

  3. A pod running under that ServiceAccount, projecting a serviceAccountToken with audience api://AzureADTokenExchange, receives an assertion Entra accepts

  4. Exchanging the assertion returns an access token for the managed identity, carrying every Azure role assigned to it

  5. create serviceaccounts/token mints the same assertion with no pod involved, and the token it buys is usable from outside the cluster

  6. The pod label azure.workload.identity/use and the ServiceAccount client-id annotation only drive the addon webhook, a convenience for applications rather than the control

Additional rights needed:

  • · any one; running a pod under the bound ServiceAccount claims the identity, and setting serviceAccountName needs no permission on the object

  • · any one; mints the assertion directly, with no pod and no node

  • · scoped to a federated credential whose subject names a ServiceAccount that does not exist yet

    · squatting the bound name, then running under it

Note:

Not a defect and nothing to patch.

The federated credential is the trust anchor, so an audit that looks only for the azure.workload.identity annotation misses every variant that does not use the addon webhook.

K8s docs ↗
  1. An IAM policy must already bind a role to the principal identifier for this namespace and ServiceAccount name in the cluster workload identity pool

  2. No annotation and no cloud service account are involved, which is the current recommended configuration rather than a legacy one

  3. IAM never checks that the ServiceAccount exists, so the binding can predate the object and the name can be squatted

  4. Creating a ServiceAccount with the bound name, or running a pod under it, claims the identity

  5. Pods then obtain tokens for that principal carrying the roles bound to it, with no annotation anywhere in the chain

Additional rights needed:

none

Note:

Not a defect and nothing to fix.

Binding IAM directly to the pool principal is the documented current approach, so the annotation-based path is the legacy one.

Auditing only for the annotation misses this entirely.

K8s docs ↗
K8s docs ↗