GKE Anonymous Endpoint Permission Enumeration
editGKE Anonymous Endpoint Permission Enumeration
editDetects 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".
Rule type: esql
Rule indices: None
Severity: medium
Risk score: 47
Runs every: 5m
Searches indices from: now-6m (Date Math format, see also Additional look-back time)
Maximum alerts per execution: 100
References:
Tags:
- Domain: Cloud
- Domain: Kubernetes
- Data Source: GCP
- Data Source: Google Cloud Platform
- Use Case: Threat Detection
- Tactic: Discovery
- Tactic: Reconnaissance
- Resources: Investigation Guide
Version: 1
Rule authors:
- Elastic
Rule license: Elastic License v2
Investigation guide
editTriage 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.
Setup
editThe GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule.
Rule query
editfrom logs-gcp.audit-* metadata _id, _index, _version
| where data_stream.dataset == "gcp.audit"
and service.name == "k8s.io"
and (
client.user.email in ("system:anonymous", "system:unauthenticated")
or client.user.email is null
)
and not gcp.audit.resource_name in ("readyz", "livez", "healthz", "version")
| stats
Esql.document_count = count(),
Esql.failure_count = sum(case(event.outcome == "failure", 1, 0)),
Esql.event_action_count_distinct = count_distinct(event.action),
Esql.resource_name_count_distinct = count_distinct(gcp.audit.resource_name),
Esql.event_action_values = values(event.action),
Esql.resource_name_values = values(gcp.audit.resource_name),
Esql.event_outcome_values = values(event.outcome),
Esql.client_user_email_values = values(client.user.email),
Esql.timestamp = VALUES(@timestamp),
Esql.data_stream_namespace = VALUES(data_stream.namespace),
Esql.user_agent_original_values = VALUES(user_agent.original)
by source.ip
| where Esql.event_action_count_distinct > 5
and Esql.resource_name_count_distinct > 3
and Esql.document_count < 50
and Esql.failure_count >= 1
| keep Esql.*, source.ip
Framework: MITRE ATT&CKTM
-
Tactic:
- Name: Discovery
- ID: TA0007
- Reference URL: https://attack.mitre.org/tactics/TA0007/
-
Technique:
- Name: Container and Resource Discovery
- ID: T1613
- Reference URL: https://attack.mitre.org/techniques/T1613/
-
Tactic:
- Name: Reconnaissance
- ID: TA0043
- Reference URL: https://attack.mitre.org/tactics/TA0043/
-
Technique:
- Name: Active Scanning
- ID: T1595
- Reference URL: https://attack.mitre.org/techniques/T1595/
-
Sub-technique:
- Name: Wordlist Scanning
- ID: T1595.003
- Reference URL: https://attack.mitre.org/techniques/T1595/003/