AWS EKS 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. 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. This rule detects cross-resource bursts from a single client fingerprint within a one-minute bucket which may represent reconnaissance.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/08/03"
  3integration = ["aws"]
  4maturity = "production"
  5min_stack_comments = "The AWS integration adds the aws.eks_audit data stream in package 8.9.0, which requires Kibana 9.6.0 or later."
  6min_stack_version = "9.6.0"
  7updated_date = "2026/10/20"
  8
  9[rule]
 10author = ["Elastic"]
 11description = """
 12Adversaries who land credentials in a cluster or abuse an over-privileged token, often map the environment before
 13exfiltration or privilege escalation. Rapid get/list traffic across distinct API resource kinds that answer those
 14questions (namespaces, workloads, roles, cluster-wide roles) is a common setup and orientation pattern for both
 15interactive attackers and automated recon scripts. This rule detects cross-resource bursts from a single client
 16fingerprint within a one-minute bucket which may represent reconnaissance.
 17"""
 18from = "now-11m"
 19language = "esql"
 20license = "Elastic License v2"
 21name = "AWS EKS Multi-Resource Discovery"
 22note = """## Triage and analysis
 23
 24### Investigating AWS EKS Multi-Resource Discovery
 25The rule groups Kubernetes audit `get`/`list` events on namespaces, pods, roles, and clusterroles into one-minute windows
 26per `user.name`, `source.ip`, `user_agent.original`, and flags windows where three or more distinct resource types appear.
 27That combination is consistent with someone sketching cluster layout and privilege structure rather than touching a single
 28resource type. **Allowed and denied** authorizations are both included: failures still signal probing and validate which
 29object types the caller attempted to reach.
 30
 31### Possible investigation steps
 32
 33- Pivot on `Esql.time_interval` and the same identity or IP in raw audit logs to see ordering (e.g. namespaces first,
 34  then roles, then pods) and whether calls succeeded.
 35- Review `Esql.decisions` and namespaces touched; correlate with RBAC for that identity to see if scope matches a
 36  known job or breaks least-privilege expectations.
 37- Hunt for follow-on activity: secret/configmap reads, rolebinding changes, pod exec, anonymous or unusual user agents.
 38- Baseline automation: CI, GitOps, and some monitoring agents can read several resource types during sync; exclude
 39  known service accounts or source networks if noisy.
 40
 41### False positive analysis
 42
 43- Platform operators or runbooks that reconcile RBAC and workload state may legitimately span these resource types in
 44  a short window; tune by user, IP allowlist, or user agent when documented.
 45- Some installers briefly query namespaces, pods, and roles during upgrades—correlate with change windows.
 46
 47### Response and remediation
 48
 49- If malicious, revoke or rotate the implicated credentials, review and tighten RBAC, and inspect for data access or
 50  persistence established after the burst."""
 51references = ["https://microsoft.github.io/Threat-Matrix-for-Kubernetes/"]
 52risk_score = 47
 53rule_id = "67ff2b08-37af-53ce-a19e-00acca8515e0"
 54setup = """This rule reads EKS control-plane audit logs collected by the AWS integration
 55into `logs-aws.eks_audit-*`, where the AWS EKS audit ingest
 56pipelines normalize each audit record under `aws.eks.audit.*`.
 57
 58Enable the `audit` control-plane log type on the EKS cluster, send its
 59CloudWatch log group through the AWS integration, and confirm events carry
 60`data_stream.dataset: aws.eks_audit` and
 61`cloud.provider: aws` before enabling this rule.
 62"""
 63severity = "medium"
 64tags = [
 65    "Domain: Cloud",
 66    "Domain: Containers",
 67    "Platform: AWS",
 68    "Platform: Kubernetes",
 69    "Data Source: AWS",
 70    "Data Source: Amazon Web Services",
 71    "Data Source: Kubernetes API Server Audit Logs",
 72    "Service: AWS EKS",
 73    "Use Case: Threat Detection",
 74    "Tactic: Discovery",
 75    "Rule Type: ES|QL",
 76    "Resources: Investigation Guide",
 77    "Profile: Beta",
 78]
 79timestamp_override = "event.ingested"
 80type = "esql"
 81
 82query = '''
 83from logs-aws.eks_audit-* metadata _id, _index, _version
 84| eval Esql.time_interval = date_trunc(1 minute, @timestamp)
 85| where data_stream.dataset == "aws.eks_audit"
 86    and event.action in ("get", "list")
 87    and aws.eks.audit.objectRef.resource in ("namespaces", "nodes", "pods", "roles", "configmaps", "serviceaccounts", "clusterroles", "clusterrolebindings", "rolebindings")
 88    and source.ip is not null and user.name IS NOT NULL
 89    and not to_string(source.ip) in ("127.0.0.1", "::1")
 90    and not user.name rlike """(system:serviceaccount:kube-system:|eks:|system:kube-|arn:aws:sts::.*:assumed-role/AWSServiceRoleForAmazonEKS/).*"""
 91    and not aws.eks.audit.user.username in ("system:serviceaccount:flux-system:kustomize-controller", "system:serviceaccount:flux-system:helm-controller", "system:serviceaccount:flux-system:source-controller", "system:serviceaccount:security:trivy-operator")
 92| stats
 93    Esql.unique_resources = count_distinct(aws.eks.audit.objectRef.resource),
 94    Esql.enumerated_resources = values(aws.eks.audit.objectRef.resource),
 95    Esql.enumerated_namespaces = values(aws.eks.audit.objectRef.namespace),
 96    Esql.decisions = values(`aws.eks.audit.annotations.authorization_k8s_io/decision`)
 97  by user.name, aws.eks.audit.user.username, source.ip, user_agent.original, Esql.time_interval
 98| where Esql.unique_resources >= 3
 99| keep Esql.*, aws.eks.audit.user.username, user.name, source.ip, user_agent.original
100'''
101
102
103[[rule.threat]]
104framework = "MITRE ATT&CK"
105[[rule.threat.technique]]
106id = "T1613"
107name = "Container and Resource Discovery"
108reference = "https://attack.mitre.org/techniques/T1613/"
109
110
111[rule.threat.tactic]
112id = "TA0007"
113name = "Discovery"
114reference = "https://attack.mitre.org/tactics/TA0007/"

Triage and analysis

Investigating AWS EKS 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