diff --git a/rules/integrations/kubernetes/credential_access_kubernetes_secret_read_by_node_or_pod_service_account.toml b/rules/integrations/kubernetes/credential_access_kubernetes_secret_read_by_node_or_pod_service_account.toml new file mode 100644 index 000000000..bb4434b66 --- /dev/null +++ b/rules/integrations/kubernetes/credential_access_kubernetes_secret_read_by_node_or_pod_service_account.toml @@ -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:`) or a +pod service account (`system:serviceaccount::`) 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/"