Cloud Security Wire
AWS Azure GCP RSS
AWS Hardening Guide high

EKS IRSA and Pod Identity: Audit Your Role Trust Policies Before a Pod Compromise Does It for You

Which pods can assume which AWS roles is decided by a trust policy most teams never re-read. A practical audit and hardening guide for EKS IRSA and Pod Identity, with CLI commands and policy snippets.

By Cloud Security Wire · ·
#AWS#EKS#IRSA#Pod Identity#IAM#trust policy#Kubernetes#IMDS
High Severity

This issue has been assessed as high severity. Review affected configurations immediately.

Why this guide

This is an evergreen hardening guide, not breaking news. Our search for cloud security items from the past 48 hours found nothing dated and openable as of 3 November 2026, so we are not forcing a news hook.

On EKS, the boundary between “a pod was compromised” and “an AWS account was compromised” is the IAM role trust policy. Sources we opened on 3 November 2026:

All three are AWS documentation, so every claim below attributed to them is single-vendor. The commands are untested in our lab and use placeholders. Statements marked “our assessment” are our own judgement.

What the documentation says

  • Both IRSA and Pod Identity associate an IAM role with a Kubernetes service account so pods stop sharing the node role.
  • Credential isolation only holds when access to the EC2 Instance Metadata Service (IMDS) is restricted. If IMDS is not restricted, containers can also reach the node IAM role and may reach roles of other pods on the same node. Pods with hostNetwork: true always have IMDS access.
  • AWS states that containers are not a security boundary and that node components such as kubelet, kube-proxy and CSI drivers have extra Kubernetes API permissions.
  • Pod Identity uses the single principal pods.eks.amazonaws.com. The documented trust policy allows sts:AssumeRole and sts:TagSession, and AWS says session tags can be used in condition keys to restrict which service accounts, namespaces and clusters may use the role.

Our assessment: the Pod Identity trust policy shown in the docs is deliberately generic. Any association in any cluster in the account can point at a role that trusts that principal, so the role is only as tight as the conditions you add and who may create associations.

Audit 1: block pod access to IMDS

Check that nodes require IMDSv2 with a hop limit of 1, which stops containers from reaching the endpoint through the node’s network namespace:

aws ec2 describe-instances --filters "Name=tag:eks:cluster-name,Values=CLUSTER_NAME" \
  --query "Reservations[].Instances[].[InstanceId,MetadataOptions.HttpTokens,MetadataOptions.HttpPutResponseHopLimit]" \
  --output table

Anything showing optional or a hop limit above 1 needs a reason. Set it on a launch template, then roll the node group:

aws ec2 modify-instance-metadata-options --instance-id i-0123456789abcdef0 \
  --http-tokens required --http-put-response-hop-limit 1

Test first: workloads that rely on node credentials or hostNetwork will break.

Audit 2: find IRSA roles with loose trust

List roles whose trust policy uses web identity federation, then inspect the conditions:

aws iam list-roles --query "Roles[].RoleName" --output text | tr '\t' '\n' | while read r; do
  aws iam get-role --role-name "$r" --query Role.AssumeRolePolicyDocument --output json \
  | jq -r --arg r "$r" '.Statement[] | select(.Action=="sts:AssumeRoleWithWebIdentity")
      | "\($r)\t\(.Principal.Federated)\t\(.Condition // "NO CONDITION")"'
done

A trust policy for IRSA should pin both the audience and the exact service account. A pattern of this shape (placeholders) is the target:

{
  "Effect": "Allow",
  "Principal": {"Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.REGION.amazonaws.com/id/OIDC_ID"},
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "oidc.eks.REGION.amazonaws.com/id/OIDC_ID:aud": "sts.amazonaws.com",
      "oidc.eks.REGION.amazonaws.com/id/OIDC_ID:sub": "system:serviceaccount:NAMESPACE:SERVICE_ACCOUNT"
    }
  }
}

Flag any role with no sub condition, or with StringLike and a wildcard such as system:serviceaccount:*:*. Our assessment: such a role is assumable by any service account in the cluster.

Audit 3: review Pod Identity associations

aws eks list-pod-identity-associations --cluster-name CLUSTER_NAME
aws eks describe-pod-identity-association --cluster-name CLUSTER_NAME \
  --association-id ASSOCIATION_ID

Per the AWS page, you can create an association for a namespace or service account name that does not yet exist in the cluster. It only works once someone creates them. Our assessment: treat unexpected associations pointing at privileged roles as a finding, because an attacker with namespace-create rights could later activate them.

Hardening steps

  1. Restrict IMDS (Audit 1) on every node group.
  2. Give each workload its own service account and role. Do not attach broad policies such as AdministratorAccess or s3:* on *.
  3. Add aud and sub conditions to every IRSA trust policy. For Pod Identity, add session-tag conditions as described in the Service Authorization Reference linked from the AWS page.
  4. Restrict who holds eks:CreatePodIdentityAssociation and iam:PassRole. The AWS page states the creator needs iam:PassRole.
  5. Alert on AssumeRoleWithWebIdentity and EKS Auth calls from unexpected roles. AWS states CloudTrail records access events for both mechanisms.
  6. Remove unused OIDC providers and associations from decommissioned clusters.

What we could not verify

  • Exploitation in the wild: no evidence found as of 3 November 2026 in the three AWS pages we opened, which do not discuss attacks at all. This is not proof of absence.
  • Exact Pod Identity session tag condition key names: not shown in the pages we opened. Take them from the AWS Service Authorization Reference.
  • All commands: untested in our lab.
← All Analysis Subscribe via RSS