Cases2 cases
1 to 2 of 2
IL-0068Anonymous access to the Kubernetes API server used to plant a ClusterRoleBinding backdoor and a cryptominer DaemonSetAqua Security2023- Symptoms
Aqua's research team Nautilus recorded the attack on one of its Kubernetes honeypots. What appeared in the cluster was a DaemonSet running the image kuberntesio/kube-controller:1.0.1 from Docker Hub on every node, using the nodes' CPU to mine Monero.
- Trigger
An API server misconfigured to accept unauthenticated requests from anonymous users with privileges.
- Root cause
- Component
- Contributing factor
- Detection
Aqua recorded the attacker's API requests on its honeypot; planted AWS access keys raised a beacon when the attacker tried to use them.
- Lessons
Fixing an exposed API server is not enough once an attacker has been in: a ClusterRoleBinding to an attacker-created ServiceAccount keeps working after anonymous access is closed. Attackers name these objects and images after real Kubernetes components so they blend into the API audit logs and pass for legitimate deployments. Aqua recommends scanning clusters for vulnerabilities, exposed secrets and misconfigurations with a tool such as Trivy.
IL-0009A duplicated generated name made Argo CD replace the InfluxDB Cloud production Application and delete the whole production environmentInfluxData2022- Symptoms
Right after a pull request to the infrastructure-as-code repository was merged, every API endpoint of one InfluxDB Cloud production cluster began returning 404 errors. Writes and reads failed alike: no one could collect data, scheduled tasks failed to run and external queries did not work.
- Trigger
A merged pull request whose rendered YAML added a new Argo CD Application and AppProject that an automation error had named app01-cluster01, the name of the existing production Application, instead of app02-cluster01; reviewers did not notice the app01 and app02 difference.
- Root cause
- Component
- Contributing factor
- Detection
Monitoring and alerting did not detect the issue right away, so the team's first response was to try to roll the change back rather than plan a recovery. The write-up does not say how the team found out.
- Remediation
- stopped the revert of the merged pull request
- restored the etcd metadata cluster
- recreated the missing Kubernetes objects so the retained PersistentVolumes became available, then recreated the StatefulSets
- restored the Zookeeper volumes from an hourly Velero backup
- rebuilt the Kafka StatefulSet one pod at a time with health and readiness checks disabled
- accepted writes into the Kafka write-ahead log and scaled up the write path with more replicas and higher memory requests and limits
- recreated the storage pods, which downloaded data from object storage, reindexed it and replayed the write-ahead log
- re-enabled Argo CD, queries, dashboards and scheduled tasks, restored replica counts and ran final QA checks
- Action items
- Write runbooks for restoring state when Kubernetes objects such as PersistentVolumeClaims are deleted but the data on the underlying volumes is preserved
- Set every volume in every environment to retain data when its PersistentVolumeClaim is deleted
- Improve the process for handling public-facing incidents
- Store generated YAML as one object per file, so an overwrite of an existing object shows up as such in review
- Detect duplicate objects when generating YAML and warn before review, treating objects with the same group, namespace and name as the same even when the apiVersion string differs
- Add the Argo CD Prune=false annotation to all stateful resources and to Namespace objects managed by Argo CD
- Set FailOnSharedResource=true on Argo CD Applications so Argo CD fails before changing an object another Application manages or managed
- Lessons
The biggest gap was that monitoring did not notice the deletion quickly, which pushed the team toward a reflex rollback; in a stateful system a revert can create a new, empty instance instead of bringing the old one back. Retained volumes and clients that retry writes are what kept data loss at zero. Rendering many objects into one file let an overwrite of an existing object look like an addition, so generated configuration needs one object per file and duplicate detection that compares objects the way Kubernetes does. Stateful resources need protection from pruning, and that protection must cover their Namespace too, or deleting the namespace removes everything inside it.
These 2 cases involve Argo CD and Configuration templating. kubegap audits a Kubernetes cluster for gaps like these, read-only, from Claude Code or Codex; its checks cite public reports like the ones in this library.
By root cause1
Configuration change2 cases
- Component
- Contributing factor
- Organisation