Detection rules › Elastic

GKE API Server Proxying Request to Kubelet

Status
production
Severity
medium
Time window
6m
Author
Elastic
Source
github.com/elastic/detection-rules

Detects non-system identities using the GKE nodes/proxy API to reach a node's Kubelet through the API server. The nodes/proxy subresource allows any principal with this permission to call the Kubelet API without direct node network access or Kubelet TLS certificates. Through this path an attacker can list pod specs (including environment secrets), read Kubelet configuration, retrieve container logs, and access running pod metadata on the target node. Monitoring endpoints such as metrics, healthz, and stats/summary are excluded to reduce noise from observability tooling.

Known false positives

  • Legitimate kubelet debugging, node troubleshooting, or security tooling that uses the node proxy outside the excluded metrics paths may match. Baseline approved operators and automation identities after review.

MITRE ATT&CK coverage

Telemetry coverage

Rules detecting the same action

These rules filter on the same operation.

Rule body

[metadata]
creation_date = "2026/07/13"
integration = ["gcp"]
maturity = "production"
updated_date = "2026/07/13"

[rule]
author = ["Elastic"]
description = """
Detects non-system identities using the GKE nodes/proxy API to reach a node's Kubelet through the API server. The
nodes/proxy subresource allows any principal with this permission to call the Kubelet API without direct node network
access or Kubelet TLS certificates. Through this path an attacker can list pod specs (including environment secrets),
read Kubelet configuration, retrieve container logs, and access running pod metadata on the target node. Monitoring
endpoints such as metrics, healthz, and stats/summary are excluded to reduce noise from observability tooling.
"""
false_positives = [
    """
    Legitimate kubelet debugging, node troubleshooting, or security tooling that uses the node proxy outside the
    excluded metrics paths may match. Baseline approved operators and automation identities after review.
    """,
]
from = "now-6m"
index = ["logs-gcp.audit-*"]
language = "kuery"
license = "Elastic License v2"
name = "GKE API Server Proxying Request to Kubelet"
note = """## Triage and analysis

### Investigating GKE API Server Proxying Request to Kubelet

Review `client.user.email`, `source.ip`, and `user_agent.original` to determine who initiated the proxy request.
Examine `gcp.audit.resource_name` and `event.action` to identify which Kubelet path was accessed after `/proxy/`.

### Possible investigation steps

- Check the proxied Kubelet path for attacker intent:
  - `/proxy/pods` — pod spec enumeration, including environment variable secrets
  - `/proxy/exec` or `/proxy/run` — command execution inside containers on that node
  - `/proxy/configz` — Kubelet configuration and authentication settings
  - `/proxy/runningpods` — active workload enumeration
  - `/proxy/containerLogs` — log harvesting for leaked credentials
- Identify how the principal obtained `nodes/proxy` permission by reviewing RBAC bindings.
- Correlate with TokenRequest activity from the same actor shortly before the proxy call.
- Review whether the same principal proxied multiple nodes in a short window.

### False positive analysis

- Monitoring agents that scrape paths other than the excluded metrics/health endpoints may match. Add approved paths
  or identities after baselining.
- Cluster admin tools that inspect node health via the proxy API can match during maintenance windows.

### Response and remediation

- Review and remove unauthorized RBAC granting `nodes/proxy`.
- If `/proxy/pods` was accessed, rotate secrets and credentials that may have been exposed via environment variables
  on that node.
- If `/proxy/exec` or `/proxy/run` was accessed, treat the node as compromised and isolate it.
- Restrict `nodes/proxy` to infrastructure automation only.

"""
setup = """
The GCP Fleet integration with GKE audit logs enabled is required.
"""
references = [
    "https://kubernetes.io/docs/concepts/cluster-administration/proxies/",
    "https://stratus-red-team.cloud/attack-techniques/kubernetes/k8s.privilege-escalation.nodes-proxy/",
]
risk_score = 47
rule_id = "a4fa2bf0-1cf9-4803-bed0-1f9c6e57af3c"
severity = "medium"
tags = [
    "Domain: Cloud",
    "Domain: Kubernetes",
    "Data Source: GCP",
    "Data Source: Google Cloud Platform",
    "Use Case: Threat Detection",
    "Tactic: Privilege Escalation",
    "Tactic: Lateral Movement",
    "Tactic: Discovery",
    "Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"

query = '''
data_stream.dataset:gcp.audit and service.name:"k8s.io" and event.outcome:success and
event.action:(
  "io.k8s.core.v1.nodes.proxy.get" or
  "io.k8s.core.v1.nodes.proxy.create"
) and
not gcp.audit.resource_name:(*metrics* or *healthz* or *stats/summary* or *elastic-agent* or *configz*) and
not client.user.email:(
  "system:kube-controller-manager" or
  "system:kube-scheduler" or
  system\:serviceaccount\:kube-system\:* or
  system\:node\:*
)
'''

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1611"
name = "Escape to Host"
reference = "https://attack.mitre.org/techniques/T1611/"

[rule.threat.tactic]
id = "TA0004"
name = "Privilege Escalation"
reference = "https://attack.mitre.org/tactics/TA0004/"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1550"
name = "Use Alternate Authentication Material"
reference = "https://attack.mitre.org/techniques/T1550/"

[[rule.threat.technique.subtechnique]]
id = "T1550.001"
name = "Application Access Token"
reference = "https://attack.mitre.org/techniques/T1550/001/"

[rule.threat.tactic]
id = "TA0008"
name = "Lateral Movement"
reference = "https://attack.mitre.org/tactics/TA0008/"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1613"
name = "Container and Resource Discovery"
reference = "https://attack.mitre.org/techniques/T1613/"

[rule.threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"

[rule.investigation_fields]
field_names = [
    "@timestamp",
    "client.user.email",
    "source.ip",
    "user_agent.original",
    "event.action",
    "event.outcome",
    "gcp.audit.resource_name",
    "data_stream.namespace",
]

Stages and Predicates

Stage 1: query

data_stream.dataset:gcp.audit and service.name:"k8s.io" and event.outcome:success and
event.action:(
  "io.k8s.core.v1.nodes.proxy.get" or
  "io.k8s.core.v1.nodes.proxy.create"
) and
not gcp.audit.resource_name:(*metrics* or *healthz* or *stats/summary* or *elastic-agent* or *configz*) and
not client.user.email:(
  "system:kube-controller-manager" or
  "system:kube-scheduler" or
  system\:serviceaccount\:kube-system\:* or
  system\:node\:*
)

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.