Migrate from IRSA to Pod Identity on EKS

3 minute read

In this post, I’m going to describe how to migrate from IRSA (IAM Roles for Service Accounts) to the newer EKS Pod Identity. Pod Identity simplifies the authentication between Kubernetes service accounts and IAM roles by removing the need for OIDC provider configuration and service account annotations. Pod Identity is an EKS add-on and runs as a DaemonSet on your cluster and uses the service principal (pods.eks.amazonaws.com) to establish that trust between an IAM role and a Kubernetes service account. I’ve described how to setup IRSA in a previous post here.

Prerequisites

Before migrating, ensure you have the EKS Pod Identity Agent addon enabled on your cluster:

 1resource "aws_eks_addon" "pod_identity_agent" {
 2  cluster_name                = aws_eks_cluster.cluster.name
 3  addon_name                  = "eks-pod-identity-agent"
 4  addon_version               = "v1.0.0"
 5  resolve_conflicts_on_create = "OVERWRITE"
 6  resolve_conflicts_on_update = "OVERWRITE"
 7  depends_on = [
 8    aws_eks_cluster.cluster,
 9    aws_eks_node_group.core
10  ]
11}

Migration Steps

1. Update IAM Trust Policy

The trust policy changes from OIDC federation to a service principal trust.

Before (IRSA):

 1data "aws_iam_policy_document" "assume_role_policy" {
 2  statement {
 3    actions = ["sts:AssumeRoleWithWebIdentity"]
 4    effect  = "Allow"
 5    condition {
 6      test     = "StringEquals"
 7      variable = "${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}:sub"
 8      values   = ["system:serviceaccount:${var.env}:${var.app}"]
 9    }
10    condition {
11      test     = "StringEquals"
12      variable = "${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}:aud"
13      values   = ["sts.amazonaws.com"]
14    }
15    principals {
16      identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}"]
17      type        = "Federated"
18    }
19  }
20}

After (Pod Identity):

 1data "aws_iam_policy_document" "pod_identity_trust" {
 2  statement {
 3    sid    = "EKSPodIdentityTrust"
 4    effect = "Allow"
 5    principals {
 6      type        = "Service"
 7      identifiers = ["pods.eks.amazonaws.com"]
 8    }
 9    actions = [
10      "sts:AssumeRole",
11      "sts:TagSession"
12    ]
13  }
14}

2. Update IAM Role

Update your IAM role to use the new trust policy:

 1resource "aws_iam_role" "app" {
 2  name               = "${var.app}-${var.env}"
 3  assume_role_policy = data.aws_iam_policy_document.pod_identity_trust.json
 4  tags = {
 5    service = var.app
 6  }
 7}
 8
 9resource "aws_iam_role_policy" "app" {
10  name = "${var.app}-${var.env}"
11  role = aws_iam_role.app.name
12  policy = jsonencode({
13    Version : "2012-10-17",
14    Statement : [
15      {
16        Effect : "Allow",
17        Action : ["secretsmanager:GetSecretValue"],
18        Resource : [
19          "arn:aws:secretsmanager:${var.region}:${data.aws_caller_identity.current.account_id}:secret:${var.env}/${var.app}-??????"
20        ]
21      }
22    ]
23  })
24}

3. Create Pod Identity Association

Add the Pod Identity Association to link your IAM role to your Kubernetes service account:

1resource "aws_eks_pod_identity_association" "app" {
2  cluster_name    = var.eks_cluster
3  namespace       = var.env
4  service_account = var.app
5  role_arn        = aws_iam_role.app.arn
6}

This resource creates the binding between your cluster, namespace, service account, and IAM role. The EKS Pod Identity Agent handles the credential injection automatically.

Kubernetes Changes

The good news is that your Kubernetes manifests require minimal changes. With IRSA, you needed to annotate your service account with the role ARN:

IRSA Service Account:

1apiVersion: v1
2kind: ServiceAccount
3metadata:
4  name: my-app
5  namespace: production
6  annotations:
7    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-production

Pod Identity Service Account:

1apiVersion: v1
2kind: ServiceAccount
3metadata:
4  name: my-app
5  namespace: production

The annotation is no longer needed. The Pod Identity Agent uses the association defined in Terraform to determine which role to assume.

Verification

After applying your changes, verify the association is working:

 1# List pod identity associations
 2aws eks list-pod-identity-associations --cluster-name your-cluster
 3
 4# Describe a specific association
 5aws eks describe-pod-identity-association \
 6  --cluster-name your-cluster \
 7  --association-id <association-id>
 8
 9# Test from within a pod
10kubectl exec -it <pod-name> -n <namespace> -- aws sts get-caller-identity

The get-caller-identity command should return the assumed role ARN, confirming the Pod Identity is working correctly.

You will see the mapping of the IAM role ARN and service account in the Access tab in the EKS console under “Pod Identity associations”.