3.1. RBAC
Role Based Access Control
Until now we just assumed that we have the necessary right to do our tasks in kubernetes. But how are users Authenticated and Authorized in Kubernetes/the Kubernetes API?
Users in Kubernetes
All Kubernetes clusters have two categories of users: service accounts managed by Kubernetes, and normal users.
It is assumed that a cluster-independent service manages normal users in the following ways:
- an administrator distributing private keys
- a user store like Keystore or Google Accounts
- a file with a list of usernames and passwords
In this regard, Kubernetes does not have objects which represent normal user accounts. Normal users cannot be added to a cluster through an API call.
Even though a normal user cannot be added via an API call, any user that presents a valid certificate signed by the cluster’s certificate authority (CA) is considered authenticated. In this configuration, Kubernetes determines the username from the common name field in the ‘subject’ of the cert (e.g., “/CN=bob”). In contrast, service accounts are users managed by the Kubernetes API. They are bound to specific namespaces, and created automatically by the API server or manually through API calls.
Authentication strategies
Kubernetes uses client certificates, bearer tokens, or an authenticating proxy to authenticate API requests through authentication plugins. As HTTP requests are made to the API server, plugins attempt to associate the following attributes with the request:
- Username: a string which identifies the end user. Common values might be kube-admin or [email protected] .
- UID: a string which identifies the end user and attempts to be more consistent and unique than username.
- Groups: a set of strings, each of which indicates the user’s membership in a named logical collection of users. Common values might be system:masters or devops-team.
- Extra fields: a map of strings to list of strings which holds additional information authorizers may find useful.
The following authentication method are common:
- X509 client certificates
- bearer token
- Service account tokens
- OpenID Connect Tokens (Microsoft Entra ID, Salesforce,Google…)
RBAC Authorisation
The RBAC API declares four kinds of Kubernetes object: Role, ClusterRole, RoleBinding and ClusterRoleBinding. You can describe or amend the RBAC objects using tools such as kubectl, just like any other Kubernetes object.
Role and ClusterRole
An RBAC Role or ClusterRole contains rules that represent a set of permissions. Permissions are purely additive (there are no “deny” rules).
A Role always sets permissions within a particular namespace; when you create a Role, you have to specify the namespace it belongs in.
ClusterRole, by contrast, is a non-namespaced resource. The resources have different names (Role and ClusterRole) because a Kubernetes object always has to be either namespaced or not namespaced; it can’t be both.
RoleBinding and ClusterRoleBinding
A role binding grants the permissions defined in a role to a user or set of users. It holds a list of subjects (users, groups, or service accounts), and a reference to the role being granted. A RoleBinding grants permissions within a specific namespace whereas a ClusterRoleBinding grants that access cluster-wide.
A RoleBinding may reference any Role in the same namespace. Alternatively, a RoleBinding can reference a ClusterRole and bind that ClusterRole to the namespace of the RoleBinding. If you want to bind a ClusterRole to all the namespaces in your cluster, you use a ClusterRoleBinding.
Task 3.1.1: Create a New Service Account
In this lab, we will explore how to test Kubernetes RBAC (Role-Based Access Control) using an explicitly created service account. Unlike the default service account, which is automatically created in each namespace, we will create our own service account and bind it to a Role that grants permissions to list and create pods.
Instead of using the default service account, we will create a new service account named <namespace>-sa
:
kubectl create serviceaccount <namespace>-sa
kubectl get serviceaccount
Next, we will create a pod that uses the newly created
kubectl run kubectl-pod --image=beli/kubectl-shell --restart=Never --overrides='{ "spec": { "serviceAccount": "<namespace>-sa" }}' -- sleep infinity
We are ready to use kubectl from within our pod to list all pods in the namespace using the <namespace>-sa
service account:
kubectl exec -it kubectl-pod -- kubectl get pods
You will likely see a permission denied error because <namespace>-sa
does not have the required permissions to list pods. If you have a timeout error, try to guess what could cause it and find/correct the misconfiguration.
To allow the <namespace>-sa
service account to list and create pods, we need to create a Role that grants these permissions.
Create a file called role.yaml
to define a Role that allows listing and creating pods and logs:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: <namespace>
name: pod-manager
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["list", "get", "create"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["list", "get"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
apply the Role:
kubectl apply -f role.yaml
This Role grants the ability to list and create pods in the <namespace>
namespace. Kubernetes grants you rights to create roles and rolebindings which do not exceed your own rights.
Now that we have a Role, we need to bind the <namespace>-sa
service account to this Role so that it can use the permissions.
Create a file called rolebinding.yaml
to bind the <namespace>-sa
service account to the pod-manager
Role:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-manager-binding
namespace: <namespace>
subjects:
- kind: ServiceAccount
name: <namespace>-sa
namespace: <namespace>
roleRef:
kind: Role
name: pod-manager
apiGroup: rbac.authorization.k8s.io
Apply the RoleBinding:
kubectl apply -f rolebinding.yaml
The <namespace>-sa
service account is now bound to the pod-manager
Role, and can list and create pods in the <namespace>
namespace.
Now use the Service Account to create a new Pod
kubectl exec -it kubectl-pod -- kubectl run new-pod --image=nginx --restart=Never
Check if the new pod was created:
kubectl get pods
You should now see both kubectl-pod
and new-pod
in the output.
Feel free to experiment by modifying the Role’s permissions or testing different service accounts to better understand Kubernetes RBAC!
🤔 Can I list secrets with this service account?
You did not include secrets in your role, so you cannot list secrets directly.
However, you have the right to start a pod in this namespace, if you happen to know the name of the secret (or guess it) you can mount any secret in this namespace to the pod and read it inside the pod!
Task 3.1.2: (Advanced) Mount secrets without direct permissions
Prove the answer to above question. Create secret and then start a pod with the service account mounting the secret.
After you successfully accomplished this. You can create a new role to include secrets read in the namespace for the service account too.
Cleanup
You can delete both pods and the service account after you have finished the lab:
kubectl delete pods kubectl-pod, new-pod
kubectl delete -f role.yaml
kubectl delete -f rolebinding.yaml
kubectl delete sa <namespace>-sa