KCNA — Kubernetes and Cloud Native Associate
Same Name, Different Permissions
Goal
You attach a Role, RoleBinding, ClusterRole, and ClusterRoleBinding in turn to a single service account reader, and check with kubectl auth can-i --as how far (namespace/cluster) and how much (verbs and resources) the permissions reach. You also see how to turn off automatic token mounting.
Why it matters
Every request that arrives at the Kubernetes API server is judged as "who (subject) does what (verb) to where (resource and namespace)." RBAC has only allow rules and no deny rules, so permissions only ever grow as a union as bindings increase. Even for the same name reader, what it can do differs completely depending on which binding is attached at which scope.
A Role is valid only within one namespace, and a resource that has no namespace, like a node, can be given permission only through a ClusterRole and ClusterRoleBinding. Also, a Pod receives a service account token by default, so turning that off in Pods that do not use the API is the first step toward least privilege.
Steps
- Create the namespace
kcna-rbacand the service accountreader. - Create the Role
pod-viewer(pods get/list/watch) and the RoleBindingreader-pods. - Confirm that the same permission does not work in the
defaultnamespace and write it inscope.txt. - Create a separate Role
cm-viewer(configmaps get/list) and the RoleBindingreader-cms. - Allow reading nodes with the ClusterRole
node-viewerand the ClusterRoleBindingreader-nodes. - Run the Pod
appas reader but turn off automatic token mounting. - Confirm that reader cannot create Pods or use wildcard permissions and write it in
write-check.txt. - Record the four can-i results in
/root/kcna-rbac/report.txtas a ledger.
Notes
- When impersonating a service account, the subject name has the form
system:serviceaccount:<네임스페이스>:<이름>(namespace, name). - With
kubectl auth can-i --list -n kcna-rbac --as=...you can see all the permissions that subject has. - Official docs: Using RBAC authorization · RBAC good practices.
A newcomer account with no permissions arrives
Create the namespace kcna-rbac, and in it create the service account reader.
A service account is the identity by which a non-human workload identifies itself to the API server. It is an object that belongs to a namespace, so you have to create the namespace first. If you generate create with --dry-run=client -o yaml and apply it, it is safe to run several times. Right after it is created, reader has no permissions at all.
Let it view Pods but not delete them
In the namespace kcna-rbac, create a Role pod-viewer. Its rule must be nothing more than this: for the core group (""), on pods, the verbs get, list, and watch. Then, with a RoleBinding reader-pods, bind this Role to the service account kcna-rbac:reader.
RBAC has only allow and no deny. A Role is a list of "what can be done," and a RoleBinding decides "to whom" that list is given. Pods are in the core API group, so apiGroups is an empty string. Look at the --verb/--resource options of kubectl create role and the --role/--serviceaccount options of kubectl create rolebinding (the format is namespace:name). Check with kubectl auth can-i <동사> pods --as=system:serviceaccount:<ns>:<이름>, filling in the verb and the service account name.
Nothing is visible in the neighboring namespace
You create no new objects. Check whether reader can list Pods in the default namespace, using kubectl auth can-i, and write the result to /root/kcna-rbac/scope.txt on one line as list-pods-default=<yes|no>.
A Role and a RoleBinding belong to a namespace. So that permission is valid only inside the namespace where the binding exists. Ask the same question twice, changing only the -n value. Do not write by guessing; copy the value can-i returned as it is.
Permissions are not added on; they are bound separately
Without touching the existing pod-viewer, in the namespace kcna-rbac create a separate Role cm-viewer. The rule is: for configmaps in the core group, get and list. Bind it to reader with the RoleBinding reader-cms. reader must be able to list ConfigMaps but not delete them.
When several bindings are attached to one subject, the permissions become a union. So if you split roles finely by purpose, it is easy to peel off just one later. If you wedge configmaps into pod-viewer, the grader catches it. You can create the role and binding one at a time in the same way as step 02.
Nodes live outside namespaces
Create the ClusterRole node-viewer (on nodes in the core group, get and list) and, with the ClusterRoleBinding reader-nodes, bind it to the service account kcna-rbac:reader. reader must be able to list nodes.
Cluster-scoped resources such as nodes, PVs, and StorageClasses have no namespace, so you cannot give permission to them with a Role. If you bind a ClusterRole with a RoleBinding, the scope is still narrowed to a single namespace, so you need a ClusterRoleBinding to see nodes. Look at the --clusterrole option of kubectl create clusterrolebinding. Do not attach -n to can-i for nodes.
Do not hand a key to a Pod that never uses the API
In the namespace kcna-rbac, create a Pod app (image nginx:1.27-alpine). This Pod runs as the service account reader, but set automountServiceAccountToken to false so that the service account token is not automatically mounted.
By default a Pod receives its service account's token as a kube-api-access-* volume. If the container is compromised, that token can be used to call the API, so a Pod that does not use the API is better off not receiving a token. In the Pod spec, write both fields serviceAccountName and automountServiceAccountToken. Also check in kubectl get pod app -o yaml that there is no kube-api-access among the volumes.
If a read-only account tries to create a Pod
Check whether reader can create Pods in the namespace kcna-rbac and whether it can use every verb (a wildcard) on every resource, using kubectl auth can-i. Both must be no. Write the result for creating Pods to /root/kcna-rbac/write-check.txt on one line as create-pods=<yes|no>.
The only verbs given so far are get, list, and watch. create is denied unless you allow it separately. You can ask the wildcard question by putting an asterisk wrapped in quotes in the resource and verb positions. If you get yes here, permissions were given too broadly in an earlier step, so look at the Role rules again.
Record reader's permission map as a ledger
Write reader's permissions to /root/kcna-rbac/report.txt in exactly four lines: list-pods-in-ns=yes, list-pods-in-default=no, list-nodes=yes, and create-pods=no. The values must match the actual kubectl auth can-i results.
The grader checks each line against the actual can-i result impersonating the service account reader. The four questions are, in order: pods list in kcna-rbac, pods list in default, nodes list at cluster scope, and pods create in kcna-rbac. Copy the answers you asked for yourself.