Join our Newsletter — 33% off our NHI Course
Home› Guides› How to migrate EKS workloads from IRSA to…
Guide Cloud & Workload Identity

How to migrate EKS workloads from IRSA to EKS Pod Identity: a staged cutover with tighter trust

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 28 October 2026 12 min read
On this page

IAM roles for service accounts (IRSA) ties every role's trust policy to a specific cluster's OIDC provider, so roles sprawl, trust policies fill up and nobody is sure which clusters can still assume which roles. EKS Pod Identity moves the binding out of IAM trust policies and into EKS associations: one role trusts the pods.eks.amazonaws.com service principal, and EKS decides which namespace and service account receive it. This guide is the migration: checking which workloads can move, installing the agent, creating associations alongside IRSA, cutting each workload over, proving the new path in CloudTrail, and only then removing the OIDC trust. It is for platform engineers, Kubernetes administrators and cloud security teams running Amazon EKS on Linux EC2 nodes. The wider EKS identity model is in the EKS Identity Hardening Guide; this page goes deeper on the move itself.

Key takeaways

  • Not every workload can move. Pod Identity supports EKS clusters with Linux EC2 worker nodes; Fargate, Windows nodes, Outposts, EKS Anywhere and self-managed Kubernetes stay on IRSA.
  • The cutover is safe by design. AWS SDKs stop at the first valid credential in the default chain, so existing credentials keep being used after you create an association; you can stage the change and switch per workload.
  • The security boundary moves from IAM to EKS. Anyone who can create or update Pod Identity associations in a cluster can hand any role that trusts pods.eks.amazonaws.com to any service account; restrict that permission and add trust policy conditions on session tags.
  • Session tags enable one role for many workloads. eks-cluster-name, kubernetes-namespace and kubernetes-service-account can be used in ABAC conditions, but they also widen a role's reach if you rely on tags you have not tested.
  • Finish the job. Remove the OIDC provider trust, the eks.amazonaws.com/role-arn annotation and, eventually, the IAM OIDC provider, or you are running two trust paths instead of one.

When you need this

  • Role sprawl: the same role is needed in several clusters and its trust policy, at the default 2,048 characters, fits roughly four OIDC providers (about eight with an increased quota), according to AWS.
  • Provider limits: each IRSA cluster needs its own IAM OIDC provider, with a default limit of 100 per account.
  • STS throttling: with IRSA, pods call AssumeRoleWithWebIdentity themselves; with Pod Identity, EKS assumes the role and the node agent distributes credentials.
  • Separation of duties: you want IAM teams to own permissions and platform teams to own which workloads get them, instead of both editing trust policies.
  • Cluster rebuilds: blue/green cluster upgrades with IRSA require every role's trust policy to be updated for the new cluster's OIDC issuer.

Before you start

CheckRequirementHow to confirm (read-only)
Node typeLinux EC2 nodes (managed, self-managed node groups or Auto Mode)kubectl get nodes -o wide; exclude Fargate profiles and Windows node groups
Cluster versionAll supported versions; Kubernetes 1.28 needs platform version eks.4 or lateraws eks describe-cluster --name <cluster> --query cluster.platformVersion
SDK version in each imageFor example Boto3/botocore 1.34.41, AWS CLI v2 2.15.0, Java v2 2.21.30, Go v2 release-2023-11-14, JavaScript v3 3.458.0, .NET 3.7.734.0 or laterSoftware bill of materials or dependency lock files per image
Node role permissioneks-auth:AssumeRoleForPodIdentity (included in AmazonEKSWorkerNodePolicy)aws iam list-attached-role-policies on the node role
NetworkNodes reach the EKS Auth API; private subnets need an AWS PrivateLink interface endpoint for EKS AuthVPC endpoint list; test from a node
Proxies and IPv6169.254.170.23 and [fd00:ec2::23] in NO_PROXY; agent cannot start if IPv6 localhost is blocked unless IPv6 is disabled for itReview proxy environment in pod specs and node configuration
Security groups for podsVPC CNI with ENABLE_POD_ENI=true needs POD_SECURITY_GROUP_ENFORCING_MODE=standardkubectl -n kube-system get ds aws-node -o yaml

IRSA and Pod Identity compared

AttributeIRSAEKS Pod Identity
TrustRole trusts the cluster's IAM OIDC provider; condition on the service account subjectRole trusts pods.eks.amazonaws.com with sts:AssumeRole and sts:TagSession; EKS association names namespace and service account
Binding lives inIAM trust policy plus service account annotationEKS Pod Identity association (up to 5,000 per cluster)
Credential deliveryPod exchanges a projected token with STS AssumeRoleWithWebIdentityAgent DaemonSet on each node (ports 80 and 2703 on 169.254.170.23) calls AssumeRoleForPodIdentity
Pod environmentWeb identity token file and role ARN variablesAWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentials and AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE (token audience pods.eks.amazonaws.com, 24-hour expiry)
ABACNo session tagsSession tags: eks-cluster-arn, eks-cluster-name, kubernetes-namespace, kubernetes-service-account, kubernetes-pod-name, kubernetes-pod-uid
Cross-accountRole in the other account trusts the cluster's OIDC providerAssociation role in the cluster's account, with an optional target role in another account (targetRoleARN in eksctl)
EnvironmentsEKS, EKS Anywhere, Red Hat OpenShift Service on AWS, self-managed Kubernetes on EC2EKS on Linux EC2 nodes only

Step-by-step

Steps 1 and 2 are read-only. Steps 3 to 6 are additive. Steps 7 and 8 remove the old trust path and are destructive.

  1. Inventory IRSA bindings. List service accounts carrying the IRSA annotation and the roles they reference:
    kubectl get sa -A -o json | jq -r '.items[]
      | select(.metadata.annotations["eks.amazonaws.com/role-arn"] != null)
      | [.metadata.namespace, .metadata.name, .metadata.annotations["eks.amazonaws.com/role-arn"]] | @tsv'
    For each role, read its trust policy (aws iam get-role --role-name <role> --query Role.AssumeRolePolicyDocument) and record every OIDC provider and subject condition. Roles trusted by several clusters, and conditions using StringLike with wildcards, are the ones to tighten during migration.
  2. Plan with eksctl if you use it. eksctl utils migrate-to-pod-identity --cluster <cluster> without --approve only prints a plan: install the agent add-on, add the pods.eks.amazonaws.com trust to identified roles, create associations for iamserviceaccounts and migrate supported add-ons. Review the plan rather than approving it blind, because it edits role trust policies, including roles eksctl does not own.
  3. Install the agent. Skip this on EKS Auto Mode, where it is preinstalled.
    aws eks create-addon --cluster-name <cluster> --addon-name eks-pod-identity-agent
    kubectl get pods -n kube-system | grep eks-pod-identity-agent
    Pin an add-on version you have tested; AWS's example uses v1.0.0-eksbuild.1 and newer builds exist.
  4. Add the Pod Identity trust to the role, scoped by session tags. Add a statement alongside the existing OIDC statement, so both paths work during the cutover:
    {
      "Sid": "AllowEksAuthToAssumeRoleForPodIdentity",
      "Effect": "Allow",
      "Principal": { "Service": "pods.eks.amazonaws.com" },
      "Action": ["sts:AssumeRole", "sts:TagSession"],
      "Condition": {
        "StringEquals": {
          "aws:RequestTag/kubernetes-namespace": ["payments"],
          "aws:RequestTag/kubernetes-service-account": ["payments-api"]
        }
      }
    }
    The condition means a mistaken association in any cluster in the account cannot hand this role to a different workload. Add an aws:RequestTag/eks-cluster-name condition if the role should be usable from named clusters only.
  5. Create the association.
    aws eks create-pod-identity-association --cluster-name <cluster> \
      --namespace payments --service-account payments-api \
      --role-arn arn:aws:iam::111122223333:role/payments-api
    Running pods are unaffected at this point: the pod spec changes are added when a pod is created, and SDKs keep using the IRSA credentials found earlier in the chain. Allow a few seconds for the association to become consistent.
  6. Cut the workload over. Remove the eks.amazonaws.com/role-arn annotation from the service account and restart the workload (for example kubectl rollout restart deployment/payments-api -n payments) in a pilot environment first. Then verify inside a new pod:
    kubectl exec -n payments deploy/payments-api -- env | grep AWS_CONTAINER
    kubectl exec -n payments deploy/payments-api -- aws sts get-caller-identity
    The first command should show AWS_CONTAINER_CREDENTIALS_FULL_URI and AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE and no web identity variables; the second needs the AWS CLI in the image. Roll out by environment and keep the old trust statement until production has run for a full cycle.
  7. Remove the OIDC trust (destructive). When no AssumeRoleWithWebIdentity calls for the role have appeared in CloudTrail over the observation window, delete the OIDC statement from the trust policy. With eksctl, --remove-oidc-provider-trust-relationship does this for iamserviceaccounts; for add-ons eksctl always removes it.
  8. Retire the OIDC provider (destructive). Once no role in the account trusts the cluster's IAM OIDC provider, delete the provider. Keep it if anything else (for example a non-AWS consumer of the cluster's tokens) depends on it.

Decision guidance

SituationChoice
Linux EC2 nodes, supported SDKs, one AWS accountMigrate; the main gain is reusable roles and simpler cluster rebuilds
Fargate, Windows nodes, EKS Anywhere, ROSA or self-managed clustersStay on IRSA for those workloads; tighten trust conditions to exact subjects
Image with an old SDK you cannot rebuild yetStay on IRSA until rebuilt; an old SDK will not find the container credential provider
Many similar workloads needing the same access to their own dataOne role with ABAC on kubernetes-namespace or eks-cluster-name session tags, tested with real requests
Session policies or very large policiesDisable session tags on the association (needed for session policies, and the fix for PackedPolicyTooLarge), and use one role per workload
Resources in another accountUse the target role option rather than putting cross-account trust on the association role

Small estates with a few clusters can migrate by hand in a day per cluster. Large estates should manage associations in infrastructure as code next to the role definitions, and treat the eks:CreatePodIdentityAssociation and eks:UpdatePodIdentityAssociation permissions as privileged, because that is now where workload-to-role binding is decided.

Verify it worked

  • Pods: new pods carry the Pod Identity variables and token volume; get-caller-identity returns the expected role session.
  • CloudTrail: the role is assumed through EKS Pod Identity, and AssumeRoleWithWebIdentity events for the role stop after cutover.
  • Associations: aws eks list-pod-identity-associations --cluster-name <cluster> matches the inventory from step 1, one entry per migrated service account.
  • Negative test: a pod in another namespace using a service account without an association receives no role credentials.

Rollback and common errors

  • Workload fails after cutover: while the OIDC trust is still on the role, re-add the eks.amazonaws.com/role-arn annotation and restart; the pod returns to IRSA.
  • Pod still uses IRSA after the association: expected until the annotation is removed and the pod is recreated, because earlier credentials in the chain win.
  • No credentials, connection refused to 169.254.170.23: the agent is not running on that node, a proxy is intercepting the call, or IPv6 is blocked and the agent failed to start.
  • Access denied on AssumeRole: the trust policy lacks sts:TagSession, or a session tag condition does not match the namespace or service account.
  • Agent cannot get credentials in private subnets: missing PrivateLink endpoint for EKS Auth, or the node role lacks eks-auth:AssumeRoleForPodIdentity.
  • PackedPolicyTooLarge: disable session tags on that association.

Common failure patterns

  • Two trust paths forever: associations are added but the OIDC trust statements and providers are never removed, so a compromised or recreated cluster can still use IRSA.
  • Unconditioned pods.eks.amazonaws.com trust: a role trusting the service principal with no session tag conditions can be bound to any service account in any cluster in the account by whoever can create associations.
  • Broad association rights: eks:CreatePodIdentityAssociation granted to all cluster operators makes them able to give any eligible role to their own pods.
  • Ignoring the node: containers are not a security boundary and Pod Identity does not change that. Pods with hostNetwork: true can still reach IMDS and the node role; restrict them with admission policy and IMDSv2 hop limits. See the EC2 Instance Metadata Service Hardening Guide.
  • ABAC without testing: an S3 policy keyed on ${aws:PrincipalTag/eks-cluster-name} silently grants every workload in the cluster access to the cluster's data if the resource tags are broad.

Detection and measurement

  • Count of IRSA-annotated service accounts per cluster (target: only workloads that cannot migrate).
  • Roles that still trust an IAM OIDC provider after migration, and OIDC providers with no trusting roles.
  • Roles trusting pods.eks.amazonaws.com without namespace and service account conditions (target zero).
  • Pod Identity association changes outside infrastructure as code, from CloudTrail (target zero).
  • AssumeRoleWithWebIdentity calls per day for migrated roles (should reach zero).

Framework mapping

FrameworkReferenceRelevance
NIST SP 800-53 Rev 5IA-9 Service Identification and Authentication; AC-6 Least PrivilegeWorkload-specific roles bound by namespace and service account
NIST SP 800-53 Rev 5AC-2 Account Management; CM-8 System Component InventoryAssociation inventory and removal of unused trust paths
NIST CSF 2.0PR.AA-01; PR.AA-05Service identities managed; permissions enforced and reviewed
MITRE ATT&CK v20T1552.005 Cloud Instance Metadata API; T1078.004 Cloud AccountsNode credential theft and abuse of workload roles

Practitioner checklist

  • Inventory IRSA annotations and every trust policy statement per role.
  • Exclude Fargate, Windows and non-EKS workloads, and images below the minimum SDK versions.
  • Install and pin the eks-pod-identity-agent add-on; add the EKS Auth PrivateLink endpoint for private clusters.
  • Add pods.eks.amazonaws.com trust with kubernetes-namespace and kubernetes-service-account conditions.
  • Create associations, then remove annotations and restart per workload, pilot first.
  • Confirm new credentials in pods and CloudTrail before removing OIDC trust.
  • Remove OIDC trust statements and unused IAM OIDC providers.
  • Restrict who can create or update Pod Identity associations and manage them as code.

Standards and references

Related NHI Mgmt Group resources: EKS Identity Hardening Guide · Amazon EKS Security Hardening Guide · Cloud Workload Identity Guide · Multi-Cloud Workload Identity Troubleshooting Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 28 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.