IAM Roles for Service Accounts (IRSA) lets a pod on Amazon EKS assume an IAM role by exchanging its service account token through the cluster's OIDC provider. The role's trust policy decides which service accounts are allowed to do that.
The mistake: a trust policy that names the cluster's OIDC provider but leaves out the sub condition, or matches it with a wildcard such as system:serviceaccount:*:*. That trusts every service account in the cluster, so any pod that can obtain a token for the sts.amazonaws.com audience can assume the role.
Pin both claims exactly:
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:payments:payments-api",
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
}
}
Also:
- Use
StringEquals, notStringLike, unless you genuinely need a pattern, and then keep the pattern to one namespace. - Give each workload its own role. A role shared across service accounts shares its permissions too.
- Audit existing roles: look for trust policies that reference the cluster's OIDC provider without a
:subcondition. - EKS Pod Identity, the newer alternative, scopes roles through pod identity associations (namespace plus service account) rather than trust-policy conditions, which removes this particular mistake.
More context: Kubernetes and container security guardrails