AWS Ops — EKS & IAM
Use eksctl for cluster and node group management, aws eks update-kubeconfig to connect, and IRSA (IAM Roles for Service Accounts) to grant pods AWS permissions without static credentials. Use aws sts get-caller-identity to confirm which role your CLI is using.
EKS Cluster Basics
These are the daily commands you'll reach for when working with EKS — from connecting to a cluster to checking its version and add-ons.
# Connect to cluster
aws eks update-kubeconfig --region us-east-1 --name my-cluster
aws eks update-kubeconfig --region us-east-1 --name my-cluster --role-arn arn:aws:iam::123:role/eks-admin
# Cluster info
aws eks describe-cluster --name my-cluster --query 'cluster.{version:version,status:status,endpoint:endpoint}'
aws eks list-addons --cluster-name my-cluster
aws eks describe-addon --cluster-name my-cluster --addon-name vpc-cni
# Node groups
aws eks list-nodegroups --cluster-name my-cluster
aws eks describe-nodegroup --cluster-name my-cluster --nodegroup-name my-ng \
--query 'nodegroup.{status:status,instanceType:instanceTypes,desired:scalingConfig.desiredSize,min:scalingConfig.minSize,max:scalingConfig.maxSize}'
# Scale node group
aws eks update-nodegroup-config --cluster-name my-cluster \
--nodegroup-name my-ng \
--scaling-config minSize=2,maxSize=10,desiredSize=5
# Verify caller identity (which IAM role/user is active)
aws sts get-caller-identityIRSA — IAM Roles for Service Accounts
IRSA lets a Kubernetes ServiceAccount assume an IAM role, giving pods fine-grained AWS permissions without mounting static credentials. The pod receives temporary credentials via the projected token volume.
# 1. Ensure OIDC provider is associated with the cluster
eksctl utils associate-iam-oidc-provider \
--region us-east-1 --cluster my-cluster --approve
# 2. Create IAM role + SA with eksctl (simplest)
eksctl create iamserviceaccount \
--cluster my-cluster \
--namespace my-namespace \
--name my-service-account \
--attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
--approve \
--override-existing-serviceaccounts
# 3. Check the SA annotation (role ARN must be present)
kubectl describe sa my-service-account -n my-namespace | grep amazonaws
# 4. Verify pod is receiving credentials
kubectl exec -it <pod> -- aws sts get-caller-identity
# Manual trust policy (for custom IAM roles)
OIDC=$(aws eks describe-cluster --name my-cluster \
--query 'cluster.identity.oidc.issuer' --output text | sed 's|https://||')
ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
# Trust policy JSON: allow K8s SA to assume this role
cat <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Federated": "arn:aws:iam::${ACCOUNT}:oidc-provider/${OIDC}"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {"StringEquals": {
"${OIDC}:sub": "system:serviceaccount:my-namespace:my-sa",
"${OIDC}:aud": "sts.amazonaws.com"
}}
}]
}
EOFECR Operations
Common ECR commands for pushing images, managing lifecycle policies, and listing repositories. Use lifecycle policies to prevent unbounded image accumulation.
REGION=us-east-1
ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
REGISTRY=$ACCOUNT.dkr.ecr.$REGION.amazonaws.com
# Authenticate docker to ECR
aws ecr get-login-password --region $REGION | \
docker login --username AWS --password-stdin $REGISTRY
# Create repository
aws ecr create-repository --repository-name myapp --region $REGION
# Push image
docker build -t myapp:v1.2.3 .
docker tag myapp:v1.2.3 $REGISTRY/myapp:v1.2.3
docker push $REGISTRY/myapp:v1.2.3
# List images in a repo
aws ecr list-images --repository-name myapp --region $REGION
# Get image details (digest, size, tags)
aws ecr describe-images --repository-name myapp \
--query 'sort_by(imageDetails, &imagePushedAt)[-5:]|[].{tag:imageTags[0],pushed:imagePushedAt,size:imageSizeInBytes}'
# Lifecycle policy: keep last 30 tagged images, delete untagged after 1 day
aws ecr put-lifecycle-policy --repository-name myapp --lifecycle-policy-text '{
"rules": [
{"rulePriority":1,"description":"remove untagged","selection":{"tagStatus":"untagged","countType":"sinceImagePushed","countUnit":"days","countNumber":1},"action":{"type":"expire"}},
{"rulePriority":2,"description":"keep 30","selection":{"tagStatus":"tagged","tagPrefixList":["v"],"countType":"imageCountMoreThan","countNumber":30},"action":{"type":"expire"}}
]
}'IAM Debugging
When pods can't access AWS resources, work through the IAM chain: check the pod's assumed role, the attached policies, and whether the resource policy allows access.
# Check what identity the pod has assumed
kubectl exec -it <pod> -- aws sts get-caller-identity
# List policies attached to a role
aws iam list-attached-role-policies --role-name my-role
aws iam list-role-policies --role-name my-role # inline policies
# Simulate a policy (check if action is allowed without actually doing it)
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123:role/my-role \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-bucket/*
# Check aws-auth ConfigMap (maps IAM roles → K8s RBAC)
kubectl describe configmap aws-auth -n kube-system
# Add a role to aws-auth (eksctl method)
eksctl create iamidentitymapping \
--cluster my-cluster \
--arn arn:aws:iam::123456789:role/developer-role \
--group system:masters \
--username admin