The IAM Role for Service Account behind the scene
Within Amazon EKS, we use IAM Role for Service Account (IRSA) or Pod Identity Agent (IRSAv2) to grant applications permission to call AWS APIs. While Pod Identity Agent won’t be covered in this article, we’ll explore how IRSA works in your EKS cluster. Understanding this feature better will help you troubleshoot issues when they arise.
What is IRSA and Why Do We Need It?
Applications running in your cluster may need to call AWS APIs to manage AWS resources. For example, when you install an EKS Add-on like the EBS CSI Controller, it needs to interact with AWS APIs to perform tasks such as mounting EBS volumes to EKS worker nodes. The kubelet can then mount these volumes into Pods via the Container Storage Interface.
Let’s look at an example of a Service Account. In the following output, we can see the Service Account s3-readonly-sa
has an annotation eks.amazonaws.com/role-arn
with the value arn:aws:iam::123456789012:role/AmazonEKSPodS3ReadOnlyAccessRole
:
1 | kubectl describe sa s3-readonly-sa |
This means that any Pod associated with this service account will be granted permissions to operate AWS APIs according to the IAM policies attached to the specified IAM role.
How IRSA Works
Step 1: Pod Mutation
You might wonder, “How does the Service Account give a Pod permission to call AWS APIs?”
When a Pod is created, the Kubernetes API server receives the creation request. In EKS, a pre-installed AdmissionWebhook called pod-identity-webhook
intercepts this request. The API server passes the Pod manifest to the assigned controller, which then mutates or validates the Pod specification.
Here’s an example of the MutatingWebhook resource installed in an EKS cluster. Notice in the Rules block that it’s registered for verb=CREATE requestURI=/v1/pods/
:
1 | kubectl describe mutatingwebhookconfiguration pod-identity-webhook |
Step 2: Injected Information in Newly Created Pods
When a Pod is created, the MutatingWebhook captures the event, and the Mutating Controller updates the Pod manifest by adding necessary information to make IRSA work. We can observe these changes using the kubectl get pod
command:
1 | $ kubectl get pod mypod -o yaml |
The mutating webhook adds several components:
- Environment variables in
.spec.containers[].env
: These variables are used by the AWS SDK to identify which AWS regional endpoint to interact with. - Volume mounts in
.spec.containers[].volumeMounts
: These instruct kubelet to mount the secret token into the container’s filesystem. - Volumes in
.spec.volumes
: Two volumes are configured - one for calling the Kubernetes API server and another for interacting with AWS API server.
Step 3: TokenRequest Initiated by Kubelet
When the Pod is created on a node, kubelet initiates a TokenRequest to the EKS control plane. The control plane returns a JWT token, which is stored in the mounted location:
1 | bash-4.2# ls /var/run/secrets/eks.amazonaws.com/serviceaccount |
This credential can be decoded using a JWT tool. The information must exactly match what’s in the IAM Role’s Trust Entity; otherwise, you’ll encounter authentication errors when the Pod tries to authenticate with the AWS STS service.
Step 4: AWS SDK’s Interaction with AWS STS Service
Finally, the program in the Pod uses the AWS SDK to interact with AWS APIs. The SDK looks for AWS credentials using the AWS_WEB_IDENTITY_TOKEN_FILE
environment variable. The Pod then makes an AssumeRoleWithWebIdentity API call to assume the IAM role, granting it access according to the policies attached to that role.
1 | bash-4.2# aws sts get-caller-identity |
What Happens Without a Dedicated IAM Role?
If you don’t configure your application with a dedicated IAM role, the Pod (AWS SDK) will attempt to get credentials from the EC2 Instance Metadata Service (IMDS). Here’s the workflow:
- AWS SDK fails to find credentials in local files (e.g.,
/var/run/secrets/eks.amazonaws.com/serviceaccount/token
) - AWS SDK attempts to get credentials by calling the EC2 Metadata Service IP (169.254.169.254)
- The request travels through the Pod’s default gateway to the EKS node’s main interface (eth0)
- The EKS node forwards the request to EC2 Metadata Service and receives temporary credentials
- The EKS node returns the credentials to the Pod
This approach has a significant security implication: the Pod inherits all permissions granted to the EC2 instance. EKS worker nodes typically have several AWS managed IAM policies for tasks like pulling images from ECR or attaching network interfaces to EC2 instances.
While it’s possible to use the EKS worker node’s IAM role for Pods, this practice poses security risks to your AWS account and should be avoided.
Conclusion
We’ve explored the internal mechanisms of how IRSA works within Pods and EKS. This understanding is crucial for proper implementation and troubleshooting. Feel free to share any questions or comments!
The IAM Role for Service Account behind the scene