The next task is to add a new user who will have access to check pods state and watch logs – any other operations must be prohibited.
AWS EKS uses AWS IAM for authentification in a Kubernetes cluster (check the Kubernetes: part 4 – AWS EKS authentification, aws-iam-authenticator and AWS IAM post for details), bot the authorization, e.g. to determine if a user has permissions for specific operations – Kubernetes uses its own Role-Based Authorization Control mechanism.
Previous parts of this series:
- Kubernetes: part 1 – architecture and main components overview
- Kubernetes: part 2 – a cluster set up on AWS with AWS cloud-provider and AWS LoadBalancer
- Kubernetes: part 3 – AWS EKS overview and manual EKS cluster set up
- Kubernetes: part 4 – AWS EKS authentification, aws-iam-authenticator and AWS IAM post for details
Let’s first take a quick overview of RBAC in general, and then create a new user with necessary permissions.
Contents
Kubernetes RBAC overview
Documentation – Authorization Overview and Using RBAC Authorization.
RBAC model in Kubernetes consists of the three main components:
- Roles: defines permissions boundaries
- Subjects: Users (human or an application), or user groups
- RoleBingdings: specifies which Subjects have which Roles
RBAC Role
A Role example named example-role which allows access to the mynamespace with get
, watch
, and list
operations:
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: mynamespace name: example-role rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
To obtain Kubernetes apiGroups
one can use kubectl api-resources
:
[simterm]
$ kubectl api-resources -o wide NAME SHORTNAMES APIGROUP NAMESPACED KIND VERBS ... pods po true Pod [create delete deletecollection get list patch update watch] ...
[/simterm]
In the rules
above we:
apiGroups: [""]
– set core API groupresources: ["pods"]
– which resources are allowed for access["get", "watch", "list"]
– which actions are allowed over the resources above
RBAC RoleBingding
To “map” those permissions to users we are using Kubernetes RoleBingding
, which sets example-role in the mynamespace for the example-user user:
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: example-rolebinding namespace: mynamespace subjects: - kind: User name: example-user apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: example-role apiGroup: rbac.authorization.k8s.io
Here we set:
subjects
:kind: User
– an object type which will have access, in our case this is a regular username: example-user
– a user’s name to set the permissions
roleRef
:kind: Role
– what exactly will be attached to the user, in this case, it is theRole
object typename: example-role
– and the role name as it was set in thename: example-role
in the example above
Role
vs ClusterRole
Alongside with the Role
and ClusterRole
which are set of rules to describe permissions – Kubernetes also has RoleBinding
and ClusterRoleBinding
objects.
The difference is that Role
is used inside of a namespace, while ClusterRole
is cluster-wide permission without a namespace boundaries, for example:
- allow access to a cluster nodes
- resources in all namespaces
- allow access to endpoints like
/healthz
A ClusterRole
looks similar to a Role with the only difference that we have to set its kind
as ClusterRole
:
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: example-clusterrole rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
And a ClusterRoleBinding
example:
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: example-clusterrolebinding subjects: - kind: User name: example-user apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: example-clusterrole apiGroup: rbac.authorization.k8s.io
Keep in mind that once you’ll create a Binding you’ll not be able to edit its roleRef
value – instead, you’ll have to delete a Binding and recreate and again
EKS Authentification and Authorization
In a short, the Authentification and Authorization process flow is the next:
- Authentification
- a client makes a request to a Kubernetes cluster passing the client’s token with a user’s ID
- Kubernetes using
aws-iam-authenticator
asks AWS IAM to check if such a user really exist and is he is really who he claims to be
- Authorization
- if the user passed the Authentification step – Kubernetes sens him over the RBAC mechanism with all user’s data and action requests
- Kubernetes looks for a
RoleBinding
which maps a user with a Role - by a Rolу name, Kubernetes will check the user’s permissions
- and finally, Kubernreteds will allow or decline the user’s request
Next, we will:
- create an IAM user
- configure AWS CLI
- add an RBAC Role with the read-only permissions to pods
- add an RBAC RoleBinding to connect our user and the Role
IAM user
Let’s begin by creating an IAM user.
Add a new one with the only Programmatic Access:
Save its keys:
IAM policy
If a user will need to have access to the AWS API, for example, to get a list of clusters – need to add an IAM policy for him.
Go to the Policies – Add Policy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "eks:DescribeCluster", "eks:ListClusters" ], "Resource": "*" } ] }
Here we are allowing only two API calls – eks:DescribeCluster
and eks:ListClusters
, in all regions for all EKS clusters.
Save it and attach to the user:
AWS CLI config
To configure kubectl
, first we need to configure our AWS CLI, we can do it in a dedicated CLI profile, check the AWS: CLI named profiles post:
[simterm]
$ aws configure --profile eks-ro-user AWS Access Key ID [None]: AKI***FYC AWS Secret Access Key [None]: SzH***VGi Default region name [None]: eu-north-1 Default output format [None]: json
[/simterm]
Check the user ID you are using now:
[simterm]
$ aws --profile eks-ro-user sts get-caller-identity { "UserId": "AID***XGK", "Account": "534***385", "Arn": "arn:aws:iam::534***385:user/eks-ro-user" }
[/simterm]
And check access to the EKS clusters (better to say access to the AWS API):
[simterm]
$ aws --profile eks-ro-user eks list-clusters --output text CLUSTERS eks-alb-testing-3 CLUSTERS eks-alb-testing-2
[/simterm]
Kubernetes RBAC – an example
Role
Now, let’s create a real user and a Role.
We’ll begin from creating a Role to allow access to pods, their logs and to create a port-forwarding, and only for the get
, list
, create
operations:
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: eks-ro-role rules: - apiGroups: [""] resources: ["pods", "pods/log", "pods/portforward"] verbs: ["get", "list", "create"]
Apply it:
[simterm]
$ kubectl apply -f rbac-role.yml role.rbac.authorization.k8s.io/eks-ro-role created
[/simterm]
And check:
[simterm]
$ kubectl get roles -o yaml apiVersion: v1 items: - apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","metadata":{"annotations":{},"name":"eks-ro-role","namespace":"default"},"rules":[{"apiGroups":[""],"resources":["pods","pods/log"],"verbs":["get","list"]}]} creationTimestamp: "2020-03-24T10:34:27Z" name: eks-ro-role namespace: default resourceVersion: "681997" selfLink: /apis/rbac.authorization.k8s.io/v1/namespaces/default/roles/eks-ro-role uid: 09a78b6f-6dbb-11ea-827f-0a9eb3e1782e rules: - apiGroups: - "" resources: - pods - pods/log verbs: - get - list kind: List metadata: resourceVersion: "" selfLink: ""
[/simterm]
RoleBinding
The next thing is to add a RoleBinding to map our username and the Role created above:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: eks-ro-role-binding subjects: - kind: User name: eks-ro-user apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: eks-ro-role apiGroup: rbac.authorization.k8s.io
Apply:
[simterm]
$ kubectl apply -f rbac-rolebinding.yml rolebinding.rbac.authorization.k8s.io/eks-ro-role-binding created
[/simterm]
aws-auth ConfigMap
As we are using AWS – need to update the aws-auth ConfigMap
(see the AWS EKS aws-auth ConfigMap):
[simterm]
$ kubectl edit configmap aws-auth -n kube-system
[/simterm]
Add the mapUsers
and specify the user’s ARN, name and his group(s):
apiVersion: v1 data: mapRoles: | - groups: - system:bootstrappers - system:nodes rolearn: arn:aws:iam::534***385:role/eksctl-eks-alb-testing-2-nodegrou-NodeInstanceRole-M6BS1WV48RLR username: system:node:{{EC2PrivateDNSName}} mapUsers: | - userarn: arn:aws:iam::534***385:user/eks-ro-user username: eks-ro-user groups: eks-ro-role
Save, and check it:
[simterm]
$ kubectl get pods --as eks-ro-user NAME READY STATUS RESTARTS AGE nginx-7db9fccd9b-7d4rq 1/1 Running 0 58m
[/simterm]
Try to get Worker Nodes – we did not allowed access to this resource:
[simterm]
$ kubectl get nodes --as eks-ro-user Error from server (Forbidden): nodes is forbidden: User "eks-ro-user" cannot list resource "nodes" in API group "" at the cluster scope
[/simterm]
Great!
Now, let’s see a pod’s logs – run a port-forwarding to a testing pod with NGINX:
[simterm]
$ kubectl --as eks-ro-user port-forward nginx-7db9fccd9b-7d4rq 8000:80 Forwarding from 127.0.0.1:8000 -> 80 Forwarding from [::1]:8000 -> 80
[/simterm]
Make a request to the pod:
[simterm]
$ curl -I localhost:8000 HTTP/1.1 200 OK
[/simterm]
And check its logs:
[simterm]
$ kubectl --as eks-ro-user logs -f nginx-7db9fccd9b-7d4rq 127.0.0.1 - - [25/Mar/2020:07:29:06 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.69.1" "-"
[/simterm]
Done.
Useful links
- Authentication and Authorization in Kubernetes
- Privilege escalation via pod creation
- Authenticating Across Clusters with kubeconfig
- Granting User Access to Your Kubernetes Cluster
- How to Add Limited Access IAM Users to an EKS Cluster
- Managing Users or IAM Roles for your Cluster
- Kubernetes Authorization
- How do I provide access to other users and roles after cluster creation in Amazon EKS?
- How do I manage permissions across namespaces for my IAM users in an Amazon EKS cluster?
- Amazon EKS Identity-Based Policy Examples
- Kubernetes RBAC — giving permissions for logging and port-forwarding
- Add new user to manage AWS EKS
- Configuring permissions in Kubernetes with RBAC