DEV Community 👩‍💻👨‍💻

Arseny Zinchenko
Arseny Zinchenko

Posted on • Originally published at rtfm.co.ua on

Kubernetes: part 5 — RBAC authorization with a Role and RoleBinding example

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:

Let’s first take a quick overview of RBAC in general, and then create a new user with necessary permissions.

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:

kubectl api-resources -o wide

NAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KIND                             VERBS
...
pods                              po                                          true         Pod                              [create delete deletecollection get list patch update watch]
...

In the rules above we:

  1. apiGroups: [""] – set core API group
  2. resources: ["pods"] – which resources are allowed for access
  3. ["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 user
    • name: 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 the Role object type
    • name: example-role – and the role name as it was set in the name: 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:

  1. Authentification
    1. a client makes a request to a Kubernetes cluster passing the client’s token with a user’s ID
    2. 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
  2. Authorization
    1. if the user passed the Authentification step – Kubernetes sens him over the RBAC mechanism with all user’s data and action requests
    2. Kubernetes looks for a RoleBinding which maps a user with a Role
    3. by a Rolу name, Kubernetes will check the user’s permissions
    4. and finally, Kubernreteds will allow or decline the user’s request

Next, we will:

  1. create an IAM user
  2. configure AWS CLI
  3. add an RBAC Role with the read-only permissions to pods
  4. 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:

$ 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

Check the user ID you are using now:

$ 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"
}

And check access to the EKS clusters (better to say access to the AWS API):

$ aws --profile eks-ro-user eks list-clusters --output text
CLUSTERS        eks-alb-testing-3
CLUSTERS        eks-alb-testing-2

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:

$ kubectl apply -f rbac-role.yml
role.rbac.authorization.k8s.io/eks-ro-role created

And check:

$ 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: ""

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:

$ kubectl apply -f rbac-rolebinding.yml
rolebinding.rbac.authorization.k8s.io/eks-ro-role-binding created

aws-auth ConfigMap

As we are using AWS – need to update the aws-auth ConfigMap (see the AWS EKS aws-auth ConfigMap):

$ kubectl edit configmap aws-auth -n kube-system

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:

$ kubectl get pods --as eks-ro-user
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7db9fccd9b-7d4rq   1/1     Running   0          58m

Try to get Worker Nodes – we did not gave access to this resource:

$ 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

Great!

Now, let’s see a pod’s logs – run a port-forwarding to a testing pod with NGINX:

$ 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

Make a request to the pod:

$ curl -I localhost:8000
HTTP/1.1 200 OK

And check its logs:

$ 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" "-"

Done.

Useful links

Similar posts

Top comments (1)

Collapse
 
gadinaor profile image
Gadi Naor

Excellent post series on complex aspect of kubernetes. Check this RBAC tool
github.com/alcideio/rbac-tool

DEV

Thank you.

 
Thanks for visiting DEV, we’ve worked really hard to cultivate this great community and would love to have you join us. If you’d like to create an account, you can sign up here.