IRSA Architecture in Amazon EKS: Solving a Real Access Problem
Introduction
When using Kubernetes, such as Amazon EKS, apps rarely run on their own. Most workloads require interaction with AWS services such as S3, DynamoDB, or Secrets Manager. At first glance, it looks like giving that access is easy. In practice, it quickly becomes a very important security and design issue.
The problem isn’t just letting people in; it’s also making sure that access is safe, scalable, and follows the principle of least privilege. This is where our setup really fell short, and IAM Roles for Service Accounts (IRSA) gave us a clean and dependable answer.
The Problem We Faced
Our EKS cluster hosted multiple microservices, each with different access requirements. Some services needed full access to specific resources, while others required strictly limited permissions.
Initially, we relied on the EC2 instance IAM role attached to worker nodes. This is a common default approach, but it introduced a significant issue: every pod running on a node inherited the same permissions.
In practical terms, this meant:
- A logging service could access DynamoDB even if it didn’t need to
- A simple API service had access to sensitive resources like Secrets Manager
- Any compromised pod could potentially access all resources available to the node
This created an over-permissioned environment and violated the principle of least privilege, making it unsuitable for a production-grade system.
Why Traditional Approaches Failed
We looked at common methods and found that they all had the same problems.
Node IAM roles do not offer workload-level isolation. AWS only knows that the EC2 instance is making the request, not the pod itself. Because of this, permissions can’t be limited to a specific service.
Another choice was to store AWS credentials in Kubernetes Secrets, but this came with risks to operations and security. It’s hard to change static credentials; they can be seen in logs or when things are set up wrong, and they add extra work to CI/CD pipelines.
We also looked at old workarounds like kiam and kube2iam. They did address some of these issues, but they also made things more complicated, relied on node-level interception, and weren’t great for long-term scalability.
We needed a solution that was both native and safe, and that didn’t add any extra work.
Introducing IRSA
IRSA (IAM Roles for Service Accounts) solves this problem by moving the access model from the infrastructure level to the workload level.
IRSA lets you link an IAM role directly to a Kubernetes Service Account instead of giving permissions to nodes. Pods run with service accounts, which lets each workload take on its own role with clearly defined permissions.
This changes the model in a big way: permissions are no longer shared across a node; instead, they are limited to the service that needs them.
How IRSA Works
IRSA uses a mix of Kubernetes service accounts, an OpenID Connect (OIDC) identity provider, and the AWS Security Token Service (STS).
Kubernetes gives a pod a signed JSON Web Token (JWT) that shows its service account identity when it starts. AWS IAM trusts the EKS cluster’s OIDC provider as a valid identity source.
When the application inside the pod needs to access AWS, it uses this token to call STS through the AssumeRoleWithWebIdentity API. AWS validates the token against the OIDC provider and checks whether the associated IAM role allows that specific service account to assume it.
STS gives you temporary credentials if validation works. The AWS SDK automatically rotates these credentials every so often, so you don’t have to do anything.
The IRSA Flow in Action

As shown in the diagram, the process is handled by a few key components working in sync:
- The Pod Identity Webhook: This is the “magic” behind the scenes. When a pod is created, this webhook mutates the pod specification to inject the AWS Role ARN and the path to the web identity token.
- The Role Reference: The Kubernetes Service Account acts as the bridge, containing an annotation that points directly to the IAM Role.
- The STS Exchange: Instead of using static keys, the pod sends its identity token to AWS STS. STS verifies this token against the OIDC provider and, if valid, sends back temporary credentials directly to the pod.
What Happens Under the Hood
The core of IRSA lies in identity validation and trust relationships.
Each pod receives a JWT token that encodes its service account identity. This token is signed by the Kubernetes control plane and can be verified by the OIDC provider configured in AWS IAM.
The IAM role associated with IRSA includes a trust policy that defines which identities are allowed to assume it. This policy typically restricts access to a specific service account within a specific namespace.
When STS receives a request, it validates the token signature, ensures it was issued by the trusted OIDC provider, and confirms that the identity matches the conditions defined in the IAM role. Only then are temporary credentials issued.
This entire process removes the need for static credentials while maintaining strict identity-based access control.
How This Solved Our Problem
After we put IRSA into place, we changed how we controlled access to individual services instead of shared infrastructure.
Each microservice was given its own IAM role that matched its job. For instance, a logging service could only write data to S3, and an application service could only read the DynamoDB tables it needed to.
This got rid of shared permissions between pods and made the risk surface much smaller. Access became easier to predict, easier to check, and in line with best practices for security.
Benefits in Our Context
Being able to enforce least privilege at the workload level was the most immediate benefit. Now, each service only has the permissions it needs to work.
We also took out all of the static AWS credentials from our CI/CD pipelines and Kubernetes manifests. STS now handles authentication dynamically, which lowers both risk and operational costs.
The system is less likely to leak information because credentials are only good for a short time and are automatically changed. Also, AWS CloudTrail logs now make it clear which service account did each action, making it easier to trace and audit.
When it comes to architecture, IRSA works well with a microservices environment. When new services are added, they can be given separate roles without affecting the work that is already being done.
Key Takeaways
When you use traditional methods to get to AWS in Kubernetes, you often give too many permissions or put your system at risk by using static credentials. IRSA solves both problems by using OIDC-based identity and temporary credentials issued by STS.
By linking IAM roles directly to Kubernetes service accounts, you control access to each workload in a very detailed, auditable, and secure way. The result is a system that is safer and easier to run on a large scale.
References
AWS IRSA Introduction:
https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/
EKS IAM Best Practices:
https://docs.aws.amazon.com/eks/latest/best-practices/identity-and-access-management.html