CKA — Kubernetes Administrator
Authentication and Authorization Are Different Layers
Summary
A request that reaches the apiserver passes in this order: authentication (who are you) → authorization (may that person do this) → admission (does the content fit the rules). RBAC is just the second layer, and the first layer is the world of certificates and tokens. If you mix the two, your diagnosis gets tangled.
Why this matters
Kubernetes has no user object. There is no kubectl get users. That is because the apiserver is a verifier, not an issuer of identity. The source of identity lies outside.
- Client certificates — the CN becomes the user name and the O becomes the group. The admin.conf that
kubeadmcreates for you works this way. - ServiceAccount tokens — the identity of a workload inside a Pod. It has a name of the form
system:serviceaccount:<네임스페이스>:<이름>(namespace and name) and the groupsystem:serviceaccounts. - OIDC, webhooks, bootstrap tokens, and so on
So a request like "please delete that user" does not make sense. All you can do is revoke the certificate or delete the binding.
The authorization side has only four kinds of objects.
| Namespace scope | Cluster scope | |
|---|---|---|
| Defining permissions | Role | ClusterRole |
| Granting permissions | RoleBinding | ClusterRoleBinding |
There is exactly one combination here that confuses people. A RoleBinding referencing a ClusterRole is allowed, and in that case the ClusterRole's rules apply only inside the namespace where that RoleBinding lives. It is the standard way to reuse built-in ClusterRoles such as view and edit per namespace. Conversely, using a ClusterRoleBinding spreads across the entire cluster, so people often make a mistake here while trying to keep to the namespace boundary.
RBAC only accumulates. There are no deny rules. Once any binding allows something, it is allowed. So when you trace "why can this account do this," you have to sweep through all the bindings, and kubectl auth can-i --as= is the shortcut. This command only creates a SubjectAccessReview and asks the apiserver, and does not send the actual request. You can check safely with no side effects.
How it works
An Aggregated ClusterRole is a ClusterRole that does not write its rules directly. When you put a label selector in aggregationRule, a controller finds the other ClusterRoles carrying that label and fills in rules. It is an extension point that lets you add a new resource you introduced with a CRD onto the existing view/edit roles with a single label. If you write rules by hand here, the controller overwrites them.
automountServiceAccountToken decides whether to inject an API token into the Pod. By default it does. Then even an nginx Pod that never uses the API gets a token, and if the container is compromised, that token is cluster access. If you set it to false on the ServiceAccount or the Pod spec, the kube-api-access-* projected volume is not injected at all.
What it looks like in the field
Case 1 — Cut the CA private key's exposure window to 2 hours. When I grew a homelab from 3 nodes to 7, the difference between a worker join and a control plane join showed the authentication structure as it is. A worker needs only one token.
kubeadm token create --print-join-command
A control plane is different. A new node must also become an issuer of certificates, so it needs the CA private key. kubeadm does not make you carry this sensitive file around with scp; with kubeadm init phase upload-certs --upload-certs it uploads the CA key bundle encrypted, as a Secret inside the cluster. The 64-character certificate-key you give to the join command is the symmetric key that decrypts that ciphertext.
And this Secret is deleted automatically after 2 hours. Even though it is encrypted, it holds the cluster's root of trust, so the design aims to minimize the exposure window. When it expires, you just run upload-certs again, and it does not affect the existing cluster. This is the core of authentication: "how briefly you expose the root of trust."
Case 2 — The certificate SAN is itself access permission. On the same cluster, even after I grew the control plane nodes to three, nobody could connect when the first node died. That was because the apiserver certificate's SAN lacked the IPs of the other two nodes. No matter how well you design RBAC, if you do not pass TLS verification, you never even reach the authorization layer. Conversely, exploiting this property, if you put the dead node's IP on a live node's interface, every client reconnects as is, with no certificate reissue and no kubeconfig edit. What the client verifies is not the node but whether the address it connected to is in the SAN.
Case 3 — Sometimes the problem is configuration, not permissions. While installing the GPU Operator, all the Pods once got stuck at Init. kubectl get runtimeclass showed nvidia there just fine, but the node's containerd configuration had not a single character of nvidia. The name tag exists as a Kubernetes object and the substance has to be on the node, but the latter was missing. That an object exists and that it actually works are different propositions — you need the same habit when diagnosing an authorization problem. If can-i gave yes, the next step is to go down through certificates, the network, and admission webhooks, in that order.
What to do in the next lab
You create a ServiceAccount, give it only read permission with a Role/RoleBinding, and use kubectl auth can-i --as= to check both that it works and that it does not. Next you open cluster-scoped resources with a ClusterRole/ClusterRoleBinding, build an Aggregated ClusterRole, and finally create a Pod into which no token is injected at all.