GKE Anonymous Endpoint Permission Enumeration
Detects bursts of GKE API requests from an anonymous identity that probe many distinct actions and resources with mostly failed outcomes. This pattern is consistent with unauthenticated permission enumeration against an exposed API server. On GKE GCP audit logs, unauthenticated probes often omit "client.user.email" (null principal) with Unauthorized failures; those events are included alongside "system:anonymous" / "system:unauthenticated".
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/07/16"
3integration = ["gcp"]
4maturity = "production"
5updated_date = "2026/09/18"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects bursts of GKE API requests from an anonymous identity that probe many distinct actions and resources with
11mostly failed outcomes. This pattern is consistent with unauthenticated permission enumeration against an exposed API
12server. On GKE GCP audit logs, unauthenticated probes often omit "client.user.email" (null principal) with
13Unauthorized failures; those events are included alongside "system:anonymous" / "system:unauthenticated".
14"""
15from = "now-6m"
16interval = "5m"
17language = "esql"
18license = "Elastic License v2"
19name = "GKE Anonymous Endpoint Permission Enumeration"
20note = """## Triage and analysis
21
22### Investigating GKE Anonymous Endpoint Permission Enumeration
23
24Anonymous multi-endpoint failure bursts map which APIs are reachable before credential theft or exploitation.
25Treat missing `client.user.email` with Unauthorized/failure bursts as anonymous on GKE.
26
27### Investigation steps
28
29- Review `Esql.event_action_values` and `Esql.resource_name_values` for targeted APIs (secrets, RBAC, CRDs).
30- Confirm whether `source.ip` is Internet-routable and whether the API endpoint is publicly exposed.
31- Hunt for later successful anonymous or authenticated activity from the same source or user agent.
32
33### False positives
34
35- Misconfigured auth proxies that strip credentials can make legitimate clients appear anonymous during outages.
36
37"""
38references = [
39 "https://heilancoos.github.io/research/2025/12/16/kubernetes.html#unauthenticated-api-access",
40 "https://cloud.google.com/kubernetes-engine/docs/how-to/audit-logging",
41]
42risk_score = 47
43rule_id = "bd7345e5-c822-41de-a393-7573fec07ef4"
44severity = "medium"
45tags = [
46 "Domain: Cloud",
47 "Domain: Kubernetes",
48 "Data Source: GCP",
49 "Data Source: Google Cloud Platform",
50 "Use Case: Threat Detection",
51 "Tactic: Discovery",
52 "Tactic: Reconnaissance",
53 "Resources: Investigation Guide",
54 "Noise: Low",
55 "Performance: Normal",
56 "Rule Type: ES|QL",
57 "Platform: GCP",
58 "Domain: Containers",
59 "Platform: Kubernetes",
60]
61timestamp_override = "event.ingested"
62type = "esql"
63setup = "The GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule."
64
65query = '''
66from logs-gcp.audit-* metadata _id, _index, _version
67| where data_stream.dataset == "gcp.audit"
68 and service.name == "k8s.io"
69 and (
70 client.user.email in ("system:anonymous", "system:unauthenticated")
71 or client.user.email is null
72 )
73 and not gcp.audit.resource_name in ("readyz", "livez", "healthz", "version")
74| stats
75 Esql.document_count = count(),
76 Esql.failure_count = sum(case(event.outcome == "failure", 1, 0)),
77 Esql.event_action_count_distinct = count_distinct(event.action),
78 Esql.resource_name_count_distinct = count_distinct(gcp.audit.resource_name),
79 Esql.event_action_values = values(event.action),
80 Esql.resource_name_values = values(gcp.audit.resource_name),
81 Esql.event_outcome_values = values(event.outcome),
82 Esql.client_user_email_values = values(client.user.email),
83 Esql.timestamp = VALUES(@timestamp),
84 Esql.data_stream_namespace = VALUES(data_stream.namespace),
85 Esql.user_agent_original_values = VALUES(user_agent.original)
86 by source.ip
87| where Esql.event_action_count_distinct > 5
88 and Esql.resource_name_count_distinct > 3
89 and Esql.document_count < 50
90 and Esql.failure_count >= 1
91| keep Esql.*, source.ip
92'''
93
94[[rule.threat]]
95framework = "MITRE ATT&CK"
96
97[[rule.threat.technique]]
98id = "T1613"
99name = "Container and Resource Discovery"
100reference = "https://attack.mitre.org/techniques/T1613/"
101
102[rule.threat.tactic]
103id = "TA0007"
104name = "Discovery"
105reference = "https://attack.mitre.org/tactics/TA0007/"
106
107[[rule.threat]]
108framework = "MITRE ATT&CK"
109
110[[rule.threat.technique]]
111id = "T1595"
112name = "Active Scanning"
113reference = "https://attack.mitre.org/techniques/T1595/"
114
115[[rule.threat.technique.subtechnique]]
116id = "T1595.003"
117name = "Wordlist Scanning"
118reference = "https://attack.mitre.org/techniques/T1595/003/"
119
120[rule.threat.tactic]
121id = "TA0043"
122name = "Reconnaissance"
123reference = "https://attack.mitre.org/tactics/TA0043/"
Triage and analysis
Investigating GKE Anonymous Endpoint Permission Enumeration
Anonymous multi-endpoint failure bursts map which APIs are reachable before credential theft or exploitation.
Treat missing client.user.email with Unauthorized/failure bursts as anonymous on GKE.
Investigation steps
- Review
Esql.event_action_valuesandEsql.resource_name_valuesfor targeted APIs (secrets, RBAC, CRDs). - Confirm whether
source.ipis Internet-routable and whether the API endpoint is publicly exposed. - Hunt for later successful anonymous or authenticated activity from the same source or user agent.
False positives
- Misconfigured auth proxies that strip credentials can make legitimate clients appear anonymous during outages.
References
Related rules
- GKE API Server Proxying Request to Kubelet
- GKE Admission Webhook Created or Modified
- GKE Certificate Signing Request for Privileged Identity
- GKE Endpoint Permission Enumeration
- GKE Forbidden Request from Unusual User Agent