watch secrets
A stream of every Secret written in one namespace, with full data, so credentials are captured as they are created or rotated rather than having to be guessed by name.
Ranks below the same verb at cluster scope only because the blast radius stops at the namespace boundary.
In kube-system, or any namespace holding a cluster-privileged ServiceAccount, the two are equivalent.
Contextual upgrade to T0:
T0 in kube-system, or in any namespace holding a cluster-privileged ServiceAccount, since one namespace is then enough to read the credentials the whole cluster trusts.
The namespace boundary is what keeps this below the cluster-scoped verb, so the boundary is only worth as much as the namespace's contents.
Note:
Kubernetes v1.24 stopped auto-creating long-lived ServiceAccount token Secrets by default, but manually-created service-account-token Secrets remain supported and legacy token Secrets may still exist.
- API Group
- (core)
- Scope
- namespaced
- Audit Level
- RequestResponse
Escalation Paths
get or list secrets in an accessible namespace
Extract cloud API keys, DB credentials, TLS keys, or kubeconfigs
Use the credentials to escalate inside or outside the cluster
Additional rights needed:
get a known service-account-token Secret name in kube-system.
Before 1.24, these were auto-created for every ServiceAccount under a predictable name, so they could simply be guessed
Auto-creation is off by default from 1.24, so on a current cluster the Secret has to already exist, and operator-managed clusters commonly keep one
Where secrets-create is also held, the precondition can be manufactured rather than found.
Annotate a new Secret for a privileged ServiceAccount, and the token controller fills in the token
Reuse the controller ServiceAccount token for cluster-admin-equivalent access.
Tokens from Secrets carry no expiry claim, so the access does not lapse
Additional rights needed:
Note:
1.24 stopped auto-creating token Secrets, so guessing a predictable name is dead, but the underlying mechanism is not.
Manually created service-account-token Secrets are still populated with non-expiring tokens, and secrets-create in kube-system manufactures the precondition.
Create a kubernetes.io/service-account-token Secret annotated with the target ServiceAccount name.
The token controller populates .data.token with a signed JWT for that ServiceAccount which does not expire.
Population happens after the create response returns, so the token is never in the create result.
Retrieval therefore needs get, list, or watch on secrets, or a pod that mounts the Secret.
create alone mints a credential the caller cannot read.
Authenticate as the target ServiceAccount with the retrieved token.
Additional rights needed:
· create mints the token, get reads it back by name
· list returns the data without needing the name
· watch catches the token as the controller fills it in
· a pod that mounts the Secret reads it instead
Note:
The token controller still populates kubernetes.io/service-account-token Secrets created by hand, and long-lived token Secrets remain supported.
Restrict create on secrets and audit for hand-made token Secrets in kube-system.
