GKE Endpoint Permission Enumeration
Detects a single authenticated GKE identity from one source IP issuing a burst of API calls across many distinct actions and resources with a mix of successful and failed outcomes. That pattern is consistent with automated RBAC permission enumeration rather than steady-state controller traffic. Anonymous probing is covered by a separate rule.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/07/21"
3integration = ["gcp"]
4maturity = "production"
5updated_date = "2026/07/21"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects a single authenticated GKE identity from one source IP issuing a burst of API calls across many distinct
11actions and resources with a mix of successful and failed outcomes. That pattern is consistent with automated RBAC
12permission enumeration rather than steady-state controller traffic. Anonymous probing is covered by a separate rule.
13"""
14false_positives = [
15 """
16 Administrators troubleshooting RBAC from a workstation or VPN may generate mixed allow/deny results across many
17 APIs in a short window; tune by identity or source IP after validation.
18 """,
19 """
20 Newly deployed workloads with incomplete RoleBindings can probe several APIs during startup and encounter
21 intermittent denials; exclude known service accounts if documented.
22 """,
23]
24from = "now-6m"
25interval = "5m"
26language = "esql"
27license = "Elastic License v2"
28name = "GKE Endpoint Permission Enumeration"
29note = """## Triage and analysis
30
31### Investigating GKE Endpoint Permission Enumeration
32
33The rule aggregates GKE audit events per `client.user.email` and `source.ip` over the rule lookback. It alerts when
34the actor hits more than five distinct `event.action` values and more than three distinct `gcp.audit.resource_name`
35values, produces both success and failure outcomes, and stays under 75 total events. Use
36`Esql.earliest_timestamp` and `Esql.latest_timestamp` to bound the burst in Discover.
37
38### Possible investigation steps
39
40- Review `Esql.event_action_values`, `Esql.gcp_audit_resource_name_values`, and `Esql.event_outcome_values` for targeted APIs
41 (secrets, RBAC, pods/exec) and which calls succeeded.
42- Confirm whether `source.ip` and `Esql.user_agent_original_values` match expected admin or automation clients.
43- Hunt for follow-on activity from the same identity: RoleBinding changes, secret reads, privileged pod creates, or
44 exec.
45
46### False positive analysis
47
48- Platform engineers validating least-privilege RBAC can look like enumeration; correlate with change tickets.
49- Chatty operators that occasionally fail authorization may approach the thresholds; raise exclusions only after
50 confirming the identity is expected.
51
52### Response and remediation
53
54- If malicious, revoke or rotate the credential, tighten RBAC, and inspect for data access or persistence after the
55 burst.
56"""
57setup = "The GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule."
58references = [
59 "https://heilancoos.github.io/research/2025/12/16/kubernetes.html#unauthenticated-api-access",
60]
61risk_score = 47
62rule_id = "65985cd5-e654-40fe-8bc7-de26cb95309f"
63severity = "medium"
64tags = [
65 "Domain: Cloud",
66 "Domain: Kubernetes",
67 "Data Source: GCP",
68 "Data Source: Google Cloud Platform",
69 "Use Case: Threat Detection",
70 "Tactic: Discovery",
71 "Resources: Investigation Guide",
72]
73timestamp_override = "event.ingested"
74type = "esql"
75
76query = '''
77from logs-gcp.audit-* metadata _id, _index, _version
78| where data_stream.dataset == "gcp.audit"
79 and service.name == "k8s.io"
80 and client.user.email is not null
81 and source.ip is not null
82 and to_string(source.ip) != "127.0.0.1"
83 and to_string(source.ip) != "::1"
84 and client.user.email != "system:anonymous"
85 and client.user.email != "system:unauthenticated"
86 and gcp.audit.resource_name != "readyz"
87 and gcp.audit.resource_name != "livez"
88 and gcp.audit.resource_name != "healthz"
89 and gcp.audit.resource_name != "version"
90| stats
91 Esql.document_count = count(),
92 Esql.event_outcome_count_distinct = count_distinct(event.outcome),
93 Esql.event_action_count_distinct = count_distinct(event.action),
94 Esql.gcp_audit_resource_name_count_distinct = count_distinct(gcp.audit.resource_name),
95 Esql.earliest_timestamp = min(@timestamp),
96 Esql.latest_timestamp = max(@timestamp),
97 Esql.event_action_values = values(event.action),
98 Esql.event_outcome_values = values(event.outcome),
99 Esql.gcp_audit_resource_name_values = values(gcp.audit.resource_name),
100 Esql.user_agent_original_values = values(user_agent.original)
101 by client.user.email, source.ip
102| where Esql.event_outcome_count_distinct == 2
103 and Esql.event_action_count_distinct > 5
104 and Esql.gcp_audit_resource_name_count_distinct > 3
105 and Esql.document_count < 75
106| keep Esql.*, client.user.email, source.ip
107'''
108
109[[rule.threat]]
110framework = "MITRE ATT&CK"
111
112[[rule.threat.technique]]
113id = "T1613"
114name = "Container and Resource Discovery"
115reference = "https://attack.mitre.org/techniques/T1613/"
116
117[rule.threat.tactic]
118id = "TA0007"
119name = "Discovery"
120reference = "https://attack.mitre.org/tactics/TA0007/"
Triage and analysis
Investigating GKE Endpoint Permission Enumeration
The rule aggregates GKE audit events per client.user.email and source.ip over the rule lookback. It alerts when
the actor hits more than five distinct event.action values and more than three distinct gcp.audit.resource_name
values, produces both success and failure outcomes, and stays under 75 total events. Use
Esql.earliest_timestamp and Esql.latest_timestamp to bound the burst in Discover.
Possible investigation steps
- Review
Esql.event_action_values,Esql.gcp_audit_resource_name_values, andEsql.event_outcome_valuesfor targeted APIs (secrets, RBAC, pods/exec) and which calls succeeded. - Confirm whether
source.ipandEsql.user_agent_original_valuesmatch expected admin or automation clients. - Hunt for follow-on activity from the same identity: RoleBinding changes, secret reads, privileged pod creates, or exec.
False positive analysis
- Platform engineers validating least-privilege RBAC can look like enumeration; correlate with change tickets.
- Chatty operators that occasionally fail authorization may approach the thresholds; raise exclusions only after confirming the identity is expected.
Response and remediation
- If malicious, revoke or rotate the credential, tighten RBAC, and inspect for data access or persistence after the burst.
References
Related rules
- GKE Multi-Resource Discovery
- GKE Anonymous Endpoint Permission Enumeration
- GKE Forbidden Request from Unusual User Agent
- GKE API Server Proxying Request to Kubelet
- GKE API Request Failure Burst by User