← Back to Explore
elasticmediumTTP
GKE Secret Access from Node or Denied Service Account
Detects GKE Secrets API activity that should not occur in normal cluster operation: a node identity (system:node:*) performing secrets get or list, or a pod service account failing a secrets get. Kubelet and node credentials are not expected to call the Secrets API for enumeration or direct reads, and a denied service-account secret get could indicate stolen-token probing or over-privileged tooling reaching beyond its RBAC.
Detection Query
data_stream.dataset:gcp.audit and service.name:k8s.io and
source.ip:(* and not (127.0.0.1 or "::1")) and
(
(
client.user.email:system\:node\:* and
event.action:(io.k8s.core.v1.secrets.get or io.k8s.core.v1.secrets.list)
) or (
client.user.email:system\:serviceaccount\:* and
event.action:io.k8s.core.v1.secrets.get and
event.outcome:failure
)
)
Author
Elastic
Created
2026/07/17
Data Sources
GCPGoogle Cloud Platformlogs-gcp.audit-*
References
Tags
Domain: CloudDomain: KubernetesData Source: GCPData Source: Google Cloud PlatformUse Case: Threat DetectionTactic: Credential AccessResources: Investigation Guide
Raw Content
[metadata]
creation_date = "2026/07/17"
integration = ["gcp"]
maturity = "production"
updated_date = "2026/07/17"
[rule]
author = ["Elastic"]
description = """
Detects GKE Secrets API activity that should not occur in normal cluster operation: a node identity
(system:node:*) performing secrets get or list, or a pod service account failing a secrets get.
Kubelet and node credentials are not expected to call the Secrets API for enumeration or direct reads,
and a denied service-account secret get could indicate stolen-token probing or over-privileged tooling
reaching beyond its RBAC.
"""
false_positives = [
"""
Rare node maintenance or diagnostic tooling may touch the Secrets API; validate against change windows
and approved node management paths.
""",
"""
Misconfigured workloads can generate repeated denied secret gets during startup; confirm RBAC intent
before treating as compromise.
""",
]
from = "now-6m"
index = ["logs-gcp.audit-*"]
language = "kuery"
license = "Elastic License v2"
name = "GKE Secret Access from Node or Denied Service Account"
note = """## Triage and analysis
### Investigating GKE Secret Access from Node or Denied Service Account
This rule fires on two high-confidence patterns in GKE audit logs:
- `system:node:*` successfully or unsuccessfully calling `secrets.get` or `secrets.list`
- `system:serviceaccount:*` receiving `event.outcome:failure` on `secrets.get`
Treat node-originated Secrets API calls as priority. For denied service-account gets, determine whether
the identity is probing secrets outside its Role/ClusterRole or using an unexpected client from a
compromised token.
### Possible investigation steps
- Resolve `client.user.email` to the node or workload and review RBAC bindings for secret `get`/`list` scope.
- Inspect `gcp.audit.resource_name`, `source.ip`, and `user_agent.original` for anomalous clients or
cross-namespace targets.
- Correlate with successful secret reads, pod exec, token creation, or RoleBinding changes in the same window.
- For node events, confirm whether kubelet, CSI, or maintenance tooling on that node should ever call the
Secrets API.
### False positive analysis
- Node diagnostics or custom CSI helpers may rarely issue Secrets API calls; allowlist only after confirming
the path is approved.
- Broken RBAC on a newly deployed workload can produce repeated denied gets until permissions are fixed.
### Response and remediation
- If malicious, revoke the node or service-account credentials, isolate the host or workload, rotate exposed
secrets, and tighten RBAC to least privilege for the affected identity.
"""
setup = "The GCP Fleet integration with GKE audit logs enabled is required to be compatible with this rule."
references = [
"https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens",
]
risk_score = 47
rule_id = "bedab6b4-f195-45d1-8f97-7d300eb79671"
severity = "medium"
tags = [
"Domain: Cloud",
"Domain: Kubernetes",
"Data Source: GCP",
"Data Source: Google Cloud Platform",
"Use Case: Threat Detection",
"Tactic: Credential Access",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
data_stream.dataset:gcp.audit and service.name:k8s.io and
source.ip:(* and not (127.0.0.1 or "::1")) and
(
(
client.user.email:system\:node\:* and
event.action:(io.k8s.core.v1.secrets.get or io.k8s.core.v1.secrets.list)
) or (
client.user.email:system\:serviceaccount\:* and
event.action:io.k8s.core.v1.secrets.get and
event.outcome:failure
)
)
'''
[[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.007"
name = "Container API"
reference = "https://attack.mitre.org/techniques/T1552/007/"
[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"
[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",
]