TT Lab
Get started
Learn Learning paths Courses

CKA — Kubernetes Administrator

Cutting Permissions With RBAC

Continue in TT Lab

Goal

You give a ServiceAccount least privilege, confirm that the permission does not cross the namespace boundary, and go on to configure cluster-scoped permissions and an Aggregated ClusterRole.

Why it matters

RBAC problems are a sure source of points on the exam. But checking that the answer is right matters more than producing the answer. kubectl auth can-i --as= only creates a SubjectAccessReview and asks the apiserver, and does not send the actual request, so you can check any number of times with no side effects.

This lab deliberately includes a step that confirms a no. RBAC only accumulates and has no deny rules, so if you use a ClusterRoleBinding by mistake, access opens far wider than intended. People easily check that something opened, but rarely check that it did not open. The principle of least privilege cannot be kept without the habit of "confirming what should not work."

Steps

  1. Create the namespaces cka-rbac and cka-rbac-other. In cka-rbac, create the ServiceAccount deploy-bot, and in cka-rbac-other, create one ConfigMap boundary-probe for checking the boundary.
  2. In cka-rbac, create the Role pod-reader. apiGroups is core (empty string), resources are pods and pods/log, and verbs are only get, list, watch.
  3. In cka-rbac, create the RoleBinding pod-reader-bind that binds the Role pod-reader to the ServiceAccount cka-rbac/deploy-bot.
  4. Save the result of the permission check impersonating deploy-bot to /root/cka-rbac/can-i.txt. In cka-rbac, get on Pods must be yes and delete must be no.
  5. Check whether the same account can read Pods in cka-rbac-other and save the result to /root/cka-rbac/boundary.txt. The result must be no.
  6. Create the ClusterRole node-viewer (apiGroups core, resources nodes, verbs get/list/watch) and the ClusterRoleBinding node-viewer-bind and bind them to cka-rbac/deploy-bot. Listing nodes must become yes.
  7. Create the ClusterRole cka-monitoring-endpoints. Label rbac.labhub.io/aggregate-to-monitoring=true, with a rule for services and endpoints in the core group, allowing get and list. Then create the ClusterRole cka-monitoring so that its aggregationRule selects that label.
  8. In cka-rbac, create the ServiceAccount no-token with automountServiceAccountToken: false. Create the Pod locked-down (image nginx:1.27), set serviceAccountName to no-token, and also set automountServiceAccountToken: false explicitly in the Pod spec. Do not bind any permissions to this account.

Reference

A service account and namespaces for the experiment

Create the namespaces cka-rbac and cka-rbac-other. In cka-rbac, create the ServiceAccount deploy-bot, and in cka-rbac-other, create one ConfigMap boundary-probe for checking the boundary.

A service account is namespace-scoped. To check the boundary, there has to be one resource on the side that must not be accessed.

Create a read-only Role

In cka-rbac, create the Role pod-reader. apiGroups is core (empty string), resources are pods and pods/log, and verbs are only get, list, watch.

The core group is an empty string. Logs are treated as a subresource separate from Pods, so you have to list them separately. You must not include write verbs.

Connect it with a RoleBinding

In cka-rbac, create the RoleBinding pod-reader-bind that binds the Role pod-reader to the ServiceAccount cka-rbac/deploy-bot.

The kind in subjects is ServiceAccount, and along with the name you must also state the namespace where that account lives.

Check that the permission is attached

Save the result of the permission check impersonating deploy-bot to /root/cka-rbac/can-i.txt. In cka-rbac, get on Pods must be yes and delete must be no.

auth can-i only asks, without sending the actual request. The format of the service account name you put in --as is fixed.

Confirm that crossing the namespace boundary fails

Check whether the same account can read Pods in cka-rbac-other and save the result to /root/cka-rbac/boundary.txt. The result must be no.

If you get a yes here, you chose the wrong kind of binding. Look again at the difference between a RoleBinding and a ClusterRoleBinding.

Open a cluster-scoped resource

Create the ClusterRole node-viewer (apiGroups core, resources nodes, verbs get/list/watch) and the ClusterRoleBinding node-viewer-bind and bind them to cka-rbac/deploy-bot. Listing nodes must become yes.

A node does not belong to any namespace. You cannot grant access with a namespace-scoped binding.

Build an Aggregated ClusterRole

Create the ClusterRole cka-monitoring-endpoints. Label rbac.labhub.io/aggregate-to-monitoring=true, with a rule for services and endpoints in the core group, allowing get and list. Then create the ClusterRole cka-monitoring so that its aggregationRule selects that label.

You do not write rules directly in a role that uses an aggregationRule. You write the rules in the other role that carries the label.

Putting it together: create a Pod without a token

In cka-rbac, create the ServiceAccount no-token with automountServiceAccountToken: false. Create the Pod locked-down (image nginx:1.27), set serviceAccountName to no-token, and also set automountServiceAccountToken: false explicitly in the Pod spec. Do not bind any permissions to this account.

You can turn it off on both the service account and the Pod, and the Pod-side setting takes precedence. Stating both makes the intent clear.