RBAC WALKTHROUGH: Using an IAM group to assign permission to the Kubernetes API
Introduction
This walkthrough explains how to create an AWS role that members of an IAM group can assume. The assumed role is then mapped to a Kubernetes RBAC role in the aws-auth ConfigMap which allows the group members to perform a set of actions against the Kubernetes API, e.g. patch, get, create, etc.
As an alternative to assuming an IAM role, you can use the group-operator. The group-operator is a Kubernetes operator that enumerates the members of an IAM group and add/removes them from the aws-auth ConfigMap automatically.
Create a cluster role
A ClusterRole
can be used to grant the same permissions as a Role
, but because they are cluster-scoped, they can also be used to grant access to:
- cluster-scoped resources (like nodes)
- non-resource endpoints (like “/healthz”)
- namespaced resources (like pods) across all namespaces (needed to run
kubectl get pods --all-namespaces
, for example)
This role grants the ability to read pods in all namespaces.
cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader-cr
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
EOF
Create a role binding
A RoleBinding
may also reference a ClusterRole
to grant the permissions to namespaced resources defined in the ClusterRole
within the RoleBinding
's namespace. This allows administrators to define a set of common roles for the entire cluster, then reuse them within multiple namespaces.
cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-rb
namespace: default
subjects:
- kind: Group
name: pod-reader # Name is case sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: pod-reader-cr
apiGroup: rbac.authorization.k8s.io
EOF
Create IAM role
Create trust policy document
Allows all users from an AWS account to assume this role.
cat > [filename] << 'EOF'
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::123456789012:root" },
"Action": "sts:AssumeRole"
}
}
EOF
Create an IAM role
Binds the trust policy to the IAM role.
ROLE_ARN=$(aws iam create-role --role-name pod-reader-role --assume-role-policy-document file://[filename] | jq -r '.Role.Arn')
Create IAM group
aws iam create-group --group-name [group_name]
Create IAM policy document
cat > [filename] << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "123",
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Resource": [
"arn:aws:iam::123456789012:role/pod-reader-role"
]
}
]
}
EOF
Create Assume role POLICY
POLICY_ARN=$(aws iam create-policy --policy-name [policy_name] --policy-document file://[filename] | jq -r '.Policy.Arn')
Attach assume role policy to group
When the policy is attached to the group, it allows members of the group to assume an IAM role. This role is mapped to the pod-reader Kubernetes RBAC group which allows users to get and list pods in the default namespace.
aws iam attach-group-policy --group-name [group_name] --policy-arn $POLICY_ARN
Add IAM users to group
aws iam add-user-to-group --group-name [group_name] --user-name [user_name]
Update aws-auth configmap
Creates a mapping between the IAM role and the Kubernetes RBAC group pod-reader.
ROLE=" - userarn: $ROLE_ARN\n username: pod-reader\n groups:\n - pod-reader"
kubectl get -n kube-system configmap/aws-auth -o yaml | awk "/mapUsers: \|/{print;print \"$ROLE\";next}1" > /tmp/aws-auth-patch.yml
kubectl patch configmap/aws-auth -n kube-system --patch "$(cat /tmp/aws-auth-patch.yml)"
Update kubeconfig
Adding the --role
flag to the arguments passed to the AWS CLI will generate a token for specific IAM role that gets passed to the Kubernetes API when the user issues kubectl
commands.
- name: [context_name]
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
args:
- eks
- get-token
- --cluster-name
- [cluster_name]
- --role
- arn:aws:iam::123456789012:role/pod-reader-role
command: aws
env: null