Join our Newsletter — 33% off our NHI Course
Home› Guides› EKS Identity Hardening Guide: Pod Identity, IRSA and…
Guide Cloud & Workload Identity

EKS Identity Hardening Guide: Pod Identity, IRSA and Access Entries

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

Amazon EKS joins two identity systems, AWS IAM and Kubernetes RBAC, and most EKS compromises exploit the seams between them: a node role every pod can borrow, a cluster creator with permanent cluster-admin, or an aws-auth ConfigMap nobody reviews. This guide covers the EKS-specific controls that close those seams: access entries and access policies in place of aws-auth, EKS Pod Identity and IAM roles for service accounts (IRSA), instance metadata (IMDS) restrictions, the node and add-on roles, and the logs that show who did what. It assumes you already know the Kubernetes basics of service account tokens, RBAC and federation, which are covered in the Kubernetes NHI Security Guide and the Workload Identity Federation Guide. It is written for platform engineers, cloud security teams and auditors who run or assess production EKS clusters.

Key takeaways

  • Move to access entries and set the mode to API. AWS describes aws-auth as deprecated; access entries are managed through the EKS API, show up in CloudTrail and cannot lock you out with a YAML typo. The mode change is one-way, so plan it.
  • Remove the cluster creator's standing admin. Create clusters with bootstrapClusterCreatorAdminPermissions=false or disassociate AmazonEKSClusterAdminPolicy afterwards. In CONFIG_MAP mode that access cannot be revoked at all.
  • Prefer EKS Pod Identity, keep IRSA where it is the only option. Pod Identity needs no per-cluster OIDC provider, adds session tags for ABAC and separates association management (EKS) from permissions (IAM). IRSA remains necessary on Fargate, EKS Anywhere and self-managed clusters.
  • Stop pods inheriting the node role. Require IMDSv2 with a hop limit of 1 on node launch templates and move aws-node off the node role, otherwise every pod on a node holds the node's AWS permissions.
  • Turn on control plane logging. All five log types are off by default. Without audit and authenticator logs you cannot map a Kubernetes action back to the IAM session that performed it.

How identity and access work in EKS

Every request to the EKS API server is authenticated by AWS IAM and then authorised by Kubernetes RBAC (or by an EKS access policy, which EKS evaluates alongside RBAC). On the workload side, pods obtain AWS credentials through one of three paths, and the path that wins is the first one the AWS SDK default credential chain finds. Getting EKS identity right means controlling all four planes in the table below.

PlaneWho or whatEKS mechanismMain risk
Human and pipeline access to the Kubernetes APIIAM roles assumed by engineers (often via IAM Identity Center) and CI/CD rolesAccess entries with access policies or Kubernetes groups; legacy aws-auth ConfigMapOver-broad mappings to system:masters; unreviewed ConfigMap edits
Cluster management in AWSIAM principals calling eks:*IAM policies on the EKS service APIAnyone who can call CreateAccessEntry or AssociateAccessPolicy can grant themselves cluster-admin
Workload access to AWSPods via service accountsEKS Pod Identity associations or IRSAShared roles, wildcard trust, fallback to node role
Node and add-on access to AWSKubelet, VPC CNI (aws-node), controllersNode IAM role (instance profile); add-on rolesNode role readable by every pod through IMDS

Two consequences matter for hardening. First, IAM permissions on the EKS API are a privilege escalation path into Kubernetes: eks:CreateAccessEntry and eks:AssociateAccessPolicy are, in effect, cluster-admin grants and belong in the same review set as iam:PassRole. Second, Kubernetes permissions are a path into AWS: anyone who can create a pod in a namespace can run it under any service account in that namespace, and therefore use whatever IAM role that service account is associated with. The Kubernetes side of that problem is covered in the Kubernetes RBAC Guide.

Admin roles and privileged access

Access entries, access policies and authentication modes

An access entry ties one IAM principal to a cluster. You then either associate one or more AWS-managed access policies (with a cluster or namespace scope) or map the entry to Kubernetes groups and grant those groups permissions with RBAC. The cluster's authentication mode decides which sources EKS reads:

  • CONFIG_MAP: only the aws-auth ConfigMap. Legacy; the creator's admin cannot be removed.
  • API_AND_CONFIG_MAP: both. The migration state. Only the creator's entry is created automatically; every other aws-auth mapping must be recreated as an access entry by hand.
  • API: access entries only. The target state recommended in the EKS Best Practices Guide.

The switch is one-way: AWS states that you cannot change back to a mode that removes the EKS API and access entries. Older Kubernetes versions need a minimum platform version (for example eks.6 on 1.28 and eks.1 on 1.29) before access entries can be enabled.

Access policy (arn:aws:eks::aws:cluster-access-policy/...)EffectHardening note
AmazonEKSClusterAdminPolicyAll verbs on all resources, cluster-wideBreak-glass and platform automation only; never a standing human grant
AmazonEKSAdminPolicyNamespace admin: workloads, Secrets, Roles and RoleBindings, ServiceAccount impersonationCan grant itself more within the namespace; scope to named namespaces
AmazonEKSEditPolicyCreate and change most namespaced resources; reads Secrets; no RBAC permissionsStill able to run pods as any service account in scope, so it inherits their IAM roles
AmazonEKSViewPolicyRead most namespaced resources, excluding SecretsSafe default for developers and support
AmazonEKSAdminViewPolicyRead all resources including SecretsTreat as sensitive despite the "view" name
AmazonEKSSecretReaderPolicyGet, list and watch on SecretsEquivalent to credential access; restrict and monitor

Removing standing cluster-admin

  1. New clusters: create with --access-config authenticationMode=API,bootstrapClusterCreatorAdminPermissions=false and add an explicit admin entry for a platform role instead.
  2. Existing clusters: after confirming another admin path works, run aws eks disassociate-access-policy for AmazonEKSClusterAdminPolicy on the creator principal, or delete that access entry.
  3. Break-glass: keep one dedicated IAM role with the cluster admin policy, assumable only through a controlled process (approval, MFA, session recording via CloudTrail), and alert on every assumption.
  4. Clusters stuck in CONFIG_MAP mode: the creator keeps system:masters permanently, so the best practice guidance is to create clusters from a dedicated automation role nobody else can assume and audit it.

Human access should use IAM roles federated from your identity provider rather than IAM users, so that joiner, mover and leaver changes happen in one place. If you must keep aws-auth during migration, prefer mapRoles over mapUsers, edit it with tooling rather than by hand, and include {{SessionName}} in the mapped username so the Kubernetes audit log records the individual rather than just the shared role. For the general IAM role design see the AWS IAM Policies and Roles Guide; for just-in-time patterns see the Kubernetes RBAC Guide.

Integrations, API tokens and service accounts

EKS Pod Identity versus IRSA

Both mechanisms map a Kubernetes service account to an IAM role and deliver short-lived credentials. The federation mechanics behind IRSA are explained in the Workload Identity Federation Guide; the table focuses on what differs for hardening.

AttributeEKS Pod IdentityIRSA
Trust anchorService principal pods.eks.amazonaws.com, same for every clusterPer-cluster IAM OIDC identity provider
Who binds role to service accountEKS association (eks:CreatePodIdentityAssociation); permissions stay in IAMRole trust policy sub condition plus service account annotation
Scope of a bindingOne role to one service account in one namespace of one cluster; up to 5,000 associations per clusterWhatever the trust policy sub and aud conditions allow
Session tagsSix transitive tags: eks-cluster-arn, eks-cluster-name, kubernetes-namespace, kubernetes-service-account, kubernetes-pod-name, kubernetes-pod-uidNone
Credential deliveryPod Identity Agent DaemonSet on 169.254.170.23 / [fd00:ec2::23], ports 80 and 2703SDK calls sts:AssumeRoleWithWebIdentity using the projected token
Where supportedEKS on Linux EC2 nodes; not Fargate, Windows nodes, Outposts, EKS Anywhere or self-managed KubernetesAny cluster with a public OIDC issuer, including Fargate
Cross-accountRole must be in the cluster's account; chain into the target account with role assumptionTrust policy in the target account can name the cluster's OIDC provider

Decision guidance: use Pod Identity by default on EC2 Linux nodes. It lets one role serve many clusters without editing trust policies, and its session tags make attribute-based access control possible: a single role can read only S3 objects tagged with the caller's own eks-cluster-name or kubernetes-namespace by comparing against ${aws:PrincipalTag/...}. Keep IRSA for Fargate, Windows and non-EKS clusters, or where a cross-account trust must be expressed in the target account. Small estates with a handful of clusters gain less from ABAC and can run one role per application; large multi-tenant estates benefit most from tag-based policies because they avoid thousands of near-identical roles.

Hardening the role side

  • Pod Identity trust policy: allow sts:AssumeRole and sts:TagSession for pods.eks.amazonaws.com, and add "aws:SourceOrgId": "${aws:ResourceOrgId}" (or a source account or cluster ARN condition) to prevent confused deputy use from clusters outside your organisation.
  • IRSA trust policy: always pin both oidc.eks.<region>.amazonaws.com/id/<ID>:aud to sts.amazonaws.com and :sub to system:serviceaccount:<namespace>:<name> with StringEquals. A missing sub condition lets every service account in the cluster assume the role.
  • One role per application: the exception is a deliberately designed ABAC role using Pod Identity session tags.
  • Permissions boundaries: attach a boundary to every workload role so that a role edited by a delegated team cannot exceed a defined maximum.
  • Session tag size: if a workload hits PackedPolicyTooLarge, session tags can be disabled per association, but any ABAC policy relying on them then stops matching. Record that as an exception.
  • Role-tag collisions: EKS-supplied session tags override IAM role tags with the same key, which is useful: a role tagged with a false eks-cluster-name cannot spoof it.

The node role and IMDS

Every EC2 node carries an instance profile. A pod that does not use Pod Identity or IRSA, or whose SDK falls through the credential chain, can query the instance metadata service and receive the node role's credentials (MITRE ATT&CK T1552.005, Cloud Instance Metadata API). The node role typically carries AmazonEKS_CNI_Policy and AmazonEC2ContainerRegistryReadOnly, so every pod can manipulate network interfaces and pull any image in the account's registries.

  • Launch template: set http_tokens = "required" (IMDSv2) and http_put_response_hop_limit = 1. The extra network hop from a pod's namespace then prevents the response reaching the pod. EKS-provisioned defaults use a hop limit of 2, so this must be set explicitly.
  • Do not disable IMDS entirely: node components such as the termination handler depend on it. If a specific application needs IMDS, keep IMDSv2 and accept hop limit 2 only on the node group that runs it.
  • Host-network pods: pods with hostNetwork: true always reach IMDS regardless of the hop limit. Block them with admission policy outside system namespaces; see the Kubernetes Admission Control Guide.
  • Shrink the node role: move the aws-node DaemonSet to Pod Identity (supported from VPC CNI v1.15.5) or IRSA and remove AmazonEKS_CNI_Policy from the node role.

Remaining static credentials

Access keys stored in Kubernetes Secrets or environment variables bypass every control above. The Tesla Kubernetes cryptojacking incident is the standard example: an unauthenticated console led to a pod holding AWS keys, and the keys led to the AWS account. Inventory such keys with IAM credential reports, migrate the consumers, and see the Kubernetes Secrets Security Guide. External systems that need Kubernetes API access (for example a CI runner outside AWS) should assume an IAM role mapped through an access entry rather than hold a long-lived service account token Secret.

Logging and detection

Control plane logging is off by default and is enabled per log type. Logs land in the CloudWatch log group /aws/eks/<cluster-name>/cluster, one stream per component.

SourceWhat to watch forWhy it matters
audit log (kube-apiserver-audit-*)New ClusterRoleBindings to cluster-admin, create on serviceaccounts/token, reads of Secrets, pods/exec in sensitive namespaces, anonymous requestsKubernetes-side privilege escalation (T1098.006, Additional Container Cluster Roles) and discovery (T1613)
authenticator log (authenticator-*)Which IAM ARN and session mapped to which Kubernetes usernameJoins audit events to the IAM session and therefore the human
CloudTrail (EKS API)CreateAccessEntry, AssociateAccessPolicy, UpdateClusterConfig (authentication mode, endpoint, logging), CreatePodIdentityAssociationAWS-side grants of cluster access and changes that weaken logging
CloudTrail (STS)AssumeRoleWithWebIdentity from IRSA roles, AssumeRole by pods.eks.amazonaws.com with session tags, node role credentials used from outside the VPCWorkload credential use and theft (T1528, T1078.004)
GuardDuty EKS ProtectionPolicy:Kubernetes/AnonymousAccessGranted, CredentialAccess:Kubernetes/SuccessfulAnonymousAccess, Policy:Kubernetes/AdminAccessToDefaultServiceAccount, PrivilegeEscalation:Kubernetes/AnomalousBehavior.RoleBindingCreated, CredentialAccess:Kubernetes/AnomalousBehavior.SecretsAccessedManaged detections over the audit stream

Metrics that show the programme is working:

  • Percentage of clusters in API authentication mode (target 100%).
  • Number of principals with AmazonEKSClusterAdminPolicy or system:masters per cluster (target: break-glass role plus platform automation only).
  • Percentage of workloads calling AWS that use Pod Identity or IRSA, against those using static keys or the node role (target: no static keys).
  • Percentage of node groups with IMDSv2 required and hop limit 1.
  • Percentage of clusters with audit and authenticator logging enabled.
  • Time from an unexpected cluster-admin grant (CloudTrail or audit) to alert.

Hardening baseline

Roll changes out cluster by cluster, starting with a non-production cluster that mirrors production add-ons.

  1. Observe: enable all five control plane log types, export aws-auth, list access entries (aws eks list-access-entries), Pod Identity associations and IRSA roles, and record which pods currently obtain credentials from IMDS (CloudTrail calls made with the node role from pods).
  2. Recreate access: switch to API_AND_CONFIG_MAP, recreate each aws-auth mapping as an access entry with the narrowest access policy and namespace scope, then compare authenticator logs to confirm users now resolve through entries. Rollback at this stage is simple: the ConfigMap still works.
  3. Cut over: switch to API. This cannot be reverted, so do it only once a break-glass entry is tested and every mapping has a matching entry.
  4. Remove creator admin and restrict IAM permissions on eks:CreateAccessEntry, eks:AssociateAccessPolicy and eks:UpdateClusterConfig to the platform pipeline role, ideally with an SCP.
  5. Migrate workloads to Pod Identity (or IRSA where required) one namespace at a time. Confirm in CloudTrail that the new role is in use before removing old keys.
  6. Close IMDS: roll new launch templates with hop limit 1 through a canary node group; roll back by reverting the template version if a workload breaks.
  7. Restrict the endpoint: enable private endpoint access and either disable public access or limit it to known CIDR ranges.
  8. Enforce: disable automountServiceAccountToken on default service accounts, remove system:unauthenticated from all bindings except system:public-info-viewer (older clusters may still bind it to system:discovery and system:basic-user), and block hostNetwork pods through admission control.

Framework mapping

Control areaNIST SP 800-53 Rev. 5NIST CSF 2.0CIS Controls v8.1ISO/IEC 27001:2022 Annex A
Access entries, removing creator adminAC-2, AC-6PR.AA-05Control 5, Control 6A.5.18, A.8.2
Pod Identity, IRSA, no static keysIA-5, IA-9PR.AA-01Control 6A.5.17
IMDS restriction, node role reductionAC-6PR.AA-05Control 6A.5.15
Control plane logs, CloudTrail, GuardDutyAU-2, AU-6DE.CM-03Control 8A.8.15

Common misconfigurations

  • IRSA trust without a sub condition. Copying a trust policy that checks only aud lets any service account in the cluster assume the role, including ones created by a tenant with namespace-level rights.
  • "Edit" treated as low risk. AmazonEKSEditPolicy cannot touch RBAC, but it can create a pod using any service account in the namespace and so inherit every IAM role associated with those accounts. Review namespace edit grants together with the roles mapped in that namespace.
  • Half-finished migration. Clusters left in API_AND_CONFIG_MAP keep a second, unaudited path: a later aws-auth edit grants access that never appears in access entry reviews.
  • Hop limit left at 2. Pod Identity is deployed but IMDS is still reachable, so any pod without an association silently falls back to the node role, which often has broad ECR and EC2 network rights.
  • Logging off or partial. Only api logs enabled, so there is no audit trail of RBAC changes and no authenticator mapping from Kubernetes user to IAM session.
  • Static keys left in Secrets after migration. Workloads move to Pod Identity but old access keys remain active in IAM and in Secrets, which is exactly the exposure seen in the Tesla incident. Deactivate and delete keys once CloudTrail shows no further use.

Practitioner checklist

  • Every cluster is in API authentication mode and aws-auth has been deleted or emptied.
  • The cluster creator has no standing access entry; one tested break-glass role holds AmazonEKSClusterAdminPolicy.
  • Human access uses federated IAM roles mapped to namespace-scoped access policies, not IAM users.
  • IAM rights to eks:CreateAccessEntry, eks:AssociateAccessPolicy and eks:UpdateClusterConfig are limited to the platform pipeline and alerted on.
  • Workloads use Pod Identity (trust policy with aws:SourceOrgId) or IRSA (trust pinned to aud and exact sub), with permissions boundaries.
  • Node launch templates require IMDSv2 with hop limit 1; hostNetwork pods are blocked outside system namespaces.
  • aws-node runs on its own role and AmazonEKS_CNI_Policy is off the node role.
  • No AWS access keys exist in Secrets, ConfigMaps or environment variables.
  • audit and authenticator control plane logs, CloudTrail and GuardDuty EKS Protection are enabled and routed to the SOC.
  • The API endpoint is private or restricted to known CIDR ranges.

Standards and references

Related NHI Mgmt Group resources: Kubernetes NHI Security Guide · Workload Identity Federation Guide · GKE Identity Hardening Guide · AKS Identity Hardening Guide · AWS IAM Policies and Roles Guide

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 26 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org