KCSA — Kubernetes Security Associate
Identity, audience, and permission are different questions
In one line
Who a token represents, who it may be sent to, and what it is allowed to do are different questions. A decoding result or an administrator's proxy request alone cannot answer all three questions.
Why this was needed
Here is an example incident. A token that had been used for a report service was sent to the Kubernetes API and a 401 came back. One team member says permissions are missing from the role and proposes attaching cluster-admin. Another says the token's expiry time is tomorrow, so the server is wrong. Neither has yet confirmed the cause. If it is a token for a different audience, increasing permissions does not fix it, and only unnecessary permissions are left behind.
In the personal VM of this unit, a reader account with the same name exists in two namespaces. Each account reads only a single lesson-policy ConfigMap in its own namespace. The data is a synthetic string, training-only. You can reproduce the difference between authentication and authorization even without sensitive secrets, so there is no reason to bring in a real service token to practice.
How it works
Observe issuance, validation, and use separately
TokenRequest is a request to obtain a service account's credentials. The request includes an audience, the desired lifetime, and, if needed, the name and UID of an object to bind to. You must check the actual expiry time in the response, and do not assume that the number you requested is always applied as is. This time, an administrator issues the token for the training account. This administrator's permission to issue and the issued token subject's permission to read ConfigMaps are separate.
If you base64url-decode the middle part of a JWT, you can read claims such as sub, aud, and exp. But that does not mean the signature was checked. Reading an employee number written on paper is different from confirming the authenticity of an ID with the issuing authority. Do not write that validation is complete just because you read the token contents.
TokenReview is used to ask for the authentication result of a token. This time's helper performs that check on an administrator's request but shows only whether it authenticated, the audience, the username, and the UID instead of the token's original text. Even if this result is true, it does not mean that user was allowed to look up the ConfigMap. Only by sending an actual read request separately can you confirm the result of the role and binding.
Do not mix other identity documents into the request
If you add just one option to kubectl using the administrator kubeconfig and call it the service account's action, the experiment becomes ambiguous. This time's GET client does not use the administrator client certificate and uses only the bearer token in Authorization. It keeps server CA verification and uses no redirects or proxy. Which credentials went to which address is part of the experiment.
The --as proxy request allowed to administrators is useful for checking RBAC. But that request does not contain the signature, audience, or expiry of the old token you want to check. The starting point of this unit is not to reuse the result that a proxy request succeeded as evidence of token validity.
How to read the audience experiment
This VM's API uses labhub-kcsa-api as its audience. A token issued by specifying labhub-kcsa-report gets a 401 on this API's ConfigMap read. If you TokenReview the same token while explicitly naming the report audience, the authentication result is true. The token was not broken as a whole; it was that the audience it was presented to was different. This is a result confirmed in this unit's actual k3s probe.
This is an example that assumes an external report service exists; the report server was not deployed in this lab. In a real service, you must decide the allowed audiences in server configuration and check against that scope. A check that unconditionally accepts the audience the requester sent loses the purpose of separating audiences.
What it looks like in the field
First confirm the request address and the type of credentials, and then look at the audience, expiry, and authentication result. After authentication succeeds, check the target resource, verb, namespace, and RBAC. Do not conclude that all 403s have the same cause; keep the response reason and the requesting subject together. An anonymous request is also not always a 401, so do not generalize this time's observation of an invalid bearer to all requests.
Setting automountServiceAccountToken to false on a Pod and an SA is a setting that avoids automatic token mounting. It is not a setting that removes the administrator's TokenRequest issuance permission. This Pod turns off automatic mounting and issues the token explicitly so that the two effects are not mixed. A typical projected token is rotated by the kubelet, but the kubelet does not renew on your behalf the token you saved to a file this time. You must distinguish and operate the two delivery methods.
Connecting to the next lesson
The next piece looks at the situation where the UID changes when an account is recreated. In the lab after that, you make a baseline of your own resource 200 and another team's resource 403, and compare the 401 and the TokenReview result when presenting a token for a different audience. Do not paste the token's original text into a terminal, a report, or a bulletin board. Record only claims and hashes, and mark next to each whether it was a decoding, authentication, or authorization observation.