CKA — Kubernetes Administrator
Cutting Permissions With RBAC
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
- Create the namespaces
cka-rbacandcka-rbac-other. Incka-rbac, create the ServiceAccountdeploy-bot, and incka-rbac-other, create one ConfigMapboundary-probefor checking the boundary. - In
cka-rbac, create the Rolepod-reader. apiGroups is core (empty string), resources arepodsandpods/log, and verbs are onlyget,list,watch. - In
cka-rbac, create the RoleBindingpod-reader-bindthat binds the Rolepod-readerto the ServiceAccountcka-rbac/deploy-bot. - Save the result of the permission check impersonating
deploy-botto/root/cka-rbac/can-i.txt. Incka-rbac, get on Pods must be yes and delete must be no. - Check whether the same account can read Pods in
cka-rbac-otherand save the result to/root/cka-rbac/boundary.txt. The result must be no. - Create the ClusterRole
node-viewer(apiGroups core, resourcesnodes, verbsget/list/watch) and the ClusterRoleBindingnode-viewer-bindand bind them tocka-rbac/deploy-bot. Listing nodes must become yes. - Create the ClusterRole
cka-monitoring-endpoints. Labelrbac.labhub.io/aggregate-to-monitoring=true, with a rule forservicesandendpointsin the core group, allowinggetandlist. Then create the ClusterRolecka-monitoringso that its aggregationRule selects that label. - In
cka-rbac, create the ServiceAccountno-tokenwithautomountServiceAccountToken: false. Create the Podlocked-down(imagenginx:1.27), set serviceAccountName tono-token, and also setautomountServiceAccountToken: falseexplicitly in the Pod spec. Do not bind any permissions to this account.
Reference
- When impersonating a service account, the name has the form
system:serviceaccount:<네임스페이스>:<이름>(namespace and name). - The files in steps 4 and 5 only need to contain the command output (yes or no) as it is.
- Common mistake 1: leaving out the namespace in subjects in step 3. You must state it explicitly even for the same namespace.
- Common mistake 2: doing step 6 with a RoleBinding. Nodes are cluster-scoped, so you cannot open them with a namespace binding.
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.