Kubernetes Multi-Resource Discovery

Adversaries who land credentials in a cluster—or abuse an over-privileged token—often map the environment before exfiltration or privilege escalation. A practical first pass is to learn where workloads run, how the cluster is partitioned, and what RBAC exists at namespace vs cluster scope. Rapid get/list traffic across distinct API resource kinds that answer those questions (namespaces, workloads, roles, cluster-wide roles) is a common setup and orientation pattern for both interactive attackers and automated recon scripts. It is less typical for steady-state controllers, which usually touch a narrow set of resources repeatedly. This rule highlights that cross-resource burst from a single client fingerprint within a one-minute bucket so analysts can separate routine automation from potential discovery and permission reconnaissance ahead of follow-on actions.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/04/22"
  3integration = ["kubernetes"]
  4maturity = "production"
  5updated_date = "2026/04/22"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Adversaries who land credentials in a cluster—or abuse an over-privileged token—often map the environment before
 11exfiltration or privilege escalation. A practical first pass is to learn where workloads run, how the cluster is
 12partitioned, and what RBAC exists at namespace vs cluster scope. Rapid `get`/`list` traffic across distinct
 13API resource kinds that answer those questions (namespaces, workloads, roles, cluster-wide roles) is a common
 14setup and orientation pattern for both interactive attackers and automated recon scripts. It is less typical for
 15steady-state controllers, which usually touch a narrow set of resources repeatedly. This rule highlights that
 16cross-resource burst from a single client fingerprint within a one-minute bucket so analysts can separate routine
 17automation from potential discovery and permission reconnaissance ahead of follow-on actions.
 18"""
 19from = "now-11m"
 20interval = "5m"
 21language = "esql"
 22license = "Elastic License v2"
 23name = "Kubernetes Multi-Resource Discovery"
 24note = """## Triage and analysis
 25
 26### Investigating Kubernetes Multi-Resource Discovery
 27
 28The rule groups Kubernetes audit `get`/`list` events on namespaces, pods, roles, and clusterroles into one-minute windows 
 29per `user.name`, `source.ip`, `user_agent.original`, and flags windows where three or more distinct resource types appear. 
 30That combination is consistent with someone sketching cluster layout and privilege structure rather than touching a single 
 31resource type. **Allowed and denied** authorizations are both included: failures still signal probing and validate which 
 32object types the caller attempted to reach.
 33
 34### Possible investigation steps
 35
 36- Pivot on `Esql.time_interval` and the same identity or IP in raw audit logs to see ordering (e.g. namespaces first,
 37  then roles, then pods) and whether calls succeeded.
 38- Review `Esql.decisions` and namespaces touched; correlate with RBAC for that identity to see if scope matches a
 39  known job or breaks least-privilege expectations.
 40- Hunt for follow-on activity: secret/configmap reads, rolebinding changes, pod exec, anonymous or unusual user agents.
 41- Baseline automation: CI, GitOps, and some monitoring agents can read several resource types during sync; exclude
 42  known service accounts or source networks if noisy.
 43
 44### False positive analysis
 45
 46- Platform operators or runbooks that reconcile RBAC and workload state may legitimately span these resource types in
 47  a short window; tune by user, IP allowlist, or user agent when documented.
 48- Some installers briefly query namespaces, pods, and roles during upgrades—correlate with change windows.
 49
 50### Response and remediation
 51
 52- If malicious, revoke or rotate the implicated credentials, review and tighten RBAC, and inspect for data access or
 53  persistence established after the burst.
 54"""
 55references = [
 56    "https://attack.mitre.org/techniques/T1613/",
 57    "https://microsoft.github.io/Threat-Matrix-for-Kubernetes/",
 58]
 59risk_score = 47
 60rule_id = "c2a91e88-4f4b-4e1d-9c7b-8fde112a9403"
 61severity = "medium"
 62tags = [
 63    "Data Source: Kubernetes",
 64    "Domain: Kubernetes",
 65    "Use Case: Threat Detection",
 66    "Tactic: Discovery",
 67    "Resources: Investigation Guide",
 68]
 69timestamp_override = "event.ingested"
 70type = "esql"
 71query = '''
 72from logs-kubernetes.audit_logs-* metadata _id, _index, _version
 73| eval Esql.time_interval = date_trunc(1 minute, @timestamp)
 74| where event.dataset == "kubernetes.audit_logs"
 75    and event.action in ("get", "list")
 76    and kubernetes.audit.objectRef.resource in ("namespaces", "nodes", "pods", "roles", "configmaps", "serviceaccounts", "clusterroles", "clusterrolebindings", "rolebindings")
 77    and source.ip is not null and user.name IS NOT NULL
 78    and not to_string(source.ip) in ("127.0.0.1", "::1")
 79    and not user.name rlike """(system:serviceaccount:kube-system:|eks:|system:kube-|arn:aws:sts::.*:assumed-role/AWSServiceRoleForAmazonEKS/|system:serviceaccount:kube-system:azure|system:node:aks-default|aksService).*"""
 80| stats
 81    Esql.unique_resources = count_distinct(kubernetes.audit.objectRef.resource),
 82    Esql.enumerated_resources = values(kubernetes.audit.objectRef.resource),
 83    Esql.enumerated_namespaces = values(kubernetes.audit.objectRef.namespace),
 84    Esql.decisions = values(`kubernetes.audit.annotations.authorization_k8s_io/decision`)
 85  by user.name, source.ip, user_agent.original, Esql.time_interval
 86| where Esql.unique_resources >= 3
 87| keep Esql.*, user.name, source.ip, user_agent.original
 88'''
 89
 90[[rule.threat]]
 91framework = "MITRE ATT&CK"
 92
 93[[rule.threat.technique]]
 94id = "T1613"
 95name = "Container and Resource Discovery"
 96reference = "https://attack.mitre.org/techniques/T1613/"
 97
 98[rule.threat.tactic]
 99id = "TA0007"
100name = "Discovery"
101reference = "https://attack.mitre.org/tactics/TA0007/"

Triage and analysis

Investigating Kubernetes Multi-Resource Discovery

The rule groups Kubernetes audit get/list events on namespaces, pods, roles, and clusterroles into one-minute windows per user.name, source.ip, user_agent.original, and flags windows where three or more distinct resource types appear. That combination is consistent with someone sketching cluster layout and privilege structure rather than touching a single resource type. Allowed and denied authorizations are both included: failures still signal probing and validate which object types the caller attempted to reach.

Possible investigation steps

  • Pivot on Esql.time_interval and the same identity or IP in raw audit logs to see ordering (e.g. namespaces first, then roles, then pods) and whether calls succeeded.
  • Review Esql.decisions and namespaces touched; correlate with RBAC for that identity to see if scope matches a known job or breaks least-privilege expectations.
  • Hunt for follow-on activity: secret/configmap reads, rolebinding changes, pod exec, anonymous or unusual user agents.
  • Baseline automation: CI, GitOps, and some monitoring agents can read several resource types during sync; exclude known service accounts or source networks if noisy.

False positive analysis

  • Platform operators or runbooks that reconcile RBAC and workload state may legitimately span these resource types in a short window; tune by user, IP allowlist, or user agent when documented.
  • Some installers briefly query namespaces, pods, and roles during upgrades—correlate with change windows.

Response and remediation

  • If malicious, revoke or rotate the implicated credentials, review and tighten RBAC, and inspect for data access or persistence established after the burst.

References

Related rules

to-top