So you've got a kubeadm cluster up and running. Congratulations, you've just installed the default, opinionated, and frankly pretty open configuration that the k8s maintainers provide. It's fine for a lab. For anything else, it's a compliance nightmare waiting to happen.
Everyone points to the CIS Kubernetes Benchmark PDF like it's the holy grail. It's not. It's a checklist written for auditors, not engineers. The real value is in understanding *which* of those 200+ checks actually matter for your threat model and not just blindly running `kube-bench` and calling it a day. Most of the hardening guides out there are just regurgitating the same `kube-bench` commands you can find in the README, wrapped in some affiliate-link-laden blog post. Let's skip that.
The first thing you need to do is ditch the static pod manifests kubeadm gives you and move to a proper, managed systemd service for the kubelet. The default kubeadm setup runs it with `--authorization-mode=AlwaysAllow` and other horrors. Your control plane nodes should have a `/etc/systemd/system/kubelet.service.d/10-hardening.conf` that actually enforces something.
```ini
[Service]
Environment="KUBELET_AUTHZ_ARGS=--authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt"
Environment="KUBELET_SYSCTL_ARGS=--allowed-unsafe-sysctls=net.ipv4.tcp_keepalive_time"
# You'll need to add other overrides here, merging with existing kubeadm args
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_SYSTEMD_ARGS $KUBELET_AUTHZ_ARGS $KUBELET_EXTRA_ARGS
```
Then you get into the API server. `--anonymous-auth=false` is the obvious one, but have you looked at your `--enable-admission-plugins`? `NodeRestriction` is non-negotiable. `PodSecurity` (or the deprecated `PodSecurityPolicy` if you're on an older version) is where you'll actually stop workload misbehavior, not by tweaking TLS ciphers. And for the love of all that is holy, if your `--audit-log-path` is still writing to a local file on a node you might lose, you've missed the point entirely.
The real work isn't running the scanner; it's the remediation. Half the "failures" `kube-bench` reports are warnings that you need to decide on. For example, it'll flag that the scheduler and controller-manager don't bind to a specific interface. On a properly firewalled control plane network with no public interface, that might be an acceptable risk versus the complexity of running them as a static pod with custom flags. The other half will break your cluster if you apply them post-hoc. Changing etcd's peer/auth certs after the fact? Good luck.
Most people stop at the control plane. The node-level benchmarks (the 4.x series in CIS) are where the real grind is: sysctl flags, cri config, partitioning, and user permissions. Automate this with your node provisioning (Terraform, Ansible, etc.) or you'll drift immediately. And none of this matters if your applications run as root because your developers can't be bothered with a `securityContext`.
Just my 2 cents