[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:
+101
@@ -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 workload’s 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/"
|
||||
Reference in New Issue
Block a user