[New] Kubernetes Secret get or list from Node or Pod Service Account (#5973)

* [New] Kubernetes Secret get or list from Node or Pod Service Account

Kubernetes audit identities for kubelet (`system:node:*`) and workloads (`system:serviceaccount:*`) are meant to operate with tight, predictable API usage. Direct `get` or `list` on the Secrets API from those principals is
often a sign of credential access.

* Update credential_access_kubernetes_secret_read_by_node_or_pod_service_account.toml

* Update credential_access_kubernetes_secret_read_by_node_or_pod_service_account.toml
This commit is contained in:
Samirbous
2026-05-02 11:48:24 +01:00
committed by GitHub
parent e0c6e715fb
commit 338548a306
@@ -0,0 +1,101 @@
[metadata]
creation_date = "2026/04/22"
integration = ["kubernetes"]
maturity = "production"
updated_date = "2026/04/22"
[rule]
author = ["Elastic"]
description = """
Kubernetes audit identities for kubelet (`system:node:*`) and workloads (`system:serviceaccount:*`) are meant to
operate with tight, predictable API usage. Direct `get` or `list` on the Secrets API from those principals is
often a sign of credential access. Attackers who stole a pod service-account token or node credentials sweep Secret objects for
tokens, registry credentials, TLS keys, or application configuration. Even denied attempts still reveal intent to
reach sensitive material. Legitimate controllers do read secrets they mount or manage, so this signal is most valuable
when paired with triage (namespace scope, user agent, RBAC, and whether the identity should touch those secret names at
all).
"""
false_positives = [
"""
In-cluster operators, CSI drivers, GitOps agents, and some platform controllers legitimately list or get Secrets in
namespaces they manage; exclude known service accounts, namespaces, or user agents after baselining.
""",
"""
Rare kubelet or node maintenance tooling may touch Secret APIs; validate against change windows and approved node
management paths.
""",
]
index = ["logs-kubernetes.audit_logs-*"]
language = "kuery"
license = "Elastic License v2"
name = "Kubernetes Secret get or list from Node or Pod Service Account"
note = """## Triage and analysis
### Investigating Kubernetes Secret get or list from Node or Pod Service Account
This rule fires on Kubernetes audit events where the authenticated user is a node (`system:node:<nodename>`) or a
pod service account (`system:serviceaccount:<namespace>:<name>`) and the verb maps to read-style access
(`get`, `list`) on the **secrets** resource. Treat node-originated secret reads as high priority: kubelet should
not broadly enumerate cluster secrets. For service accounts, prioritize cross-namespace access, access to
high-value secret names, and clients that do not match the workloads normal user agent or deployment.
### Possible investigation steps
- Resolve `user.name` (or `kubernetes.audit.user.username` if present) to the node or workload and review RBAC
RoleBindings and ClusterRoleBindings for secret `get`/`list` scope.
- Inspect `kubernetes.audit.objectRef.namespace`, `kubernetes.audit.objectRef.name`, source IP, and
`user_agent.original` for automation you recognize versus anomalous scripts or generic HTTP clients.
- Review `kubernetes.audit.annotations.authorization_k8s_io/decision` for successful reads versus probing denials.
- Correlate with pod exec, token creation, RoleBinding changes, or secret modification in the same time window.
### False positive analysis
- Controllers that reconcile Secrets (e.g. cert-manager, external-secrets, sealed-secrets) may match; allowlist their
service accounts if behavior is expected and scoped.
- Helm and package managers can list release secrets during deploys; correlate with pipelines and chart releases.
### Response and remediation
- If malicious, revoke the token or node credentials, cordon or isolate the host or workload, rotate exposed secrets, and
tighten RBAC to least privilege for the affected identity.
"""
references = [
"https://attack.mitre.org/techniques/T1552/007/",
"https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens",
]
risk_score = 47
rule_id = "f8a31c62-0d4e-4b9a-b7e1-6c2a9d4e8f10"
severity = "medium"
tags = [
"Data Source: Kubernetes",
"Domain: Kubernetes",
"Use Case: Threat Detection",
"Tactic: Credential Access",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
data_stream.dataset:"kubernetes.audit_logs" and
event.action:(get or list) and
kubernetes.audit.objectRef.resource:"secrets" and
user.name:(system\:serviceaccount\:* or system\:node\:*) and source.ip:*
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1552"
name = "Unsecured Credentials"
reference = "https://attack.mitre.org/techniques/T1552/"
[[rule.threat.technique.subtechnique]]
id = "T1552.007"
name = "Container API"
reference = "https://attack.mitre.org/techniques/T1552/007/"
[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"