Restricting access to the API server
The request path, in one breath
TLS → authentication (client cert, SA token, OIDC, webhook) → authorisation
(Node, RBAC, webhook) → admission (mutating, then validating: PSA, Gatekeeper,
ImagePolicyWebhook) → etcd.
Every "restrict access to the API" task is a flag on one of those stages.
The flags, in the static pod manifest
/etc/kubernetes/manifests/kube-apiserver.yaml:
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=10.0.0.10
- --authorization-mode=Node,RBAC # never AlwaysAllow
- --enable-admission-plugins=NodeRestriction
- --anonymous-auth=false # default is true
- --insecure-port=0 # gone in modern versions, still asked
- --profiling=false
- --audit-policy-file=/etc/kubernetes/audit/policy.yaml
- --audit-log-path=/var/log/kubernetes/audit.log
- --tls-min-version=VersionTLS12
Why NodeRestriction: without it, the kubelet credential of any node can
modify Pods on every node. With it, a kubelet only touches its own Node
object and the Pods bound to it.
Bound the address too
- --bind-address=127.0.0.1 # only if nothing off-node needs the API
More common in the exam: a firewall rule or a NetworkPolicy on thekube-system namespace so only the control plane can reach 6443. Check what is
actually listening with ss -ltnp | grep 6443 on the node.
Restart the static pod, then prove it
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /root/apiserver.bak
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
sleep 20 && kubectl get --raw /healthz
sudo crictl ps | grep kube-apiserver
When you break it (and you will)
The API server is a static pod. If the manifest is invalid, the kubelet keeps
trying, the container never starts, and kubectl is dead. Recovery:
sudo crictl ps -a | grep kube-apiserver # CrashLoopBackOff / Exited
sudo crictl logs <container-id> # the actual parse or flag error
sudo journalctl -u kubelet -n 100 --no-pager | grep -i apiserver
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml # fix the YAML
Then wait. The kubelet retries within ~20 seconds. Do not reboot, do not
reinstall, do not delete the manifest (that removes the control plane).
Admission plugins worth knowing
NodeRestriction— mandatory in practicePodSecurity— enforces PSA namespace labels (built in since 1.25)ImagePolicyWebhook— registry/image allow-listing (see supply chain)AlwaysPullImages— forces a registry check on every startLimitRanger,ResourceQuota— resource abuseServiceAccount— the one that mounts tokens; on by default
Enabling a plugin means a flag change and a restart. --disable-admission-plugins
is how you remove one that breaks the cluster.
kubelet-side restriction
# /var/lib/kubelet/config.yaml
authentication:
anonymous: {enabled: false}
webhook: {enabled: true}
authorization:
mode: Webhook
readOnlyPort: 0
systemctl restart kubelet
curl -sk https://localhost:10250/pods # 401/403 now, not pod JSON