Amazon EKS Pod Identity and IRSA Decision Guide - Workload Identity Design, Trade-offs, and Migration Paths

First Published:
Last Updated:

Amazon EKS has two supported mechanisms for giving a Pod its own AWS credentials, and they solve the same problem in fundamentally different ways. IAM roles for service accounts (IRSA) arrived in September 2019 and works entirely through IAM's OpenID Connect federation: the cluster publishes a signed token, the AWS SDK exchanges it with AWS STS, and the Pod receives credentials for a role whose trust policy names the cluster's OIDC provider. EKS Pod Identity arrived at re:Invent 2023 and works through an EKS-native API: you record an association between a Kubernetes service account and an IAM role, an agent on the node exchanges the Pod's token with the EKS Auth API, and the Pod receives credentials for a role that trusts a single service principal. Both are current, both are supported, and most real clusters run both at once for a while.

This guide is a decision guide first and an operations manual second. Section 5 puts the two mechanisms side by side, Section 6 turns that into an ordered decision, and — because the loudest advice in circulation is "just use Pod Identity" — Section 6 also states plainly where IRSA is still the correct answer, using the conditions AWS itself lists in the EKS Best Practices Guide. The rest of the article goes where a feature comparison stops: how each credential path actually works, how to design roles so a compromised Pod cannot borrow another Pod's permissions, how cross-account and multi-cluster patterns differ between the two, how to migrate with a rollback at every step, and what each mechanism looks like in CloudTrail when you are trying to find out which Pod made a call.

This is a moving target, so dates matter. Every behavior, quota, requirement, and availability statement below was checked against the Amazon EKS User Guide, the Amazon EKS Best Practices Guide, the Amazon EKS API Reference, and AWS What's New announcements on 2026-07-31, and the relevant announcement dates are stated inline. Capability boundaries in this area have moved several times — cross-account target roles in June 2025, session policies in March 2026, AWS PrivateLink for the cluster OIDC endpoint in July 2026 — so re-check the linked pages before you act on anything here. This guide contains no pricing figures, and it describes configuration rather than reporting measurements: the manifests and policies below follow the documented specifications and are not presented as the output of a test cluster.

Table of Contents

  1. 1. Introduction: Why Pod Credentials Became a Design Decision
  2. 2. The Problem: Giving AWS Permissions to Pods
  3. 3. How IRSA Works
  4. 4. How EKS Pod Identity Works
  5. 5. Side-by-Side Comparison
  6. 6. Choosing Between Them
  7. 7. Least-Privilege Role Design
  8. 8. Multi-Cluster and Multi-Account Patterns
  9. 9. Migration Path
  10. 10. Observability and Auditing
  11. 11. Failure Modes and Anti-Patterns
  12. 12. Frequently Asked Questions
  13. 13. Summary
  14. 14. References

1. Introduction: Why Pod Credentials Became a Design Decision

For the first years of managed Kubernetes on AWS, the answer to "how does this Pod call Amazon S3?" was "it uses the node's role." That answer is operationally simple and architecturally wrong: every Pod scheduled onto a node inherits the union of every permission any Pod on that node needs. A batch job that reads one bucket ends up sharing an instance profile with an ingress controller that can create load balancers. IRSA was introduced in 2019 precisely to break that coupling, and the AWS announcement framed it exactly that way — before it, "every pod that ran on the node inherited the same IAM role," which "made it hard to run pods with different access control requirements on the same set of nodes."

Four years later, EKS Pod Identity was introduced to address a second-order problem that only appears at scale: IRSA's per-cluster OIDC provider and per-role trust policy make the administration of workload identity grow with the number of clusters. Add a cluster and you touch every role that workload uses. Reach a hundred clusters in an account and you reach an IAM limit. Pod Identity moves the cluster-to-role mapping out of IAM trust policies and into an EKS API, so a role can serve any number of clusters without being edited.

Neither mechanism replaced the other. AWS's own guidance is layered: the User Guide comparison page says AWS "recommends using EKS Pod Identities to grant access to AWS resources to your pods whenever possible," while the Best Practices Guide says "EKS Pod Identities are recommended for new applications running on supported node types and IRSA is a good fit where you already have OIDC and IRSA in place or run on platforms that EKS Pod Identities do not support." Read together, those are a recommendation with a documented exception list — and the exception list is the reason this article exists.

The audience is the platform engineer or SRE who has an IRSA estate that works, is being asked whether to move, and needs to answer with something better than a preference. The scope is deliberately the identity mechanism itself:
  • Pod networking, the Amazon VPC CNI, IP address management, and security groups for Pods are covered in the sibling article, the Amazon EKS Networking Deep Dive. This guide only touches networking where it blocks a credential path.
  • The order in which identity policies, resource policies, SCPs, RCPs, permission boundaries, and session policies combine is covered in IAM Policy Evaluation Logic Step-by-Step. This guide writes policies; it does not re-derive the evaluation order.
  • The launch history of Amazon EKS belongs to the AWS History and Timeline regarding Amazon EKS. Dates appear here only as constraints on what you can rely on.
  • Cluster access — how a human or a CI role authenticates to the Kubernetes API through access entries or the aws-auth ConfigMap — is a different axis entirely and is only distinguished from workload identity, not explained. Kubernetes RBAC is likewise treated at overview level.
  • No pricing. The trade-offs below are expressed in quotas, throttling behavior, blast radius, and operational steps.

2. The Problem: Giving AWS Permissions to Pods

2.1 What the node role actually grants

A worker node is an Amazon EC2 instance with an instance profile. Anything running on that instance that can reach the Instance Metadata Service (IMDS) can retrieve credentials for the node IAM role. On a default Amazon EKS node that role carries permissions the data plane needs — pulling images from Amazon ECR, and, in secondary IP mode, attaching network interfaces and assigning addresses through AmazonEKS_CNI_Policy. The EKS Best Practices Guide is blunt about the consequence: those policies "effectively allow all pods running on a node to attach/detach ENIs, assign/unassign IP addresses, or pull images from ECR."

Before 2019, the workarounds were third-party proxies such as kiam and kube2iam, which intercepted IMDS traffic and vended per-Pod credentials. Both IRSA and Pod Identity are documented as eliminating the need for those, and both list the same three benefits: least privilege scoped to a service account, credential isolation when IMDS access is restricted, and auditability through AWS CloudTrail.

2.2 The isolation you do not get for free

Two caveats in the official documentation deserve to be read before any design work, because both mechanisms carry them identically.

The first is that enabling IRSA or Pod Identity does not remove the node role from the Pod. Both mechanisms insert themselves earlier in the AWS SDK credential provider chain than the instance profile, so the Pod uses the workload role by default — but the instance profile is still reachable. The Best Practices Guide states it directly: the Pod "can still inherit the rights of the instance profile assigned to the worker node." Blocking that requires restricting IMDS, typically by requiring IMDSv2 and setting the PUT response hop limit to 1 so a container cannot reach metadata through the node's network namespace. That change has a real side effect, which the same page flags as a warning: it "will prevent pods that do not use IRSA or EKS Pod Identities from inheriting the role assigned to the worker node." If any DaemonSet or sidecar in your cluster still depends on the node role, restrict IMDS in a canary node group first. The guide also warns not to disable instance metadata outright, because node components such as the termination handler depend on it.

A related detail catches people during migration: Pods configured with hostNetwork: true always have IMDS access, and both User Guide pages say so explicitly. They will still use IRSA or Pod Identity credentials when those are configured, but the hop-limit control does not isolate them.

The second caveat is the one to quote in design reviews. Both the IRSA page and the Pod Identity page carry the same "Important" note: "Containers are not a security boundary," and using either mechanism "does not change this." Pods on the same node share a kernel; node-level components such as the kubelet, kube-proxy, and CSI drivers hold permissions beyond any individual workload. Per-Pod IAM roles reduce blast radius; they do not create a trust boundary where the container runtime does not provide one. Where you need that boundary, it comes from separate nodes, separate clusters, or separate accounts — which is why Section 8 exists.

3. How IRSA Works

3.1 The token exchange

IRSA is built on a Kubernetes primitive: service account token volume projection, added in Kubernetes 1.12. Instead of the legacy, non-expiring service account secret, the kubelet projects a short-lived OIDC JSON Web Token into the Pod with a configurable audience. Amazon EKS hosts a public OIDC discovery endpoint for every cluster that serves the signing keys for those tokens, so an external system — IAM — can validate them.

The sequence for a Pod is:
  1. The service account carries the annotation eks.amazonaws.com/role-arn.
  2. A mutating webhook that runs as part of the Amazon EKS control plane watches for Pods using such a service account and injects two environment variables and a projected token volume: AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token.
  3. The AWS SDK finds those variables in its default credential provider chain and calls AWS STS AssumeRoleWithWebIdentity, presenting the projected token.
  4. IAM validates the token's signature against the cluster's OIDC provider, evaluates the role's trust policy, and returns temporary credentials.

Two rotation facts matter operationally. The kubelet refreshes the projected token when it is older than 80 percent of its total time to live, or after 24 hours, and the AWS SDKs are responsible for reloading it. Separately, the cluster's OIDC signing private key rotates every 7 days, and Amazon EKS retains the public keys until they expire — which only matters if you have external OIDC clients validating cluster tokens yourself, in which case you must refresh the keys you have cached before they expire.

A decoded IRSA token makes the identity model concrete. Its aud is sts.amazonaws.com, its iss is the cluster's OIDC issuer URL, and its sub is system:serviceaccount:<namespace>:<service-account>. Those three claims are the only thing the trust policy has to work with.

3.2 The trust policy is the access control

Because IAM performs the authorization, an IRSA role's trust policy is the control. The documented shape is a federated principal plus conditions on the two claims:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com",
          "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:default:my-service-account"
        }
      }
    }
  ]
}
The User Guide attaches an "Important" note to exactly this policy: without a sub condition, any service account in the cluster can assume the role. A separate Amazon EKS page repeats it as a warning and adds the specific anti-pattern to avoid — never use wildcards in the subject condition such as system:serviceaccount:*:*, because that "would allow any ServiceAccount in any namespace to assume the role." The documented way to widen scope deliberately is to switch the operator to StringLike and wildcard only the service account segment, and the Best Practices Guide still recommends naming the service account explicitly so that other Pods in the same namespace cannot assume the role.

3.3 Prerequisites, and the private-cluster wrinkle

IRSA has one setup step per cluster and one per role:
  • Per cluster: create an IAM OIDC identity provider for the cluster's issuer URL. eksctl utils associate-iam-oidc-provider does this in one command.
  • Per role: write the trust policy above, attach permission policies, and annotate the service account with the role ARN.

The wrinkle appears in VPCs without internet egress. Creating the OIDC provider requires resolving and reaching the cluster OIDC issuer hostname, and the User Guide documents the failure verbatim — server cant find oidc.eks.region.amazonaws.com: NXDOMAIN. On 2026-07-27 AWS announced AWS PrivateLink support for the cluster OIDC discovery and JWKS endpoint, so the supported fix is now an interface VPC endpoint for com.amazonaws.<region-code>.oidc-eks with private DNS enabled. That announcement calls out the two use cases directly: in-VPC tooling such as eksctl or Terraform creating the IAM OIDC provider, and custom token validators running inside the VPC. It also notes the endpoint's access-control behavior differs from the Amazon EKS API endpoints, so read the endpoint page rather than assuming it behaves like com.amazonaws.<region-code>.eks.

Two more prerequisites are easy to miss. Pods must reach an AWS STS endpoint, so a private cluster needs the AWS STS interface endpoint as well, and the User Guide recommends configuring a Regional AWS STS endpoint for a service account rather than the global one: "This reduces latency, provides built-in redundancy, and increases session token validity." And the SDK has to be new enough to understand the web identity token file at all.
* You can sort the table by clicking on the column name.
Language or toolMinimum version for IRSA
Java (Version 2)2.10.11
Java (Version 1)1.12.782
AWS SDK for Go v11.23.13
AWS SDK for Go v2All versions support
Python (Boto3)1.9.220
Python (botocore)1.12.200
AWS CLI1.16.232
Node (JavaScript)2.525.0 and 3.27.0
Ruby3.58.0
C++1.7.174
.NET3.3.659.1 (must also include AWSSDK.SecurityToken)
PHP3.110.7

Java carries one extra requirement the documentation calls out separately: the sts module must be on the classpath.

4. How EKS Pod Identity Works

4.1 The association and the EKS Auth API

Pod Identity replaces the OIDC federation with an EKS-native exchange. The unit of configuration is an association: a record that maps one IAM role to one Kubernetes service account in one namespace in one cluster. The User Guide is explicit that this record lives entirely in Amazon EKS — "there isn't any data or metadata about the associations inside the cluster in any Kubernetes objects and you don't add any annotations to the service accounts."

When a Pod uses a service account that has an association, Amazon EKS mutates the Pod manifest to add a projected token with audience pods.eks.amazonaws.com and an expiration of 86400 seconds, plus two environment variables:
env:
- name: AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE
  value: "/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token"
- name: AWS_CONTAINER_CREDENTIALS_FULL_URI
  value: "http://169.254.170.23/v1/credentials"
volumeMounts:
- mountPath: "/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/"
  name: eks-pod-identity-token
volumes:
- name: eks-pod-identity-token
  projected:
    defaultMode: 420
    sources:
    - serviceAccountToken:
        audience: pods.eks.amazonaws.com
        expirationSeconds: 86400 # 24 hours
        path: eks-pod-identity-token
Those variables select the container credential provider, the same step in the SDK credential chain that Amazon ECS uses. The endpoint they point at is served by the Amazon EKS Pod Identity Agent, a DaemonSet on the node, which calls eks-auth:AssumeRoleForPodIdentity against the EKS Auth API with the Pod's token. The API response returns the resolved subject (namespace and service account), an audience that "is always pods.eks.amazonaws.com", the podIdentityAssociation that matched, the assumedRoleUser, and the credentials.

The architectural difference is worth stating precisely because it is the origin of several downstream properties. With IRSA, every SDK in every Pod performs its own AssumeRoleWithWebIdentity call against AWS STS. With Pod Identity, the EKS Auth service performs the role assumption and the agent hands the result to the SDKs, so, as the User Guide puts it, "the load is reduced to once for each node and isn't duplicated in each pod." That is why the comparison table can say Pod Identity does not consume your account's AWS STS quota.
How IRSA and EKS Pod Identity each deliver AWS credentials to a Pod
How IRSA and EKS Pod Identity each deliver AWS credentials to a Pod

4.2 The trust policy is a single service principal

Because Amazon EKS performs the exchange, the role's trust policy no longer names the cluster. It names one service principal and permits two actions:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowEksAuthToAssumeRoleForPodIdentity",
      "Effect": "Allow",
      "Principal": {
        "Service": "pods.eks.amazonaws.com"
      },
      "Action": [
        "sts:AssumeRole",
        "sts:TagSession"
      ]
    }
  ]
}
sts:AssumeRole is the assumption itself; sts:TagSession is required because Pod Identity attaches session tags to the request (Section 7.3). The console only lists roles that carry this trust policy when you create an association, which is a useful sanity check.

That policy as written trusts the Amazon EKS service to assume the role on behalf of any cluster in any account that Amazon EKS will pass it — the association API and its iam:PassRole check are what actually bind it to your cluster. The Best Practices Guide therefore recommends a confused-deputy condition, and gives the organization-scoped form:
"Condition": {
  "StringEquals": {
    "aws:SourceOrgId": "${aws:ResourceOrgId}"
  }
}
Amazon EKS passes aws:SourceOrgId equal to the AWS Organizations organization ID of the account, so this restricts use of the role to clusters inside your organization. The launch blog shows the narrower variant using aws:SourceAccount and aws:SourceArn pinned to a specific cluster ARN, which is the right choice for a role that should serve exactly one cluster. Be aware of the interaction noted in the Best Practices Guide: if you pin sourceArn to a cluster and later do a blue/green cluster upgrade, you must update the trust policy for the new cluster — which gives back some of the "never edit the trust policy again" benefit, so pin deliberately.

4.3 Prerequisites

  • The agent. Install the eks-pod-identity-agent Amazon EKS add-on once per cluster. Amazon EKS Auto Mode clusters do not need it — the capability is built in, and the User Guide repeats that note on every relevant page.
  • Node role permission. The node IAM role must allow eks-auth:AssumeRoleForPodIdentity. The AWS managed AmazonEKSWorkerNodePolicy includes it. On Amazon EKS Auto Mode, the managed AmazonEKSWorkerNodeMinimalPolicy exists largely for this: the EKS Auto Mode security whitepaper states that eks-auth:AssumeRoleForPodIdentity "is the only permission on the managed AmazonEKSWorkerNodeMinimalPolicy policy." Note that the add-on itself does not take a service-account role; it borrows the node role.
  • Reachability. The nodes must reach the EKS Auth API. The setup page marks this "Important": for nodes in private subnets, create an AWS PrivateLink interface endpoint, com.amazonaws.<region-code>.eks-auth. If a proxy is in play, add 169.254.170.23 and [fd00:ec2::23] to no_proxy and NO_PROXY, or credential requests to the agent will fail.
  • Cluster version. The cluster's platform version must be at or later than the documented minimum. The only Kubernetes version currently carrying a floor is 1.28, which requires platform version eks.4; all other listed versions are supported on all platform versions.
  • Ports and addresses. The agent uses the node's hostNetwork and occupies ports 80 and 2703 on the link-local addresses 169.254.170.23 (IPv4) and [fd00:ec2::23] (IPv6). If IPv6 is disabled on your nodes the agent cannot start, and you must explicitly disable IPv6 in the agent configuration.
  • Interaction with security groups for Pods. If you use security groups for Pods with the Amazon VPC CNI, set ENABLE_POD_ENI to true and POD_SECURITY_GROUP_ENFORCING_MODE to standard. The mechanics of trunk and branch interfaces are covered in the Amazon EKS Networking Deep Dive.
  • Permission to create associations. The IAM principal creating an association must have iam:PassRole for the role being associated. This is a genuine difference from IRSA, where no PassRole check occurs.

Two limits and one behavior belong here as well. A cluster supports up to 5,000 Pod Identity associations. Each service account can be associated with one IAM role, though the same role may be associated with many service accounts. And associations are eventually consistent — the API reference warns they "may take several seconds to be effective after the initial API call returns successfully" and recommends against putting association create and update calls "in the critical, high-availability code paths of your application." Create them in a setup routine, not in a startup probe.

Finally, the SDK floor is considerably newer than IRSA's, because Pod Identity needed the container credential provider to be wired into every SDK.
* You can sort the table by clicking on the column name.
Language or toolMinimum version for EKS Pod Identity
Java (Version 2)2.21.30
Java (Version 1)1.12.746
AWS SDK for Go v1v1.47.11
AWS SDK for Go v2release-2023-11-14
Python (Boto3)1.34.41
Python (botocore)1.34.41
AWS CLI1.30.0 (v1) and 2.15.0 (v2)
JavaScript v22.1550.0
JavaScript v3v3.458.0
Kotlinv1.0.1
Ruby3.188.0
Rustrelease-2024-03-13
C++1.11.263
.NET3.7.734.0
PowerShell4.1.502
PHP3.289.0

5. Side-by-Side Comparison

* You can sort the table by clicking on the column name.
AttributeEKS Pod IdentityIRSA
Credential pathAgent on the node calls EKS Auth AssumeRoleForPodIdentitySDK in the Pod calls AWS STS AssumeRoleWithWebIdentity
Where the mapping livesAmazon EKS API only; nothing in the clusterService account annotation plus the role's trust policy
Trust policy principalService principal pods.eks.amazonaws.comThe cluster's IAM OIDC provider (federated)
Per-cluster setupInstall the Pod Identity Agent add-on (built in on EKS Auto Mode)Create an IAM OIDC identity provider
Scope of a role across clustersOne-time trust policy; reuse in any cluster unchangedTrust policy must be edited for each new cluster's issuer
Association limit5,000 associations per clusterNot applicable
Account-level ceilingNot applicableIAM default of 100 OIDC providers per account
Trust policy size pressureNone (the mapping is not in the policy)Default 2,048-character trust policy, roughly 4 relationships, typically 8 at most
Session tags and ABACSix tags attached automaticallyNot supported
Session policiesSupported, with session tags disabledNot supported
Cross-account accessTarget IAM role with automatic role chainingDirect, via AssumeRoleWithWebIdentity or manual role chaining
AWS STS quota consumptionNone from your accountYes; SDK behavior can cause throttling
iam:PassRole requiredYes, for the principal creating the associationNo
Agent required on nodesYes (built in on EKS Auto Mode)No
Minimum SDK versionsNewer floor (from late 2023)Long-standing, widely satisfied
Environments supportedAmazon EKS onlyAmazon EKS, Amazon EKS Anywhere, Red Hat OpenShift Service on AWS, self-managed Kubernetes on Amazon EC2

Compute support is the part most likely to decide the question outright, so it gets its own table.
* You can sort the table by clicking on the column name.
Compute typeEKS Pod IdentityIRSA
Linux Amazon EC2 nodes (managed or self-managed)SupportedSupported
Amazon EKS Auto ModeSupported; the agent is built inSupported
Amazon EKS Hybrid NodesSupported with the optional hybrid DaemonSet and a node-side credentials fileSupported
AWS Fargate (Linux or Windows Pods)Not supportedSupported
Windows Amazon EC2 nodesNot supportedSupported
Amazon EKS on AWS OutpostsNot supportedNot supported on local clusters
Amazon EKS AnywhereNot supportedSupported
Self-managed Kubernetes on Amazon EC2Not supportedSupported

Two notes on that table, both worth carrying into a design review.

Hybrid nodes are supported, but you would not learn that from the Pod Identity page. EKS Pod Identity has been an Amazon EKS Hybrid Nodes feature since hybrid nodes reached general availability on 2024-12-01 — that announcement lists "EKS Pod Identity" among the features you can use with them, and the EKS Hybrid Nodes overview page repeats it in two places. The "Configure add-ons for hybrid nodes" page documents the mechanism: because IMDS is not available on hybrid nodes, starting with agent version v1.3.3-eksbuild.1 the add-on can optionally deploy a DaemonSet that mounts credentials from a node-side file, and starting with v1.3.7-eksbuild.2 there is a separate DaemonSet for Bottlerocket hybrid nodes, which additionally require Bottlerocket v1.39.0 or later. On Ubuntu, RHEL, and AL2023 you set enableCredentialsFile: true in the nodeadm configuration, re-run nodeadm init on each node, and install the add-on with {"daemonsets":{"hybrid":{"create": true}}}; on Bottlerocket you pass --enable-credentials-file=true to the bootstrap container command and install with {"daemonsets":{"hybrid-bottlerocket":{"create": true}}} instead. The hybrid nodes IAM role page correspondingly lists eks-auth:AssumeRoleForPodIdentity as an optional permission "for the Amazon EKS Pod Identity Agent." The catch is that the Pod Identity page's own restrictions list still frames availability as "Linux Amazon EC2 instances" and never mentions hybrid nodes, so a reader who checks only that page will conclude, incorrectly, that they are excluded. All of these pages were consulted on 2026-07-31.

AWS Fargate and Windows are the clean, unambiguous exclusions. The Pod Identity page states that "Linux and Windows pods that run on AWS Fargate (Fargate) aren't supported" and "Pods that run on Windows Amazon EC2 instances aren't supported," and the Best Practices Guide names both as reasons to choose IRSA. If any part of the workload lands there, IRSA is not legacy — it is the mechanism.

Finally, availability by Region has moved. At launch in November 2023, Pod Identity was available in all Amazon EKS Regions except the AWS GovCloud (US) Regions and the China Regions. Checking the Amazon EKS API's Regional availability on 2026-07-31 shows CreatePodIdentityAssociation available in commercial Regions and in AWS GovCloud (US-West), and not found in China (Beijing); the February 2026 announcement of Amazon EKS add-on integration with Pod Identity in the AWS GovCloud (US) Regions is consistent with that. Confirm for your own Regions rather than trusting any snapshot, including this one.

6. Choosing Between Them

The decision is short if you take the questions in order. The first two are hard constraints; the rest are preferences with real weight.

6.1 The decision sequence

  1. Where do the Pods run? If any of them run on AWS Fargate, on Windows Amazon EC2 nodes, on Amazon EKS Anywhere, on Red Hat OpenShift Service on AWS, or on self-managed Kubernetes on Amazon EC2 — IRSA. Pod Identity does not reach those. Note this can be a per-workload answer, not a per-cluster one.
  2. Can you move the SDK? Pod Identity requires a version from late 2023 or later in every container that needs credentials, including vendored controllers and operators you do not build. If a workload is pinned to an older SDK — IRSA, until it moves.
  3. How does cross-account access have to work? If your security model requires the Pod's identity to federate directly into a role in the workload account, or your existing controls are built around per-account OIDC providers — IRSA. Pod Identity reaches other accounts by role chaining through a role in the cluster account (Section 8.2), which is a different trust shape even though the outcome is similar.
  4. Are you already running IRSA at rest? If you have a working, standardized pattern for OIDC providers and role trust policies, and you are not hitting the OIDC-provider limit, the trust-policy size limit, or AWS STS throttling — there is no forcing function. The Best Practices Guide lists "you already use IRSA successfully and have a standard pattern" as a reason to stay. Migration has a cost and should buy something.
  5. Otherwise, prefer Pod Identity, and prefer it strongly if any of these describe you: you run many clusters per account, or expect to; you do blue/green cluster upgrades and are tired of rewriting trust policies; you want ABAC so a smaller number of roles can serve many service accounts; you want cluster administrators to manage service-account-to-role mapping while IAM administrators own the permissions; or your AWS STS call volume from Pods is causing throttling.
  6. Expect to run both. Both the User Guide and the Best Practices Guide describe a mixed model as supported and normal: legacy workloads on IRSA, new workloads on Pod Identity, on the same cluster. This is not a transitional embarrassment; for clusters that also run AWS Fargate Pods it is the permanent steady state.

6.2 When IRSA is the right answer, stated plainly

Because the general advice runs the other way, it is worth collecting the cases in one place. The EKS Best Practices Guide's own list is: you already use IRSA successfully and have a standard pattern for OIDC providers and IAM roles; your workloads run where Pod Identity is not supported, "such as AWS Fargate, Windows nodes, or applications using un-supported AWS SDKs"; and you require "a direct OIDC-based federation model to roles in your workload accounts" with security controls already built around OIDC providers.

To that documented list, three practical situations follow from facts elsewhere in this guide:
  • You need workload identity outside Amazon EKS too. If the same application also runs on Amazon EKS Anywhere, on Red Hat OpenShift Service on AWS, or on self-managed Kubernetes, IRSA gives you one mechanism everywhere. Pod Identity would give you two.
  • You cannot grant iam:PassRole to whoever manages the cluster. Pod Identity requires it for association creation; IRSA does not. In organizations where PassRole is tightly held, that is a governance conversation, not a checkbox.
  • The workload cannot tolerate the credential cache window. Pod Identity credentials are cached by the agent for 6 hours without a target role and 59 minutes with one, and changing an association does not reset the cache (Section 10.3). If your operational model depends on a role change taking effect promptly without restarting Pods, understand that behavior before you move.

None of that argues against Pod Identity as the default for new work on supported node types. It argues against treating "migrate everything" as a goal in itself.

7. Least-Privilege Role Design

The mechanism decides how a Pod gets credentials. Role design decides what those credentials are worth if the Pod is compromised — and the guidance is mostly shared between the two.

7.1 Role granularity

The Best Practices Guide's default is one IAM role per application, with both mechanisms, for isolation and least privilege, and a dedicated service account per application rather than reusing the namespace default. There is one documented reason to deviate: "when using ABAC with EKS Pod Identity, you may use a common IAM role across multiple service accounts and rely on their session attributes for access control," which "is especially useful when operating at scale, as ABAC allows you to operate with fewer IAM roles." So the trade is roles versus policy complexity, and only Pod Identity offers the second option.

While you are there, turn off what you are not using: if an application does not call the Kubernetes API, set automountServiceAccountToken: false so the Kubernetes API token is not mounted at all.

7.2 Scoping the trust policy

For IRSA, scope with the sub and aud conditions in Section 3.2 — always naming the service account, never a full wildcard. For Pod Identity, the equivalent scoping happens in two places: the association (which is itself the cluster, namespace, and service account binding) and the confused-deputy condition in Section 4.2. Adding aws:SourceOrgId is the low-friction default; adding aws:SourceArn pinned to a cluster is stricter but costs you a trust policy edit on cluster replacement.

Both mechanisms benefit from a permissions boundary on workload roles. The Best Practices Guide recommends it for both, framed as ensuring "the roles used by IRSA or Pod Identities can not exceed a maximum level of permissions" — a useful control when role creation is delegated to application teams.

7.3 Session tags and ABAC

This is Pod Identity's most consequential exclusive feature. When EKS Auth assumes the role it attaches six session tags:
Session tagValue
eks-cluster-arnThe ARN of the Amazon EKS cluster
eks-cluster-nameThe name of the Amazon EKS cluster
kubernetes-namespaceThe namespace the Pod runs in
kubernetes-service-accountThe service account name
kubernetes-pod-nameThe Pod name
kubernetes-pod-uidThe Pod UID

They are referenced in policies as ${aws:PrincipalTag/<key>} — for example, a bucket policy that only grants access when the caller's kubernetes-service-account, kubernetes-namespace, and eks-cluster-arn all match expected values.

The uniqueness caveat is the part people get wrong. The Best Practices Guide spells it out: Kubernetes service accounts are only unique within a namespace, and Kubernetes namespaces are only unique within a cluster — and cluster names can repeat across accounts. A policy that conditions on kubernetes-service-account alone is not an access control; it is a naming convention. Condition on eks-cluster-arn plus kubernetes-namespace plus kubernetes-service-account together. The guide also notes that a cluster deleted and recreated with the same name in the same Region and account will have the same ARN, which matters if you rely on ARN uniqueness across a rebuild.

Three more documented behaviors:
  • All Pod Identity session tags are transitive — they are passed to any subsequent AssumeRole your workload performs, so you can condition on them in another account (Section 8).
  • You cannot add custom tags to the assumption. Tags applied to the IAM role itself remain available through the same ${aws:PrincipalTag/...} syntax.
  • On conflict, the tag Amazon EKS adds wins over a same-named tag on the role.

Session tags can be disabled per association, and the documented reason is specific: AWS packs inline session policies, managed policy ARNs, and session tags into a binary format with its own size limit, so if you hit PackedPolicyTooLarge, dropping the tags is a way to reduce it.

Because ABAC turns tags into permissions, who can set those tags becomes a privilege escalation question. The Best Practices Guide says it directly: someone able to set kubernetes- or eks- tags "may be able to set tags identical to what would be passed during EKS Pod Identity role chaining and may be able to escalate their privileges," and recommends restricting that with an IAM policy or a Service Control Policy. If you are building the guardrail, the SCP and RCP design patterns are in AWS Organization Guardrails.

7.4 Session policies

Announced on 2026-03-24, session policies let a Pod Identity association carry an inline IAM policy that narrows the role's permissions for that association only. The constraints are tight and all of them matter:
  • The effective permissions are the intersection of the role's identity-based policies and the session policy. A session policy can only reduce, never add.
  • It requires disableSessionTags to be true. Session tags and session policies cannot be combined, because of the AWS STS packed-policy size quota. That is an either/or design decision, not a configuration detail.
  • The plaintext policy cannot exceed 2,048 characters.
  • If the association also specifies a targetRoleArn, the session policy applies to the target role's permissions, not to the role used to assume it.

The use case is a shared role serving several applications where you want per-application narrowing without minting a role each time — the same problem ABAC solves, with the opposite trade-off, and you must pick one.

7.5 The controls this guide does not re-derive

Workload roles sit inside the same evaluation machinery as everything else: SCPs and RCPs above them, resource policies beside them, permission boundaries around them. Where a Pod's call is denied and the role's policy clearly allows it, the answer is in that machinery — see IAM Policy Evaluation Logic Step-by-Step for the order, the AWS IAM Glossary for the vocabulary, and IAM Anti-Patterns for the failure catalogue. To review a candidate policy before you attach it, the IAM Policy Least Privilege Analyzer runs entirely in the browser.

8. Multi-Cluster and Multi-Account Patterns

8.1 One role, many clusters

This is Pod Identity's headline benefit and it is precisely bounded. Because the cluster is not named in the trust policy, "you can make identical associations in each cluster without modifying the trust policy of the role." With IRSA, every new cluster means a new OIDC issuer and therefore an edit to every role that workload uses in that cluster — and each edit consumes part of a trust policy that defaults to 2,048 characters, which the comparison documentation translates to roughly four relationships, typically eight at most even after a limit increase.

The same asymmetry shows up during blue/green cluster upgrades, where you stand up a new cluster beside the old one and shift traffic. The Best Practices Guide notes that with IRSA "you will need to update the trust policy of each of the IRSA IAM roles with the OIDC endpoint of the new cluster," whereas with Pod Identity "you would create pod identity associations between the IAM roles and service accounts in the new cluster" — and only update the trust policy "if you have a sourceArn condition." That last clause is the cost of the stricter confused-deputy condition from Section 4.2, and it is a fair trade to make consciously.

8.2 Cross-account with Pod Identity target roles

Announced on 2025-06-12, target IAM roles let an association name two roles and have Amazon EKS perform the chaining. The mechanics, from the User Guide:
  • You supply a Pod Identity role in the cluster's account and a target IAM role that can be in the same or a different account. The Pod Identity role must be in the cluster's account "due to IAM PassRole requirements."
  • When a Pod requests credentials, Pod Identity assumes the first role, then uses those credentials to assume the target role, and injects the target role's credentials into the Pod.
  • The Pod Identity role needs a permission policy allowing sts:AssumeRole and sts:TagSession on the target role ARN.
  • The target role's trust policy authorizes the Pod Identity role and — this is the useful part — can condition on the transitive session tags with aws:RequestTag/eks-cluster-arn, aws:RequestTag/kubernetes-namespace, and aws:RequestTag/kubernetes-service-account, plus ArnEquals on aws:PrincipalARN. That lets the resource-owning account authorize a specific service account in a specific namespace in a specific cluster, without trusting the whole cluster account.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::111122223333:root" },
      "Action": [ "sts:AssumeRole", "sts:TagSession" ],
      "Condition": {
        "StringEquals": {
          "aws:RequestTag/eks-cluster-arn": "arn:aws:eks:us-east-1:111122223333:cluster/example-cluster",
          "aws:RequestTag/kubernetes-namespace": "ExampleNameSpace",
          "aws:RequestTag/kubernetes-service-account": "ExampleServiceAccountName"
        },
        "ArnEquals": {
          "aws:PrincipalARN": "arn:aws:iam::111122223333:role/eks-pod-identity-primary-role"
        }
      }
    }
  ]
}
If you disabled session tags on the association, the tag conditions are unavailable and Pod Identity instead sets sts:ExternalId to a value encoding the cluster, namespace, and service account in the form region/account/cluster-name/namespace/service-account-name, which you condition on instead. Both variants are documented; the tag form composes better with ABAC, and the external-ID form is what you use alongside session policies.

The caching behavior changes when a target role is present, and it is the single most surprising operational fact in this area: the agent caches credentials for 6 hours for an association with no target role, and 59 minutes when a target role is set. Modifying an existing association — changing the role ARN, adding a target role, updating the session policy — does not reset the cache. To make a change take effect sooner you recreate the Pods; otherwise you wait for expiry.

8.3 Cross-account with IRSA

IRSA offers two documented shapes, and the User Guide states the trade-off up front: option 1 "is simpler but requires Account B to create and manage an OIDC identity provider for Account A's cluster," while option 2 "keeps OIDC management in Account A but requires role chaining through two AssumeRole calls."
  1. Identity provider in the resource account. Account B creates an IAM OIDC provider for Account A's cluster issuer and a role trusting it; Account A annotates the service account with Account B's role ARN. The Pod then federates directly into the workload account — which is exactly the "direct OIDC-based federation model" that Section 6 lists as a reason to keep IRSA.
  2. Chained AssumeRole. Account A keeps the OIDC provider and an IRSA role; Account B's role trusts Account A; the Pod chains with two AWS CLI profiles, one using web_identity_token_file and the other using it as source_profile. The documentation attaches an "Important" note here too: replace the account-root principal in Account B's trust policy with the specific Account A role ARN, because using the root "allows any IAM principal in Account A to assume this role."

Note the shape difference this creates for governance. With IRSA option 1, the resource account owns an identity provider that names a specific cluster — coupling that must be maintained when the cluster is replaced. With Pod Identity target roles, the resource account owns only a role that trusts a role, with tag conditions describing the workload — no cluster-specific IAM object to maintain, but an extra hop and the shorter cache window.

8.4 Where the clusters and the resources live

Both mechanisms support centralized clusters (one cluster account, resources in workload accounts) and decentralized clusters (a cluster in each workload account, no cross-account access at all), and the EKS Best Practices Guide compares those two topologies directly on cluster management, resilience, isolation, quotas, networking, and access management. The decentralized model removes the cross-account question entirely, which is worth weighing before engineering around it. For the surrounding account structure — organizational units, guardrails, and the operational patterns that go with them — see AWS Multi-Account Operational Patterns.

9. Migration Path

Migration from IRSA to Pod Identity is incremental and reversible up to the last step, provided you sequence it correctly. The property that makes it safe is the credential provider chain: "if your workloads currently use credentials that are earlier in the chain of credentials, those credentials will continue to be used even if you configure an EKS Pod Identity association for the same workload." In other words, you can put the new configuration in place before you remove the old one.
Staged migration from IRSA to EKS Pod Identity with a rollback point
Staged migration from IRSA to EKS Pod Identity with a rollback point

9.1 Preconditions

Before touching anything, confirm all of the following, per workload rather than per cluster:
  1. The Pods run on a supported compute type (Section 5). Anything on AWS Fargate or Windows nodes stops here and stays on IRSA.
  2. Every container that needs credentials uses an SDK at or above the Pod Identity floor (Section 4.3). This includes third-party controllers and operators.
  3. The cluster meets the platform version requirement, and the Pod Identity Agent add-on is installed (or the cluster is Amazon EKS Auto Mode).
  4. The node role allows eks-auth:AssumeRoleForPodIdentity, and nodes in private subnets can reach the EKS Auth endpoint.
  5. The principal that will create associations has iam:PassRole for the target roles.

9.2 The staged sequence

Stage 1 — Add the second trust relationship (reversible). Edit the role's trust policy to trust both the existing OIDC provider and pods.eks.amazonaws.com. Nothing changes yet; the role simply accepts two ways in. The launch blog describes this as the way "to ensure a seamless migration."
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ExistingIrsaTrust",
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com",
          "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:default:my-service-account"
        }
      }
    },
    {
      "Sid": "AllowEksAuthToAssumeRoleForPodIdentity",
      "Effect": "Allow",
      "Principal": { "Service": "pods.eks.amazonaws.com" },
      "Action": [ "sts:AssumeRole", "sts:TagSession" ],
      "Condition": {
        "StringEquals": { "aws:SourceOrgId": "${aws:ResourceOrgId}" }
      }
    }
  ]
}
Warning: editing a trust policy replaces it wholesale. Read the current document with aws iam get-role --role-name my-role --query Role.AssumeRolePolicyDocument, keep a copy, and add the statement to it — do not write the new statement over the old document. A role whose OIDC statement is dropped by accident stops working for every Pod already using it, in every cluster that trusts it.

Stage 2 — Create the association and restart the Pods (reversible).
aws eks create-pod-identity-association \
  --cluster-name my-cluster \
  --role-arn arn:aws:iam::111122223333:role/my-role \
  --namespace default \
  --service-account my-service-account
Associations are eventually consistent, so allow several seconds. Then restart the workload — kubectl rollout restart deployment/my-deployment — so the mutating webhook injects the Pod Identity environment variables. The launch blog notes that when a role is set up for both, "the EKS Pod Identity webhook gives preference to EKS Pod Identity over IRSA."

Stage 3 — Verify before removing anything (reversible). Confirm the Pod actually switched, using both the Pod spec and CloudTrail (Section 10). The Pod spec check is immediate:
# Should now show the container credentials URI
kubectl exec deploy/my-deployment -- env | grep AWS_CONTAINER_CREDENTIALS_FULL_URI

# Should show the assumed role identity in use
kubectl exec deploy/my-deployment -- aws sts get-caller-identity
Rollback from any stage up to here is a single reversible action: delete the association with aws eks delete-pod-identity-association --cluster-name my-cluster --association-id a-abcdefghijklmnop1 and restart the workload. Because the OIDC trust statement and the service account annotation are still in place, the Pod returns to IRSA. Nothing has been destroyed.

Stage 4 — Remove the IRSA path (the destructive step). Only after verification, remove the federated statement from the trust policy and drop the eks.amazonaws.com/role-arn annotation from the service account. Treat this as a separate change with its own approval, and observe two hard warnings:
  • Do not delete the cluster's IAM OIDC identity provider as part of a per-workload migration. The provider is an account-level object shared by every role that trusts that cluster. Deleting it breaks all of them at once, including workloads you have not migrated and any external token validators. Retire it only when nothing in the account references that issuer, and treat it as a change with a cluster-wide blast radius.
  • Removing the annotation and the trust statement are independently reversible, but only if you kept the values. Record the issuer URL and the exact sub condition before you delete them; reconstructing an issuer ID from memory is not possible.

9.3 Doing it with eksctl

eksctl automates the sequence. The documented behavior is that eksctl utils migrate-to-pod-identity installs the agent add-on if absent, identifies roles associated with iamserviceaccounts and with add-ons that support Pod Identity, updates those roles' trust policies to add the Amazon EKS service principal (optionally removing the OIDC relationship), creates the associations, and updates add-ons to use Pod Identity.
# Plan only. Without --approve, eksctl prints the task list and changes nothing.
eksctl utils migrate-to-pod-identity --cluster my-cluster

# Apply. Add --remove-oidc-provider-trust-relationship only after verification.
eksctl utils migrate-to-pod-identity --cluster my-cluster --approve
Run the plan form first and read it. --remove-oidc-provider-trust-relationship collapses Stage 1 and Stage 4 into one command, which removes the rollback point described above; use it only on roles you have already verified.

9.4 Add-ons are a separate track

Cluster add-ons that call AWS need roles too, and here Pod Identity has a dedicated path. On 2024-11-18 AWS announced direct integration between Amazon EKS add-ons and Pod Identity, so add-on operations through the console, CLI, API, eksctl, and AWS CloudFormation can manage the associations themselves rather than requiring separate Pod Identity API calls; the same integration reached the AWS GovCloud (US) Regions in February 2026. Before installing an add-on you can ask the API what it needs:
# Does this add-on require IAM permissions?
aws eks describe-addon-versions \
  --addon-name aws-ebs-csi-driver \
  --kubernetes-version 1.30

# What service account and managed policy does it recommend?
aws eks describe-addon-configuration \
  --query podIdentityConfiguration \
  --addon-name aws-ebs-csi-driver \
  --addon-version v1.31.0-eksbuild.1
The User Guide also publishes a support table for AWS add-ons — Amazon EBS CSI Driver from v1.26.0-eksbuild.1, Amazon VPC CNI from v1.15.5-eksbuild.1, Amazon EFS CSI Driver from v2.0.5-eksbuild.1, AWS Distro for OpenTelemetry from v0.94.1-eksbuild.1, Amazon CloudWatch Observability agent from v3.1.0-eksbuild.1, with Mountpoint for Amazon S3 CSI Driver listed as not supported. That table carries the line "This table was last updated on October 28, 2024," so treat it as a floor and confirm with describe-addon-versions for your add-on and cluster version rather than as a current inventory. For the Amazon VPC CNI specifically, the Best Practices Guide notes the aws-node DaemonSet supports Pod Identity in versions v1.15.5 and later, and separately recommends moving aws-node off the node role entirely — one of the highest-value single changes available, since the node role's CNI permissions are otherwise shared by every Pod on the node.

10. Observability and Auditing

10.1 What each mechanism looks like in CloudTrail

The two mechanisms produce structurally different audit trails, and knowing which to search for is half the diagnosis.

IRSA produces AWS STS AssumeRoleWithWebIdentity events. The response identifies the federation directly: the Provider is the cluster's OIDC provider ARN, the Audience is sts.amazonaws.com, and SubjectFromWebIdentityToken carries system:serviceaccount:<namespace>:<service-account>. That subject is the direct link from an AWS API call back to a Kubernetes identity — but note what it does not contain: the cluster. If two clusters share an OIDC-federated role, the subject alone will not tell them apart; the provider ARN will.

Pod Identity produces AssumeRole events with pods.eks.amazonaws.com as the principal, carrying the six session tags. Those tags are strictly more informative than the IRSA subject: they include the cluster ARN, the namespace, the service account, and both the Pod name and Pod UID. Where IRSA tells you "some Pod using this service account," Pod Identity tells you which Pod instance, in which cluster. Separately, the agent's own calls appear as eks-auth:AssumeRoleForPodIdentity, which is documented as being "only used by the EKS Pod Identity Agent" — if you see it from anywhere else, investigate.

If you are building the account-wide collection and query layer for this, the design is in Centralized Logging and Audit Architecture on AWS, and the metrics and tracing side in the AWS Observability Architecture Guide.

10.2 Auditing the mapping itself

Beyond the credential events, audit the configuration. With Pod Identity the entire mapping is in the Amazon EKS API, so aws eks list-pod-identity-associations and describe-pod-identity-association give you an authoritative inventory of which service account may assume which role — something IRSA cannot offer, because its equivalent is spread across every service account annotation in every cluster plus every role trust policy in IAM. That inventory property is a genuine and underrated operational advantage of Pod Identity, and it is worth capturing on a schedule.

Note also who can change it. Association creation requires iam:PassRole, so the CloudTrail events for association APIs, combined with the PassRole grants in your account, define the set of principals who can hand an IAM role to a workload. On the IRSA side the equivalent power is "who can edit role trust policies" plus "who can annotate service accounts in the cluster" — two different systems, which is exactly the separation-of-duties argument the User Guide makes for Pod Identity: "all configuration of EKS Pod Identity associations is done in Amazon EKS and all configuration of the IAM permissions is done in IAM."

10.3 The cache window explains most "my change did not apply"

Repeating the fact from Section 8.2 because it lands here operationally: the Pod Identity Agent caches credentials for 6 hours without a target role and 59 minutes with one, and modifying an association does not reset the cache. If you change the role on an association and the Pod's permissions do not change, that is expected behavior, not a bug. Recreate the Pods to pick it up immediately, or wait for expiry.

10.4 Diagnosing a broken credential path

The failure signatures are documented and distinctive:
  • AccessDeniedException on eks-auth:AssumeRoleForPodIdentity in the agent logs means the node role lacks the permission, or an SCP blocks the action. Check the node role first — this is not about the workload role.
  • A read timeout on http://169.254.170.23/v1/credentials, or "unable to fetch credentials from EKS Auth," points at reachability: the EKS Auth interface endpoint in a private cluster, a firewall, or a proxy configuration that does not exclude the link-local address.
  • InvalidIdentityToken: No OpenIDConnect provider found in your account for https://oidc.eks.<region>.amazonaws.com/id/... is the IRSA equivalent: the cluster's IAM OIDC provider does not exist, or its URL does not match the cluster's issuer.
  • "Unable to locate credentials" from an SDK usually means the SDK version does not support the mechanism you configured, or the Pod is not actually using the service account you think it is.

Useful checks in order: read the agent logs with kubectl logs -n kube-system -l app.kubernetes.io/name=eks-pod-identity-agent, then kubectl exec ... -- env | grep AWS_ to see which mechanism the webhook actually wired up, then aws sts get-caller-identity from inside the Pod to see the identity that results. If get-caller-identity returns the node role, the Pod is falling through the credential chain to the instance profile, which is the single most common silent failure — and the reason Section 2.2 recommends restricting IMDS so that it fails loudly instead.

11. Failure Modes and Anti-Patterns

  • A wildcard in the IRSA sub condition. system:serviceaccount:*:* lets any service account in the cluster assume the role. The documentation calls this out with a warning; treat any trust policy without an explicit service account as a finding.
  • Omitting the sub condition entirely. Same outcome, less obvious. An IRSA trust policy that conditions only on aud is cluster-wide.
  • Assuming per-Pod roles removed the node role. They did not. Without IMDS restriction the Pod still reaches the instance profile, and a credential failure will silently fall through to it rather than erroring.
  • Restricting IMDS without checking what depends on it. Setting the hop limit to 1 breaks any Pod that has not been migrated to IRSA or Pod Identity, and Pods with hostNetwork: true keep IMDS access regardless. Disabling instance metadata entirely breaks node components.
  • ABAC conditions on the service account name alone. Service accounts are unique only within a namespace and namespaces only within a cluster. Always combine eks-cluster-arn, kubernetes-namespace, and kubernetes-service-account.
  • Letting anyone set kubernetes- or eks- tags. With ABAC in place, tag-setting permission is permission-granting permission. Constrain it with an IAM policy or an SCP.
  • Expecting session policies and session tags to coexist. They cannot; session policies require session tags to be disabled. Choosing session policies means giving up the ABAC conditions in the same association.
  • Migrating a workload whose SDK is too old. The association will exist, the environment variables will be injected, and the SDK will ignore them — falling through the chain, often to the node role, which looks like it works until the permissions differ.
  • Forgetting the node role permission or the private endpoint. eks-auth:AssumeRoleForPodIdentity on the node role and the eks-auth interface endpoint in private subnets are prerequisites, not optimizations.
  • Forgetting no_proxy. A cluster-wide proxy that does not exclude 169.254.170.23 and [fd00:ec2::23] sends credential requests to the proxy.
  • Putting association creation in a startup path. Associations are eventually consistent by several seconds; the API reference explicitly recommends keeping create and update calls out of high-availability code paths.
  • Deleting the IAM OIDC provider during a partial migration. It is an account-level object shared by every role trusting that cluster. Removing it is not a per-workload cleanup step.
  • Assuming a role change takes effect immediately. The 6-hour and 59-minute cache windows, and the fact that association updates do not reset the cache, catch teams during incident response.
  • Sharing one service account across applications. The mechanism is only as granular as the service account. A shared service account means a shared role, whichever mechanism you use.
  • Treating "Pod Identity everywhere" as the goal. AWS Fargate and Windows Pods cannot use it, and a working IRSA estate is not a defect. Migrate where it buys something.

12. Frequently Asked Questions

Q. Should every Amazon EKS cluster move to Pod Identity?
A. No. AWS recommends Pod Identity "whenever possible" for supported node types, and the Best Practices Guide recommends it "for new applications running on supported node types" — but the same guide lists concrete cases for IRSA: an existing working IRSA pattern, workloads on AWS Fargate or Windows nodes or with unsupported SDKs, and a requirement for direct OIDC-based federation into workload accounts. Decide per workload, not per cluster, and expect a mixed model.

Q. Can both mechanisms run in the same cluster?
A. Yes, and that is the documented migration model. If a role trusts both the OIDC provider and pods.eks.amazonaws.com and an association exists, the EKS Pod Identity webhook gives preference to Pod Identity. Because Pod Identity sits ahead of the old credentials in the SDK chain, you can configure the new path before removing the old one.

Q. Does Pod Identity work on AWS Fargate?
A. No. The User Guide states that Linux and Windows Pods running on AWS Fargate are not supported, as are Pods on Windows Amazon EC2 instances. Use IRSA for those. For Fargate-based container workloads more broadly, the Amazon ECS-side patterns are in the Amazon ECS on Fargate Microservices Architecture Guide.

Q. What about Amazon EKS Hybrid Nodes?
A. Supported — EKS Pod Identity has been listed as an Amazon EKS Hybrid Nodes feature since their general availability on 2024-12-01 — but it needs extra setup, because IMDS is unavailable on hybrid nodes. The Pod Identity Agent add-on deploys an optional DaemonSet that reads credentials from a node-side file: from agent v1.3.3-eksbuild.1 for Ubuntu, RHEL, and AL2023 (set enableCredentialsFile: true in the nodeadm configuration and install with {"daemonsets":{"hybrid":{"create": true}}}), and from v1.3.7-eksbuild.2 for Bottlerocket, which also requires Bottlerocket v1.39.0 or later and instead uses the bootstrap container flag --enable-credentials-file=true with {"daemonsets":{"hybrid-bottlerocket":{"create": true}}}. Note that the restrictions list on the Pod Identity page still describes availability in terms of Linux Amazon EC2 instances and does not mention hybrid nodes, so do not read that list as a denial.

Q. How does cross-account access differ between the two?
A. IRSA federates directly: the Pod's token can be exchanged for a role in another account, either by creating an OIDC provider in that account or by chaining AssumeRole. Pod Identity chains natively: you set a target IAM role on the association, Amazon EKS assumes the cluster-account role and then the target role, and the target account can authorize on the transitive session tags or on sts:ExternalId. The Pod Identity role must live in the cluster's account because of the iam:PassRole requirement, and the credential cache shortens to 59 minutes when a target role is set.

Q. Why did my permission change not take effect?
A. Almost certainly the credential cache. The Pod Identity Agent caches for 6 hours without a target role and 59 minutes with one, and updating an association does not reset it. Recreate the Pods to apply a change immediately.

Q. Do I still need the IAM OIDC provider after migrating?
A. Only if something still uses it. It is an account-level object shared by every role that trusts that cluster's issuer, plus any external token validators you run. Remove the federated statement from individual role trust policies first, verify, and retire the provider itself as a separate, cluster-wide change.

Q. Is Pod Identity available in every Region?
A. Not identically, and this has changed. At launch in November 2023 it was excluded from the AWS GovCloud (US) Regions and the China Regions. Checking the Amazon EKS API's Regional availability on 2026-07-31 shows CreatePodIdentityAssociation present in commercial Regions and in AWS GovCloud (US-West) and not found in China (Beijing), consistent with the February 2026 announcement of add-on integration in the AWS GovCloud (US) Regions. Verify for the Regions you actually use.

13. Summary

Amazon EKS gives you two ways to hand a Pod its own AWS credentials, and they differ in where the cluster-to-role mapping lives. IRSA puts it in IAM: a per-cluster OIDC provider, a federated trust policy per role, and an SDK that exchanges a projected token with AWS STS. EKS Pod Identity puts it in Amazon EKS: an association record, a single service principal in the trust policy, and an agent that obtains credentials from the EKS Auth API on the node's behalf. Everything else follows from that one difference — why Pod Identity roles survive cluster replacement unedited, why it can attach session tags and support ABAC, why it needs iam:PassRole and an agent, why it does not consume your AWS STS quota, and why it cannot reach AWS Fargate or Windows Pods.

The decision is therefore short. Compute type and SDK version are hard constraints; if a workload runs on AWS Fargate, on Windows nodes, or outside Amazon EKS, IRSA is not legacy, it is the answer. If your controls are built on direct OIDC federation into workload accounts, IRSA is the answer. If you already run IRSA well and are not hitting the 100-provider limit, the 2,048-character trust policy, or AWS STS throttling, staying is a legitimate decision. Everywhere else — and especially with many clusters, blue/green cluster upgrades, ABAC ambitions, or a desire to separate cluster administration from IAM administration — Pod Identity is the better default, and a mixed cluster is a supported steady state rather than an unfinished migration.

Whichever you choose, the design work is the same: one role per application, one service account per application, trust policies that name the service account rather than wildcarding it, ABAC conditions that combine the cluster ARN with the namespace and service account rather than trusting a name to be unique, permissions boundaries on delegated roles, and IMDS restricted so a credential failure surfaces instead of silently falling back to the node role. Migrate in stages with the dual-trust window in place, keep the association-deletion rollback available until CloudTrail confirms the switch, and treat removing the OIDC provider as a cluster-wide change rather than a cleanup task. Because this area is still moving — cross-account target roles in June 2025, session policies in March 2026, AWS PrivateLink for the cluster OIDC endpoint in July 2026 — re-check the linked documentation before you act; everything here was verified on 2026-07-31 and dated accordingly.

For the layers around this one: Pod networking and security groups for Pods are in the Amazon EKS Networking Deep Dive, the service's launch history is in the AWS History and Timeline regarding Amazon EKS, policy evaluation order is in IAM Policy Evaluation Logic Step-by-Step, the organization-level guardrails are in AWS Organization Guardrails, and a worked example of a demanding Amazon EKS workload that needs both is in Self-Managed LLM Inference on Amazon EKS.

14. References

Related Articles


References:
Tech Blog with curated related content

Written by Hidekazu Konishi