Attacker Persistence Mechanisms
Getting in is one problem; staying in is a different one, and in Kubernetes it is solved with ordinary objects that look like configuration. This guide plants three of them, shows why each survives a reboot, and ends with the one query that finds the first.
Kubernetes Threat Model Guide 30 of 42 Intermediate
- Kubernetesapiserver v1.36.4, kubelet v1.36.3
- Runtimecontainerd 2.2.6
- CNICilium 1.18.1
- Built withkubeadm v1.36.3
- TimeAbout 16 min
Manually created kubernetes.io/service-account-token Secrets are still populated by the token controller in v1.36 and the JWT they contain carries no exp. Auto-creation of these Secrets ended in 1.24; creating one by hand did not.
- Host kernel7.0.0-29
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| CKA5001 | 192.168.0.41 | Ubuntu 26.04 LTS | Control Plane Node (tainted NoSchedule) | 2 Core | 4 GB | 50 GB |
| CKA5001-NODE01 | 192.168.0.42 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
| CKA5001-NODE02 | 192.168.0.43 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
| CKA5001-NODE03 | 192.168.0.44 | Ubuntu 26.04 LTS | Worker Node | 2 Core | 4 GB | 50 GB |
This guide includes
Use this when the question is how an intruder stays in. This matters because persistence in Kubernetes is usually an ordinary object rather than malware - a binding, a non-expiring token, or a CronJob that recreates whatever you delete.
- creating a backdoor that is one object and no code whatsoever
- requesting a legacy Secret token that does not expire, and reading its claims
- asking for a modern token for contrast, and comparing the two directly
- leaving a beacon that is not a running process, on a schedule
- running the one query that finds the first of these
Before you start
-
A backdoor that is one object
-
A credential that does not expire
-
For contrast, the modern token
-
A beacon that is not a running process
-
The query that finds the first one