AWS IAM Roles for Kubernetes Pods in EKS
Amazon Elastic Kubernetes Service (EKS) simplifies the deployment and management of Kubernetes clusters on AWS. As organizations transition to containerized workloads, it becomes crucial to implement robust security measures. One powerful tool at your disposal is AWS Identity and Access Management (IAM), which allows you to control access to AWS services and resources securely. In this article, we’ll explore the usage of IAM Roles for pods in AWS EKS and discuss the option of using IAM Roles for Service Accounts.
Why IAM Roles for Pods?
When running applications on Kubernetes, pods often need to interact with AWS services such as S3, DynamoDB, or other AWS resources. Instead of embedding AWS credentials directly within the pod or managing them manually, IAM Roles for pods provide a more secure and scalable solution.
Key Advantages of Using IAM Roles for Pods:
1. Improved Security:
IAM Roles allow you to follow the principle of least privilege, granting pods only the permissions they need to perform specific actions. This minimizes the risk associated with exposed or leaked credentials.
2. Automated Credential Rotation:
IAM Roles come with automatic credential rotation, enhancing the security of your applications by regularly rotating access keys. This eliminates the need for manual intervention and ensures that your credentials remain up-to-date.
3. Simplified Access Management:
IAM Roles facilitate centralized access management, enabling you to define and enforce access policies consistently across your Kubernetes cluster. This simplifies auditing and compliance efforts.
Implementing IAM Roles for Pods in EKS
AWS provides two methods of implementing IAM Roles for Pods in EKS: IAM Roles for ServiceAccounts (IRSA), and EKS Pod Identity (released in November 2023).
Using IAM Roles for Service Accounts (IRSA):
Let’s walk through the steps of setting up IAM Roles for pods in AWS EKS:
1. Create an IAM OIDC Identity Provider
Before associating IAM roles with Kubernetes service accounts, you need to create an OIDC identity provider. Follow the detailed instructions in the AWS documentation.
2. Create an IAM Role
Create an IAM role that defines the permissions your pods require. Ensure that you trust the OIDC identity provider you created in the previous step.
# Example IAM Role JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/<eks-cluster-id>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.<region>.amazonaws.com/id/<eks-cluster-id>:sub": "system:serviceaccount:<namespace>:<service-account-name>"
}
}
}
]
}
3. Associate the IAM Role with the Kubernetes Service Account:
Update your Kubernetes service account to use the IAM role created above.
# Example Kubernetes Service Account YAML
apiVersion: v1
kind: ServiceAccount
metadata:
name: <service-account-name>
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/<iam-role-name>
4. Test that the role can be properly assumed by the pod
In order to test that the IAM Role can be used by the pod, it is easiest to launch a debug pod in the respective namespace. For this example, we use our public kotaicode/ubuntu-devops docker image. This docker image contains a lot of useful tools for debugging in different cloud providers, database systems, and the code for the docker image is public in github.
# assuming that the serviceaccount is "replace-me"
SA_NAME=replace-me kubectl run tmp-shell-0 --rm -i --tty --image kotaicode/ubuntu-devops:24 --overrides '{"spec":{"serviceAccountName":"'$SA_NAME'"}}' -- /bin/bash
# this will launch a pod in the current namespace, and gives you a shell
# now, from inside the pod we check our AWS role
aws sts get-caller-identity --no-cli-pager
{
"UserId": "AXXXXXXXXX:botocore-session-12343214",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/xxxxxxxxxxxx"
}
EKS Pod Identity:
In November 2023, AWS launched the feature of EKS Pod Identity, which further simplifies the usage of IAM roles for pods.
EKS Pod Identity allows for more granular control over pod-level permissions. With this feature, you can assign IAM roles directly to individual pods, tailoring permissions to the specific needs of each workload. One significant improvement is the simplified configuration of pod identities. EKS Pod Identity automates the setup of IAM roles and OIDC identity providers, reducing the manual steps required to establish secure pod-to-AWS communication.
On top, auditability is increased, since access and event logging is available through AWS CloudTrail to help facilitate retrospective auditing.
Amazon EKS Pod Identity provides credentials to pods with an additional EKS Auth API and an agent pod that runs on each node. From the code itself, AWS SDKs are used to access AWS services. Note that you need to use an updated AWS SDK in your client code, which already supports the EKS Pod Identity feature.
The details of how EKS Pod Identities work can be found in the AWS documentation.
The next steps are a summary of the required steps, please follow the official documentation.
The steps boil down to:
- Install the EKS Pod Identity Agent in your cluster
- Once the agent is up and running, you can use the AWS console or AWS CLI to map pod ServiceAccounts to IAM roles:
2.1. create a serviceaccount in your cluster
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
2.2. Create a role, which allows the AssumeRole for the pods.eks.amazonaws.com principal using such an assumeRolepolicyDocument
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowEksAuthToAssumeRoleForPodIdentity",
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
}
2.3. Attach the IAM policies to the role to grant the desired permissions
2.4. create the association between the serviceAccount and the IAM Role
aws eks create-pod-identity-association --cluster-name my-cluster --role-arn arn:aws:iam::111122223333:role/my-role --namespace default --service-account my-service-account
To debug the functionality, you can use the same steps as with IRSAs, by launching a pod, and checking the assume-role functionality
# assuming that the serviceaccount is "replace-me"
SA_NAME=replace-me kubectl run tmp-shell-0 --rm -i --tty --image kotaicode/ubuntu-devops:24 --overrides '{"spec":{"serviceAccountName":"'$SA_NAME'"}}' -- /bin/bash
# this will launch a pod in the current namespace, and gives you a shell
# now, from inside the pod we check our AWS role
aws sts get-caller-identity --no-cli-pager
{
"UserId": "AXXXXXXXXX:botocore-session-12343214",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/xxxxxxxxxxxx"
}
Summary
Whether you use the IRSA concept or the newer EKS Pod Identity feature, it is highly recommended to be as specific and restrictive as possible and hence assign permissions on a per Pod level and leverage the existing AWS IAM security architecture.
It is a bad practice to assign policies directly to the nodes of the EKS cluster and thus giving all pods permissions. Ideally you should consider the security best practices for AWS EKS, and disable the instance metadata service, as per the AWS documentation.