Detection rules › Elastic

GKE Pod Exec Cloud Instance Metadata Access

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

Detects successful GKE pod exec sessions whose command references Google Cloud instance metadata endpoints, including metadata.google.internal, computeMetadata/v1, or the link-local metadata IP 169.254.169.254. Workloads that reach the GKE metadata service from an exec session are often attempting to harvest short-lived credentials or instance attributes from the node or workload identity boundary. That behavior is high risk because it can expose cloud credentials to code running inside a container. GKE records the command in gcp.audit.labels.command.gke.io/command when an explicit command is passed to exec.

Known false positives

  • Break-glass debugging from platform engineers may include curl to the metadata IP or hostname.

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/15"
integration = ["gcp"]
maturity = "production"
updated_date = "2026/07/15"

[rule]
author = ["Elastic"]
description = """
Detects successful GKE pod exec sessions whose command references Google Cloud instance metadata endpoints, including
metadata.google.internal, computeMetadata/v1, or the link-local metadata IP 169.254.169.254. Workloads that reach the
GKE metadata service from an exec session are often attempting to harvest short-lived credentials or instance attributes
from the node or workload identity boundary. That behavior is high risk because it can expose cloud credentials to code
running inside a container. GKE records the command in gcp.audit.labels.command.gke.io/command when an explicit command
is passed to exec.
"""
false_positives = [
    """
    Break-glass debugging from platform engineers may include curl to the metadata IP or hostname.
    """,
]
from = "now-6m"
index = ["logs-gcp.audit-*"]
language = "kuery"
license = "Elastic License v2"
name = "GKE Pod Exec Cloud Instance Metadata Access"
note = """## Triage and analysis

### Investigating GKE Pod Exec Cloud Instance Metadata Access

This alert fires when a successful pods/exec API call includes a command targeting GKE/GCP instance metadata.
Review `gcp.audit.labels.command.gke.io/command` for the full command string.

### Possible investigation steps

- Confirm the actor (`client.user.email`), source IP, and user agent that performed exec.
- Map `gcp.audit.resource_name` to the target pod/namespace and determine whether the workload should ever call metadata.
- Correlate with GCP audit logs for token issuance or IAM activity around the same time from the node or workload identity.
- Hunt adjacent activity from the same identity: secret reads, additional execs, or RBAC changes.

### False positive analysis

- Approved platform tooling or bootstrap scripts may query metadata during startup; baseline those images and identities.
- Break-glass egress/metadata connectivity tests can match; document and allowlist those principals.

### Response and remediation

- If unauthorized, terminate the session, isolate the workload, revoke or rotate instance and workload credentials that
  could have been read, and tighten pods/exec RBAC plus network policies that deny link-local metadata from pods.
"""
setup = "The GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule."
references = [
    "https://cloud.google.com/kubernetes-engine/docs/concepts/protecting-cluster-metadata",
]
risk_score = 73
rule_id = "c8bf56cc-c648-4f88-bb4f-9e504d0779d1"
severity = "high"
tags = [
    "Domain: Cloud",
    "Domain: Kubernetes",
    "Data Source: GCP",
    "Data Source: GCP Audit Logs",
    "Data Source: Google Cloud Platform",
    "Use Case: Threat Detection",
    "Tactic: Credential Access",
    "Tactic: Execution",
    "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.type:start and
event.action:("io.k8s.core.v1.pods.exec.create" or "io.k8s.core.v1.pods.exec.get") and
gcp.audit.labels.command.gke.io/command:(
  *169.254.169.254* or *metadata.google.internal* or *computeMetadata/v1*
)
'''

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

[[rule.threat.technique]]
id = "T1552"
name = "Unsecured Credentials"
reference = "https://attack.mitre.org/techniques/T1552/"

[[rule.threat.technique.subtechnique]]
id = "T1552.005"
name = "Cloud Instance Metadata API"
reference = "https://attack.mitre.org/techniques/T1552/005/"

[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"

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

[[rule.threat.technique]]
id = "T1609"
name = "Container Administration Command"
reference = "https://attack.mitre.org/techniques/T1609/"

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

[rule.investigation_fields]
field_names = [
    "@timestamp",
    "client.user.email",
    "source.ip",
    "user_agent.original",
    "event.action",
    "event.outcome",
    "event.type",
    "gcp.audit.labels.command.gke.io/command",
    "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.type:start and
event.action:("io.k8s.core.v1.pods.exec.create" or "io.k8s.core.v1.pods.exec.get") and
gcp.audit.labels.command.gke.io/command:(
  *169.254.169.254* or *metadata.google.internal* or *computeMetadata/v1*
)

Indicators

These rows show field, operator, and value matches.