Amazon EKS — IAM and RBAC

2 minute read

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

  1. User runs kubectl get pods
  2. kubectl calls aws eks get-token to get a pre-signed STS URL
  3. This token is sent to the EKS API server
  4. API server sends the token to the AWS IAM Authenticator webhook
  5. IAM Authenticator calls STS to validate the identity
  6. Identity is mapped to a Kubernetes user/group
  7. 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

  1. Use groups, not individual users — map IAM roles to K8s groups, then bind roles to groups
  2. Principle of least privilege — start with read-only, add permissions as needed
  3. Never use system:masters for day-to-day operations — create specific ClusterRoles
  4. Use namespaces for isolation — namespace-scoped Roles limit blast radius
  5. Audit RBAC regularly — kubectl auth can-i --list helps review permissions
  6. Migrate to EKS Access Entries — more manageable than aws-auth ConfigMap

Updated: