﻿---
title: GKE Endpoint Permission Enumeration
description: 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...
url: https://www.elastic.co/docs/reference/security/prebuilt-rules/rules/integrations/gcp/discovery_gcp_gke_endpoint_permission_enumeration
products:
  - Elastic Security
---

# 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.
**Rule type**: esql
**Rule indices**:
**Rule Severity**: medium
**Risk Score**: 47
**Runs every**: 5m
**Searches indices from**: `now-6m`
**Maximum alerts per execution**: 100
**References**:
- [[https://heilancoos.github.io/research/2025/12/16/kubernetes.html#unauthenticated-api-access](https://heilancoos.github.io/research/2025/12/16/kubernetes.html#unauthenticated-api-access)](https://heilancoos.github.io/research/2025/12/16/kubernetes.html#unauthenticated-api-access)

**Tags**:
- Domain: Cloud
- Domain: Kubernetes
- Data Source: GCP
- Data Source: Google Cloud Platform
- Use Case: Threat Detection
- Tactic: Discovery
- Resources: Investigation Guide
- Noise: High
- Performance: Fast
- Profile: Aggressive
- Rule Type: ES|QL
- Platform: GCP
- Domain: Containers
- Platform: Kubernetes

**Version**: 2
**Rule authors**:
- Elastic

**Rule license**: Elastic License v2
The GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule.

## Investigation guide


## 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`, and `Esql.event_outcome_values` for targeted APIs
  (secrets, RBAC, pods/exec) and which calls succeeded.
- Confirm whether `source.ip` and `Esql.user_agent_original_values` match 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.


## Rule Query

```esql
from logs-gcp.audit-* metadata _id, _index, _version
| where data_stream.dataset == "gcp.audit"
    and service.name == "k8s.io"
    and client.user.email is not null
    and source.ip is not null
    and to_string(source.ip) != "127.0.0.1"
    and to_string(source.ip) != "::1"
    and client.user.email != "system:anonymous"
    and client.user.email != "system:unauthenticated"
    and gcp.audit.resource_name != "readyz"
    and gcp.audit.resource_name != "livez"
    and gcp.audit.resource_name != "healthz"
    and gcp.audit.resource_name != "version"
| stats
    Esql.document_count = count(),
    Esql.event_outcome_count_distinct = count_distinct(event.outcome),
    Esql.event_action_count_distinct = count_distinct(event.action),
    Esql.gcp_audit_resource_name_count_distinct = count_distinct(gcp.audit.resource_name),
    Esql.earliest_timestamp = min(@timestamp),
    Esql.latest_timestamp = max(@timestamp),
    Esql.event_action_values = values(event.action),
    Esql.event_outcome_values = values(event.outcome),
    Esql.gcp_audit_resource_name_values = values(gcp.audit.resource_name),
    Esql.user_agent_original_values = values(user_agent.original)
  by client.user.email, source.ip
| where Esql.event_outcome_count_distinct == 2
    and Esql.event_action_count_distinct > 5
    and Esql.gcp_audit_resource_name_count_distinct > 3
    and Esql.document_count < 75
| keep Esql.*, client.user.email, source.ip
```

**Framework:** MITRE ATT&CK
- Tactic:
  - Name: Discovery
  - Id: TA0007
  - Reference URL: [[https://attack.mitre.org/tactics/TA0007/](https://attack.mitre.org/tactics/TA0007/)](https://attack.mitre.org/tactics/TA0007/)
- Technique:
  - Name: Container and Resource Discovery
  - Id: T1613
  - Reference URL: [[https://attack.mitre.org/techniques/T1613/](https://attack.mitre.org/techniques/T1613/)](https://attack.mitre.org/techniques/T1613/)