Module 02 · Lesson 01

Restrict API Access

Close anonymous auth, and understand what actually reaches the API server.

Hands-on
Learning objectives
  • 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.
kube-apiserver RBAC

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.

terminal
$kubectl get clusterrolebindings -o wide | grep -iE 'anonymous|unauthenticated'
$kubectl describe rolebinding anonymous-can-view -n cks-api

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.

bash
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
can-i --as is the fastest tool in this domain

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

yaml
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

terminal
$curl -sk https://127.0.0.1:6443/healthz
ok
$curl -sk https://127.0.0.1:6443/version | head -3
Where the line sits

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?

A RoleBinding in namespace dev references the cluster-admin ClusterRole. What does the subject get?

Should you remove the default binding that lets unauthenticated callers reach /healthz?

Recap

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.