IAM Roles for Service Accounts IRSA Lab
Provision an OpenID Connect (OIDC) identity provider, map an AWS IAM Role to a Kubernetes Service Account, and verify access using a test Pod.
Prerequisites
-
An active Amazon EKS cluster.
-
kubectl,eksctl, andawsCLI tools configured and authenticated.
Step 1: Associate an OIDC Provider
EKS clusters have an OIDC issuer URL. You must associate an IAM OIDC provider with this cluster so IAM can validate the tokens generated by Kubernetes.
Bash
# Replace and with your cluster details
export CLUSTER_NAME="eks-cluster"
export AWS_REGION="us-east-1"
eksctl utils associate-iam-oidc-provider \
--cluster $CLUSTER_NAME \
--region $AWS_REGION \
--approve
``
# Replace and with your cluster details
export CLUSTER_NAME="eks-cluster"
export AWS_REGION="us-east-1"
eksctl utils associate-iam-oidc-provider \
--cluster $CLUSTER_NAME \
--region $AWS_REGION \
--approve
Step 2: Create an AWS IAM Policy
Create a policy that defines the exact AWS permissions the Pod requires. In this lab, we will grant read-only access to Amazon S3.
Bash
cat < s3-readonly-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
}
]
}
EOF
# Create the policy and capture the ARN
POLICY_ARN=$(aws iam create-policy \
--policy-name EKSS3ReadOnlyPolicy \
--policy-document file://s3-readonly-policy.json \
--query 'Policy.Arn' \
--output text)
echo $POLICY_ARN
``
cat < s3-readonly-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
}
]
}
EOF
# Create the policy and capture the ARN
POLICY_ARN=$(aws iam create-policy \
--policy-name EKSS3ReadOnlyPolicy \
--policy-document file://s3-readonly-policy.json \
--query 'Policy.Arn' \
--output text)
echo $POLICY_ARN
Step 3: Create the IAM Role and Kubernetes Service Account
This step creates an IAM role, attaches the policy from Step 2, and creates a Kubernetes Service Account annotated with the IAM Role ARN. It establishes the trust relationship.
Bash
eksctl create iamserviceaccount \
--name s3-reader-sa \
--namespace default \
--cluster $CLUSTER_NAME \
--region $AWS_REGION \
--attach-policy-arn $POLICY_ARN \
--approve \
--override-existing-serviceaccounts
``
eksctl create iamserviceaccount \
--name s3-reader-sa \
--namespace default \
--cluster $CLUSTER_NAME \
--region $AWS_REGION \
--attach-policy-arn $POLICY_ARN \
--approve \
--override-existing-serviceaccounts
Step 4: Deploy a Test Pod
Deploy an AWS CLI Pod configured to use the newly created Service Account (s3-reader-sa).
Bash
cat < test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: aws-cli-tester
namespace: default
spec:
serviceAccountName: s3-reader-sa
containers:
- name: aws-cli
image: amazon/aws-cli:latest
command: ["sleep", "3600"]
restartPolicy: Never
EOF
kubectl apply -f test-pod.yaml
``
cat < test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: aws-cli-tester
namespace: default
spec:
serviceAccountName: s3-reader-sa
containers:
- name: aws-cli
image: amazon/aws-cli:latest
command: ["sleep", "3600"]
restartPolicy: Never
EOF
kubectl apply -f test-pod.yaml
Wait for the Pod to be in the Running state:
Bash
kubectl get pods aws-cli-tester -w
``
kubectl get pods aws-cli-tester -w
Step 5: Verify IRSA Configuration
Exec into the Pod and verify that the AWS CLI is automatically picking up the injected web identity token.
1: Check the environment variables: Kubernetes automatically injects AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE when the Service Account is annotated.
Bash
kubectl exec -it aws-cli-tester -- env | grep AWS
``
kubectl exec -it aws-cli-tester -- env | grep AWS
2: Verify Identity: Check which IAM role the Pod is assuming.
Bash
kubectl exec -it aws-cli-tester -- aws sts get-caller-identity
``
kubectl exec -it aws-cli-tester -- aws sts get-caller-identity
Expected Output: The Arn should reflect the IAM role created in Step 3, not the worker node's IAM role.
3: Test S3 Access:
Bash
kubectl exec -it aws-cli-tester -- aws s3 ls
``
kubectl exec -it aws-cli-tester -- aws s3 ls
Expected Output: A list of S3 buckets in your account.
4: Test Unauthorized Access (Validation): Attempt to create an S3 bucket to ensure the least privilege policy is enforced.
Bash
kubectl exec -it aws-cli-tester -- aws s3 mb s3://my-irsa-test-bucket-12345
``
kubectl exec -it aws-cli-tester -- aws s3 mb s3://my-irsa-test-bucket-12345
Expected Output: AccessDenied error.
Step 6: Teardown
Remove the resources to avoid any ongoing configuration drift or clutter.
Bash
kubectl delete -f test-pod.yaml
eksctl delete iamserviceaccount \
--name s3-reader-sa \
--namespace default \
--cluster $CLUSTER_NAME \
--region $AWS_REGION
aws iam delete-policy --policy-arn $POLICY_ARN
rm s3-readonly-policy.json test-pod.yaml
``
kubectl delete -f test-pod.yaml
eksctl delete iamserviceaccount \
--name s3-reader-sa \
--namespace default \
--cluster $CLUSTER_NAME \
--region $AWS_REGION
aws iam delete-policy --policy-arn $POLICY_ARN
rm s3-readonly-policy.json test-pod.yaml