[New] Kubernetes Rapid Secret GET Activity Against Multiple Objects (#5967)

* [New] Kubernetes Rapid Secret GET Activity Against Multiple Objects

Detects multiple k8 get secret calls for unique secret names in a short period of time (rule interval default to every 5m):

* Update credential_access_kubernetes_multiple_secret_retrieval_burst.toml

* Update credential_access_kubernetes_multiple_secret_retrieval_burst.toml

* Update credential_access_kubernetes_multiple_secret_retrieval_burst.toml

* Update credential_access_kubernetes_multiple_secret_retrieval_burst.toml
This commit is contained in:
Samirbous
2026-05-02 10:43:13 +01:00
committed by GitHub
parent a892cd1b6d
commit 0a4a05f322
@@ -0,0 +1,94 @@
[metadata]
creation_date = "2026/04/22"
integration = ["kubernetes"]
maturity = "production"
updated_date = "2026/04/22"
[rule]
author = ["Elastic"]
description = """
This rule detects an unusual volume of Kubernetes API get requests against multiple distinct Secret objects from the same client
fingerprint (user, source IP, and user agent) within a defined lookback window. This can indicate credential access or in-cluster
reconnaissance, where a user or token is used to enumerate and retrieve sensitive data such as service account tokens, registry
credentials, TLS material, or application configuration. Failed get requests are also included, as they may reveal RBAC boundaries,
confirm the existence of targeted secrets, or reflect automated probing activity.
"""
from = "now-6m"
language = "esql"
license = "Elastic License v2"
name = "Kubernetes Rapid Secret GET Activity Against Multiple Objects"
note = """## Triage and analysis
### Investigating Kubernetes Rapid Secret GET Activity Against Multiple Objects
This rule surfaces clusters of `get` operations on the `secrets` API where the same identity and client path
(`user.name`, `source.ip`, `user_agent.original`) touch several different secret names within the rule lookback window.
**Allowed and denied** outcomes are included: successful reads may indicate harvesting; repeated **forbidden** or
**unauthorized** responses can still signal reconnaissance, RBAC probing, or scripted spray against secret names that
exist in the cluster.
### Investigation steps
- Inspect `Esql.outcome` for a mix of allow vs deny and whether failures cluster on sensitive namespaces.
- Map the identity to RBAC and namespace scope; review `Esql.secrets_names` and `Esql.namespaces` for high-value
targets (tokens, registry credentials, TLS bundles, application secrets).
- Pivot on the same `source.ip` and user for follow-on API activity (exec, pod create, role changes, broad `list` on secrets).
- Validate against expected automation (CI, GitOps, backup, in-cluster controllers) before treating as malicious.
### False positives
- Startup, Helm, or controllers may legitimately touch many secrets in one window; tune by user, namespace, or IP
allowlists when baselined.
"""
references = [
"https://attack.mitre.org/techniques/T1552/007/",
]
risk_score = 73
rule_id = "b4c8e2a1-9f3d-4e7c-a2b1-0d5e6f7a8b9c"
severity = "high"
tags = [
"Data Source: Kubernetes",
"Domain: Kubernetes",
"Use Case: Threat Detection",
"Tactic: Credential Access",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "esql"
query = '''
from logs-kubernetes.audit_logs-* metadata _id, _index, _version
| where event.dataset == "kubernetes.audit_logs"
and event.action == "get"
and kubernetes.audit.objectRef.resource == "secrets"
and source.ip is not null and user.name is not null
and not to_string(source.ip) in ("127.0.0.1", "::1") and
not user.name in ("system:kube-controller-manager", "system:kube-scheduler") and
not kubernetes.audit.objectRef.name like "sh.helm.release.*"
| stats
Esql.unique_credentials = count_distinct(kubernetes.audit.objectRef.name),
Esql.secrets_names = values(kubernetes.audit.objectRef.name),
Esql.namespaces = values(kubernetes.audit.objectRef.namespace),
Esql.outcome = values(`kubernetes.audit.annotations.authorization_k8s_io/decision`)
by user.name, source.ip, user_agent.original
| where Esql.unique_credentials >= 3
| KEEP user.name, source.ip, user_agent.original, Esql.*
'''
[[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/"