2026-11-09
Tighter security for the components we run in your cluster
#security #kubernetes #component #wireguard #aikido
We’ve locked down how the platform components in your cluster run, so a compromised component can do far less damage. Nothing changes in how you use your cluster. The changes reach non-production clusters first, and production follows after a soak period. This is proactive hardening: we found no signs of exploitation.
What changed
- WireGuard no longer runs privileged. WireGuard is the one platform component that’s reachable from the internet by design. Until now it ran as a privileged container, which made it root on its node. Now it gets only the two network capabilities it needs and runs in its own user namespace, so its root user isn’t root on the node. Its root filesystem is also read-only now. Your existing VPN clients keep working as before.
- Platform components run as non-root and locked down. Flux, cert-manager, KEDA, Alloy, Grafana, Tempo, Velero, Dex, the Vertical Pod Autoscaler and others now run as an explicit non-root user and group. They can’t escalate privileges, and they use the default seccomp profile. Where possible, their root filesystem is read-only. Alloy and the Tailscale connector we use to reach your cluster used to run as root and now run as non-root users.
- No Kubernetes API token where it isn’t needed. Components that never talk to the Kubernetes API, such as Alertmanager, Loki, Tempo and Alloy, no longer get a ServiceAccount token. A compromised pod has no credentials to use against your cluster.
- Secrets come from files instead of environment variables. Grafana, Alloy, oauth2-proxy and the Tailscale connector now read their secrets from mounted files. Environment variables leak easily, for example into debug output or child processes.
- Self-hosted GitHub Actions runners. If we run GitHub Actions runners for you, their controller and listener now run as non-root with a read-only filesystem. Your runners and workflows stay the same.
- Already live since October: the Cluster Portal runs under its own ServiceAccount, and every platform container has a memory limit, so one misbehaving component can’t starve a node.
What you’ll see in Aikido
If you’ve connected your cluster to Aikido, you’ll see far fewer findings on our platform components. On our test cluster, the container-hardening checks went from 84 open findings to zero. Most of them are fixed. Some can’t be fixed: add-ons whose setup AWS controls, and controllers that need the Kubernetes API to do their job. Those are marked as accepted in the Aikido baseline we maintain, each with the reason.
What you need to do
Nothing, in almost every case. One edge case: if your cluster definition sets observability.grafana.secretEnv, Grafana now reads those values from files. A Grafana provisioning file or plugin that reads one of those environment variables directly would get a $__file{...} reference instead of the value. We didn’t find any cluster that sets this, but if yours does, let us know before your production rollout.
What’s next
Next, we’re looking at admission control: having the cluster itself refuse privileged or root containers in namespaces that don’t need them. We’ll share more once we’ve chosen an approach.