Amazon EKS — IAM and RBAC
EKS uses AWS IAM for authentication and Kubernetes RBAC for authorization. Every API call hits IAM first (who are you?) then RBAC (what can you do?).
How Authentication Works
- User runs
kubectl get pods - kubectl calls
aws eks get-tokento get a pre-signed STS URL - This token is sent to the EKS API server
- API server sends the token to the AWS IAM Authenticator webhook
- IAM Authenticator calls STS to validate the identity
- Identity is mapped to a Kubernetes user/group
- RBAC rules determine what that user can do
Cluster Creator Admin
The IAM principal (user or role) that creates the EKS cluster automatically gets system:masters privileges. This identity is hardcoded — it cannot be removed from access.
# Check who you're authenticated as
aws sts get-caller-identity
aws-auth ConfigMap (Legacy)
The aws-auth ConfigMap maps IAM identities to Kubernetes users/groups:
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789:role/EKSNodeRole
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
- rolearn: arn:aws:iam::123456789:role/DevTeamRole
username: dev-user
groups:
- dev-group
mapUsers: |
- userarn: arn:aws:iam::123456789:user/admin
username: admin
groups:
- system:masters
Warning: aws-auth is being replaced by EKS Access Entries. Use access entries for new clusters.
Kubernetes RBAC
Role (Namespace-Scoped)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"]
ClusterRole (Cluster-Scoped)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-admin
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "create", "update", "delete"]
RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-pod-reader
namespace: production
subjects:
- kind: Group
name: dev-group
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: platform-admins
subjects:
- kind: Group
name: platform-admin-group
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
Common RBAC Patterns
| Pattern | Role Type | Verbs | Use Case |
|---|---|---|---|
| Read-only | Role | get, list, watch | Developers viewing production |
| Deployer | Role | get, list, create, update, patch | CI/CD pipeline |
| Namespace admin | ClusterRole + RoleBinding | * on namespace resources | Team lead |
| Cluster admin | ClusterRole + ClusterRoleBinding | * on all resources | Platform team |
Verify Access
# Check your current permissions
kubectl auth can-i create deployments -n production
kubectl auth can-i delete pods -n production
# Check another user's permissions
kubectl auth can-i create deployments -n production --as=dev-user
# List all bindings
kubectl get rolebindings -n production
kubectl get clusterrolebindings
Best Practices
- Use groups, not individual users — map IAM roles to K8s groups, then bind roles to groups
- Principle of least privilege — start with read-only, add permissions as needed
- Never use
system:mastersfor day-to-day operations — create specific ClusterRoles - Use namespaces for isolation — namespace-scoped Roles limit blast radius
- Audit RBAC regularly —
kubectl auth can-i --listhelps review permissions - Migrate to EKS Access Entries — more manageable than aws-auth ConfigMap