IRSA Uncovered: A Deep Dive into Kubernetes Service Accounts and IAM Roles in EKS
In today’s cloud-native ecosystem, security is paramount, and managing access in containerised applications remains a top priority. AWS’s IAM Roles for Service Accounts (IRSA) feature in Amazon EKS offers a secure way to assign AWS IAM roles to Kubernetes pods without embedding sensitive credentials. This article dives into how IRSA works, steps for implementing it in EKS, and essential tips for securing your applications.
Why Use IRSA?
By default, Kubernetes pods in Amazon EKS assume the IAM role associated with their EC2 nodes, granting each pod equal access to AWS services. IRSA provides a way to securely assign AWS permissions to pods by linking IAM roles directly to Kubernetes service accounts. This lets you:
- Restrict permissions to individual pods rather than entire nodes.
- Avoid long-term AWS credentials in code or environment variables.
- Apply the principle of least privilege, keeping permissions tight.
IRSA Architecture Overview
IRSA is built on three core components:
- OIDC Provider: AWS uses an OpenID Connect (OIDC) identity provider to authenticate the service account’s token.
- IAM Role with Trust Policy: An IAM role with a trust policy allows the service account to assume the role.
- Service Account Annotation: The Kubernetes service account links to the IAM role through an annotation.
Step 1: Configuring IRSA in EKS
Let’s walk through the complete implementation.
1. Set Up OIDC Provider
EKS clusters support OIDC, but you need to enable an identity provider if you haven’t already.
To check if OIDC is enabl
aws eks describe-cluster --name <cluster_name> --query "cluster.identity.oidc.issuer" --output text
If it returns a URL, you’re set. Otherwise, use the following to enable it (or check EKS Console for options):
eksctl utils associate-iam-oidc-provider --region <region> --cluster <cluster_name> --approve
2. Create an IAM Role with a Trust Policy
The next step is to create an IAM role that allows specific pods to assume the role based on their service account.
Define your trust policy JSON (trust-policy.json
):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account_id>:oidc-provider/<oidc_provider_url>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"<oidc_provider_url>:sub": "system:serviceaccount:<namespace>:<service_account_name>"
}
}
}
]
}
Replace <account_id>
, <oidc_provider_url>
, <namespace>
, and <service_account_name>
with the relevant values.
Create the role with:
aws iam create-role --role-name <role_name> --assume-role-policy-document file://trust-policy.json
3. Attach Policies to the IAM Role
Attach an IAM policy granting access to the AWS resources needed by the pod. Here’s an example for S3 access:
aws iam attach-role-policy --role-name <role_name> --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
You can create custom policies if required. Ensure these follow the least privilege principle.
Step 2: Create a Kubernetes Service Account and Link It to IAM
With the IAM role in place, it’s time to create a Kubernetes service account annotated with this IAM role.
1. Create the Service Account
In your EKS cluster, define a service account YAML manifest (service-account.yaml
):
apiVersion: v1
kind: ServiceAccount
metadata:
name: <service_account_name>
namespace: <namespace>
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<account_id>:role/<role_name>
Apply this manifest:
kubectl apply -f service-account.yaml
2. Deploy a Pod Using the Service Account
Deploy a pod to use this service account and confirm it can access the AWS resource (e.g., S3) with a quick test.
Here’s an example deployment YAML (s3-test-pod.yaml
):
apiVersion: v1
kind: Pod
metadata:
name: s3-reader
namespace: <namespace>
spec:
serviceAccountName: <service_account_name>
containers:
- name: aws-cli
image: amazon/aws-cli
command: ["/bin/sh", "-c"]
args:
- "aws s3 ls s3://<bucket_name> --region <region>"
Apply the pod configuration:
kubectl apply -f s3-test-pod.yaml
Check the pod’s logs to confirm access:
kubectl logs s3-reader -n <namespace>
Step 3: Validate and Troubleshoot IRSA
1. Validate the IAM Role Association
Check that the pod is using the correct role by inspecting its service account’s annotation.
kubectl get serviceaccount <service_account_name> -n <namespace> -o yaml
2. Verify Pod Access in CloudTrail
You can also use AWS CloudTrail to validate which roles and permissions the pod is using.
3. Debugging Common Issues
- OIDC Provider Missing: Ensure the OIDC provider is correctly associated with your cluster.
- IAM Role Policy: Double-check the permissions associated with the IAM role.
- Trust Policy Issues: Ensure that the
StringEquals
condition aligns with your service account’s fully qualified name.
Best Practices for Using IRSA
- Use Least Privilege: Only assign the permissions necessary for each pod’s function.
- Automate with Infrastructure as Code: Tools like Terraform or Helm can simplify managing IAM roles and service accounts.
- Enable Monitoring and Logging: Set up logging in CloudTrail to monitor pod access and troubleshoot quickly.
Conclusion
IRSA is a powerful tool for securely managing access in Kubernetes workloads on AWS EKS. By carefully setting up IAM roles, OIDC providers, and Kubernetes service accounts, you can isolate permissions to individual pods, enhancing the security of your EKS clusters. With IRSA, teams can avoid hardcoded credentials while keeping access both secure and auditable, which is essential in today’s cloud-native environments.
With this approach, you’ll find IRSA essential for running production-grade EKS environments. Whether you’re new to IRSA or refining your setup, this article should provide a practical starting point for integrating IAM roles securely with Kubernetes pods.