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.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/07/09"
  3integration = ["azure"]
  4maturity = "production"
  5updated_date = "2026/07/09"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Detects a single Kubernetes identity in AKS (Azure Kubernetes Service) that is denied (HTTP 403 Forbidden) across
 11multiple distinct API resource types within a short window. Broad authorization failures spanning many resources are a
 12strong signal of API enumeration (reconnaissance with a stolen service account token), as an actor
 13probes what its credentials can reach before privilege escalation. Detection is based on the breadth of denied resources
 14rather than the raw failure count, so single-resource controller retry loops do not trigger it.
 15"""
 16false_positives = [
 17    """
 18    A workload or observability agent with partial RBAC can be denied across several resource types and resemble
 19    enumeration (for example a monitoring agent that watches resources it lacks permission for). Baseline such
 20    identities and raise the cardinality threshold, or exclude the specific validated service account, after review.
 21    Single-resource retry loops (one resource denied repeatedly) do not trigger this rule because detection is based on
 22    the number of distinct resources denied, not the raw failure count.
 23    """,
 24]
 25from = "now-9m"
 26index = ["logs-azure.platformlogs-*"]
 27interval = "5m"
 28language = "kuery"
 29license = "Elastic License v2"
 30name = "Azure AKS Potential API Enumeration by User"
 31note = """## Triage and analysis
 32
 33### Investigating Azure AKS Potential API Enumeration by User
 34
 35AKS kube-audit events are carried under the flattened `azure.platformlogs.properties.log.*` subtree and share the ARM
 36operation `event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read`. This rule groups forbidden
 37(HTTP 403) Kubernetes API calls by `azure.platformlogs.properties.log.user.username` and alerts when one identity is
 38denied across several distinct `objectRef.resource` types within the interval. Breadth of denied resources (rather than
 39raw failure volume) is the signal: an identity probing many resource types it cannot reach is characteristic of API
 40enumeration with a stolen service account token, whereas a controller stuck retrying one forbidden resource stays on a
 41single resource and does not trigger.
 42
 43### Possible investigation steps
 44
 45- Enumerate the distinct `azure.platformlogs.properties.log.objectRef.resource` and
 46  `azure.platformlogs.properties.log.verb` values denied for the identity, and read the human-readable denial in
 47  `azure.platformlogs.properties.log.responseStatus.message` (for example "secrets is forbidden: User ... cannot list
 48  resource"), to see what the actor was mapping out.
 49- Identify the acting identity in `azure.platformlogs.properties.log.user.username` and its groups in
 50  `azure.platformlogs.properties.log.user.groups`. Service account tokens (`system:serviceaccount:<ns>:<sa>`) probing
 51  broadly are the primary concern; confirm whether that identity should be issuing these calls at all.
 52- Inspect `azure.platformlogs.properties.log.userAgent` to distinguish interactive tooling (`kubectl`) or a known
 53  controller from custom recon tooling (for example `kubectl-recon`, `curl`, or other enumeration clients).
 54- Validate the source in `azure.platformlogs.properties.log.sourceIPs`. In-cluster agents use loopback
 55  (`127.0.0.1`/`::1`) or pod-network addresses (e.g. `10.244.0.0/16`); an external caller wielding a service account
 56  token is more suspicious.
 57- Hunt for later successful calls (`responseStatus.code:2xx`) from the same identity or source that indicate the actor
 58  found a permitted action or escalated, and correlate with recent Entra ID sign-ins or role assignments.
 59
 60### False positive analysis
 61
 62- A workload or observability agent with partial RBAC can be denied across several resource types and resemble
 63  enumeration. Baseline such identities, raise the cardinality threshold, or exclude the specific validated service
 64  account after review.
 65- Single-resource retry loops (one resource denied repeatedly, such as a controller watching a resource it lacks
 66  permission for) do not trigger this rule, since detection is based on the count of distinct resources denied.
 67
 68### Response and remediation
 69
 70- If unauthorized, revoke the identity's tokens and kubeconfig and review the RBAC bindings assigned to it.
 71- Determine whether any request from the identity succeeded and scope the impact accordingly.
 72- Collect kube-audit and identity artifacts per incident response procedures.
 73"""
 74references = [
 75    "https://learn.microsoft.com/en-us/azure/aks/monitor-aks",
 76    "https://microsoft.github.io/Threat-Matrix-for-Kubernetes/",
 77    "https://github.com/inguardians/peirates",
 78]
 79risk_score = 47
 80rule_id = "13a3cc0e-1f69-4cc9-8f2f-892d7c7032dc"
 81setup = """
 82The Azure Fleet integration collecting AKS diagnostic logs forwarded through Event Hub into the `azure.platformlogs`
 83data stream is required for this rule. The `kube-audit` log category is required specifically: authorization denials
 84during enumeration are predominantly get/list/watch (read) operations, which the `kube-audit-admin` category excludes.
 85A cluster that ships only `kube-audit-admin` is effectively blind to this rule, since only write-verb denials remain
 86visible.
 87"""
 88severity = "medium"
 89tags = [
 90    "Domain: Cloud",
 91    "Domain: Kubernetes",
 92    "Data Source: Azure",
 93    "Data Source: Azure Platform Logs",
 94    "Data Source: Kubernetes",
 95    "Use Case: Threat Detection",
 96    "Tactic: Discovery",
 97    "Resources: Investigation Guide",
 98]
 99timestamp_override = "event.ingested"
100type = "threshold"
101
102query = '''
103data_stream.dataset:azure.platformlogs and
104  event.action:"Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" and
105  azure.platformlogs.category:"kube-audit" and
106  azure.platformlogs.properties.log.stage:"ResponseComplete" and
107  azure.platformlogs.properties.log.responseStatus.code:"403" and
108  azure.platformlogs.properties.log.responseStatus.reason:"Forbidden" and
109  not azure.platformlogs.properties.log.user.username:(
110    system\:node\:* or "aksService" or "hcpService" or "readinessChecker" or
111    system\:serviceaccount\:kube-system\:*
112  )
113'''
114
115[rule.investigation_fields]
116field_names = [
117    "@timestamp",
118    "event.action",
119    "azure.platformlogs.category",
120    "azure.platformlogs.properties.log.verb",
121    "azure.platformlogs.properties.log.user.username",
122    "azure.platformlogs.properties.log.user.groups",
123    "azure.platformlogs.properties.log.userAgent",
124    "azure.platformlogs.properties.log.sourceIPs",
125    "azure.platformlogs.properties.log.objectRef.resource",
126    "azure.platformlogs.properties.log.objectRef.namespace",
127    "azure.platformlogs.properties.log.requestURI",
128    "azure.platformlogs.properties.log.responseStatus.code",
129    "azure.platformlogs.properties.log.responseStatus.reason",
130    "azure.platformlogs.properties.log.responseStatus.message",
131]
132
133[rule.threshold]
134field = [
135  "azure.resource.id",
136  "azure.platformlogs.properties.log.user.username"
137]
138value = 1
139
140[[rule.threshold.cardinality]]
141field = "azure.platformlogs.properties.log.objectRef.resource"
142value = 4
143
144[[rule.threat]]
145framework = "MITRE ATT&CK"
146
147[[rule.threat.technique]]
148id = "T1613"
149name = "Container and Resource Discovery"
150reference = "https://attack.mitre.org/techniques/T1613/"
151
152[rule.threat.tactic]
153id = "TA0007"
154name = "Discovery"
155reference = "https://attack.mitre.org/tactics/TA0007/"

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

Related rules

to-top