Module 02 · Lesson 01
Restrict API Access
Close anonymous auth, and understand what actually reaches the API server.
- Find every binding that grants a permission, without reading them all.
- Distinguish anonymous access that is legitimate from access that is not.
- Explain what a RoleBinding to a ClusterRole actually grants.
Something granted this
When an identity can do something it should not, the question is never "how do I block it". There is no deny in RBAC. The question is which binding is granting it, and your job is to find and remove that.
Ask the authorizer, not the objects
Reading bindings by hand misses aggregation, inherited grants and bindings you did not think to grep for. Asking the API server what it would decide accounts for all of it at once.
for ns in $(kubectl get ns -o name | cut -d/ -f2); do
if kubectl auth can-i list pods -n "$ns" --as=system:anonymous >/dev/null 2>&1; then
echo "anonymous can list pods in: $ns"
fi
done
kubectl auth can-i VERB RESOURCE --as=USER --as-group=GROUP -n NS answers in
one call what auditing every Role, ClusterRole and binding answers slowly and
incompletely. Reach for it first, then go find the binding once you know the answer is
yes.
A RoleBinding can reference a ClusterRole
kind: RoleBinding # namespaced binding...
metadata:
namespace: dev
roleRef:
kind: ClusterRole # ...to a cluster-scoped role
name: view
That grants the view permissions inside that namespace only. It
is the normal way to reuse the built-in roles without granting them cluster-wide, and it
surprises people in both directions: they assume it grants nothing, or they assume it grants
everything.
Some anonymous access is meant to be there
Load balancers and probes need liveness and version endpoints, and the
system:public-info-viewer ClusterRole exists for exactly that. Do not remove
it. The rule is simple: unauthenticated may check liveness, and may never read resources.
You need to know whether an identity can read secrets in a namespace. What is the most reliable check?
Manual auditing misses aggregated roles, group membership and bindings you did not grep for. The authorizer evaluates every path at once, which is exactly the question you are asking.
A RoleBinding in namespace dev references the cluster-admin ClusterRole. What does the subject get?
The binding's kind decides the scope, not the role's. That makes this a genuinely useful pattern, and also a very easy thing to misread during an audit in either direction.
Should you remove the default binding that lets unauthenticated callers reach /healthz?
Liveness and version endpoints leak nothing useful and breaking them breaks health checking. The control you want is that anonymous cannot read resources, which is a different binding entirely.
There is no deny in RBAC, so unwanted access always means finding the grant. Ask the
authorizer with auth can-i --as rather than reading objects. A RoleBinding
to a ClusterRole scopes it to that namespace. Liveness endpoints stay anonymous. Next:
RBAC itself.