Detection rules › Elastic
Azure AKS Potential API Enumeration by User
Detects a single Kubernetes identity in AKS (Azure Kubernetes Service) that is denied (HTTP 403 Forbidden) across multiple distinct API resource types within a short window. Broad authorization failures spanning many resources are a strong signal of API enumeration (reconnaissance with a stolen service account token), as an actor probes what its credentials can reach before privilege escalation. Detection is based on the breadth of denied resources rather than the raw failure count, so single-resource controller retry loops do not trigger it.
Known false positives
- A workload or observability agent with partial RBAC can be denied across several resource types and resemble enumeration (for example a monitoring agent that watches resources it lacks permission for). Baseline such identities and raise the cardinality threshold, or exclude the specific validated service account, after review. Single-resource retry loops (one resource denied repeatedly) do not trigger this rule because detection is based on the number of distinct resources denied, not the raw failure count.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Discovery |
Rule body
[metadata]
creation_date = "2026/07/09"
integration = ["azure"]
maturity = "production"
updated_date = "2026/07/09"
[rule]
author = ["Elastic"]
description = """
Detects a single Kubernetes identity in AKS (Azure Kubernetes Service) that is denied (HTTP 403 Forbidden) across
multiple distinct API resource types within a short window. Broad authorization failures spanning many resources are a
strong signal of API enumeration (reconnaissance with a stolen service account token), as an actor
probes what its credentials can reach before privilege escalation. Detection is based on the breadth of denied resources
rather than the raw failure count, so single-resource controller retry loops do not trigger it.
"""
false_positives = [
"""
A workload or observability agent with partial RBAC can be denied across several resource types and resemble
enumeration (for example a monitoring agent that watches resources it lacks permission for). Baseline such
identities and raise the cardinality threshold, or exclude the specific validated service account, after review.
Single-resource retry loops (one resource denied repeatedly) do not trigger this rule because detection is based on
the number of distinct resources denied, not the raw failure count.
""",
]
from = "now-9m"
index = ["logs-azure.platformlogs-*"]
interval = "5m"
language = "kuery"
license = "Elastic License v2"
name = "Azure AKS Potential API Enumeration by User"
note = """## Triage and analysis
### Investigating Azure AKS Potential API Enumeration by User
AKS kube-audit events are carried under the flattened `azure.platformlogs.properties.log.*` subtree and share the ARM
operation `event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read`. This rule groups forbidden
(HTTP 403) Kubernetes API calls by `azure.platformlogs.properties.log.user.username` and alerts when one identity is
denied across several distinct `objectRef.resource` types within the interval. Breadth of denied resources (rather than
raw failure volume) is the signal: an identity probing many resource types it cannot reach is characteristic of API
enumeration with a stolen service account token, whereas a controller stuck retrying one forbidden resource stays on a
single resource and does not trigger.
### Possible investigation steps
- Enumerate the distinct `azure.platformlogs.properties.log.objectRef.resource` and
`azure.platformlogs.properties.log.verb` values denied for the identity, and read the human-readable denial in
`azure.platformlogs.properties.log.responseStatus.message` (for example "secrets is forbidden: User ... cannot list
resource"), to see what the actor was mapping out.
- Identify the acting identity in `azure.platformlogs.properties.log.user.username` and its groups in
`azure.platformlogs.properties.log.user.groups`. Service account tokens (`system:serviceaccount:<ns>:<sa>`) probing
broadly are the primary concern; confirm whether that identity should be issuing these calls at all.
- Inspect `azure.platformlogs.properties.log.userAgent` to distinguish interactive tooling (`kubectl`) or a known
controller from custom recon tooling (for example `kubectl-recon`, `curl`, or other enumeration clients).
- Validate the source in `azure.platformlogs.properties.log.sourceIPs`. In-cluster agents use loopback
(`127.0.0.1`/`::1`) or pod-network addresses (e.g. `10.244.0.0/16`); an external caller wielding a service account
token is more suspicious.
- Hunt for later successful calls (`responseStatus.code:2xx`) from the same identity or source that indicate the actor
found a permitted action or escalated, and correlate with recent Entra ID sign-ins or role assignments.
### False positive analysis
- A workload or observability agent with partial RBAC can be denied across several resource types and resemble
enumeration. Baseline such identities, raise the cardinality threshold, or exclude the specific validated service
account after review.
- Single-resource retry loops (one resource denied repeatedly, such as a controller watching a resource it lacks
permission for) do not trigger this rule, since detection is based on the count of distinct resources denied.
### Response and remediation
- If unauthorized, revoke the identity's tokens and kubeconfig and review the RBAC bindings assigned to it.
- Determine whether any request from the identity succeeded and scope the impact accordingly.
- Collect kube-audit and identity artifacts per incident response procedures.
"""
references = [
"https://learn.microsoft.com/en-us/azure/aks/monitor-aks",
"https://microsoft.github.io/Threat-Matrix-for-Kubernetes/",
"https://github.com/inguardians/peirates",
]
risk_score = 47
rule_id = "13a3cc0e-1f69-4cc9-8f2f-892d7c7032dc"
setup = """
The Azure Fleet integration collecting AKS diagnostic logs forwarded through Event Hub into the `azure.platformlogs`
data stream is required for this rule. The `kube-audit` log category is required specifically: authorization denials
during enumeration are predominantly get/list/watch (read) operations, which the `kube-audit-admin` category excludes.
A cluster that ships only `kube-audit-admin` is effectively blind to this rule, since only write-verb denials remain
visible.
"""
severity = "medium"
tags = [
"Domain: Cloud",
"Domain: Kubernetes",
"Data Source: Azure",
"Data Source: Azure Platform Logs",
"Data Source: Kubernetes",
"Use Case: Threat Detection",
"Tactic: Discovery",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "threshold"
query = '''
data_stream.dataset:azure.platformlogs and
event.action:"Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" and
azure.platformlogs.category:"kube-audit" and
azure.platformlogs.properties.log.stage:"ResponseComplete" and
azure.platformlogs.properties.log.responseStatus.code:"403" and
azure.platformlogs.properties.log.responseStatus.reason:"Forbidden" and
not azure.platformlogs.properties.log.user.username:(
system\:node\:* or "aksService" or "hcpService" or "readinessChecker" or
system\:serviceaccount\:kube-system\:*
)
'''
[rule.investigation_fields]
field_names = [
"@timestamp",
"event.action",
"azure.platformlogs.category",
"azure.platformlogs.properties.log.verb",
"azure.platformlogs.properties.log.user.username",
"azure.platformlogs.properties.log.user.groups",
"azure.platformlogs.properties.log.userAgent",
"azure.platformlogs.properties.log.sourceIPs",
"azure.platformlogs.properties.log.objectRef.resource",
"azure.platformlogs.properties.log.objectRef.namespace",
"azure.platformlogs.properties.log.requestURI",
"azure.platformlogs.properties.log.responseStatus.code",
"azure.platformlogs.properties.log.responseStatus.reason",
"azure.platformlogs.properties.log.responseStatus.message",
]
[rule.threshold]
field = [
"azure.resource.id",
"azure.platformlogs.properties.log.user.username"
]
value = 1
[[rule.threshold.cardinality]]
field = "azure.platformlogs.properties.log.objectRef.resource"
value = 4
[[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/"
Stages and Predicates
Stage 1: query
data_stream.dataset:azure.platformlogs and
event.action:"Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" and
azure.platformlogs.category:"kube-audit" and
azure.platformlogs.properties.log.stage:"ResponseComplete" and
azure.platformlogs.properties.log.responseStatus.code:"403" and
azure.platformlogs.properties.log.responseStatus.reason:"Forbidden" and
not azure.platformlogs.properties.log.user.username:(
system\:node\:* or "aksService" or "hcpService" or "readinessChecker" or
system\:serviceaccount\:kube-system\:*
)
Exclusions
The rule actively suppresses these predicates.
Indicators
These rows show field, operator, and value matches.