get secrets
Naming a known Secret returns its full data, not metadata, including values, tokens, TLS keys, kubeconfigs, and imagePullSecrets.
In kube-system, access to one high-value Secret can equal cluster takeover.
T0 with following verbs:
A long-lived token for a privileged ServiceAccount, minted on demand
scoped to same namespace as a cluster-admin-equivalent ServiceAccount
create on secrets makes the token controller mint a non-expiring token for any ServiceAccount in the namespace.
get is what reads it back, since the controller writes .data.token after the create response has already returned.
Note:
The pre-v1.24 predictable auto-created ServiceAccount token Secret path is mostly legacy, but manually-created service-account-token Secrets and other high-value Secrets remain dangerous.
- 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.
