Detection rules › Elastic

Azure AKS Service Account Token Created via TokenRequest API

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

Detects an identity minting a service account token via the AKS (Azure Kubernetes Service) TokenRequest API (serviceaccounts/token), excluding known AKS control-plane and platform identities. Adversaries request service account tokens from a compromised identity to impersonate a workload, move laterally, or escalate privileges within the cluster. Coverage includes workload service accounts (system:serviceaccount:*), so a compromised in-cluster token minting a token for another service account is not excluded.

Known false positives

  • Controllers, CI/CD systems, and platform components legitimately request service account tokens. Baseline the requesting identities and exclude verified automation after review.

MITRE ATT&CK coverage

TacticTechniques
Credential Access

Telemetry coverage

Rules detecting the same action

These rules filter on the same operation.

Rule body

[metadata]
creation_date = "2026/07/23"
integration = ["azure"]
maturity = "production"
updated_date = "2026/07/23"

[rule]
author = ["Elastic"]
description = """
Detects an identity minting a service account token via the AKS (Azure Kubernetes Service) TokenRequest API
(serviceaccounts/token), excluding known AKS control-plane and platform identities. Adversaries request service account
tokens from a compromised identity to impersonate a workload, move laterally, or escalate privileges within the cluster.
Coverage includes workload service accounts (system:serviceaccount:*), so a compromised in-cluster token minting a token
for another service account is not excluded.
"""
false_positives = [
    """
    Controllers, CI/CD systems, and platform components legitimately request service account tokens. Baseline the
    requesting identities and exclude verified automation after review.
    """,
]
from = "now-9m"
index = ["logs-azure.platformlogs-*"]
language = "kuery"
license = "Elastic License v2"
name = "Azure AKS Service Account Token Created via TokenRequest API"
note = """## Triage and analysis

### Investigating Azure AKS Service Account Token Created via TokenRequest API

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`. The TokenRequest API
(`serviceaccounts/token`) mints a bound service account token. The kubelet (`system:node:*`) and the
kube-controller-manager (`aksService`) mint these tokens continuously for normal pod operation and are excluded; the
signal is a non-platform identity minting one. An attacker with rights over a service account can request a token to act
as that workload identity, reaching resources the compromised principal cannot.

### Possible investigation steps

- Identify the requesting identity in `azure.platformlogs.properties.log.user.username` (and its groups in
  `azure.platformlogs.properties.log.user.groups`) and whether it should mint tokens. A workload service account
  (`system:serviceaccount:<ns>:<sa>`) minting a token, or `masterclient` (the local cluster-admin cert), is the
  higher-concern case.
- Inspect `azure.platformlogs.properties.log.userAgent` to distinguish interactive/expected tooling (`kubectl create
  token`) from custom clients (for example `curl`), which is a stronger indicator of scripted abuse.
- Identify the target service account in `azure.platformlogs.properties.log.objectRef.name` /
  `azure.platformlogs.properties.log.objectRef.namespace` and what RBAC that account holds; minting a token for a
  higher-privileged service account is privilege escalation.
- Evaluate the source in `azure.platformlogs.properties.log.sourceIPs` and pivot on it for follow-on API calls made with
  the minted token, and correlate with recent RBAC changes, secret reads, or exec sessions from the same identity.

### False positive analysis

- Controllers, CI/CD systems, and platform components legitimately request service account tokens (for example the
  kube-controller-manager as `aksService`, which is excluded). Additional automation such as GitOps operators or CI
  running `kubectl create token` may surface; baseline those identities and exclude the specific validated account
  rather than re-broadening to all `system:*`, which would blind the rule to compromised workload service accounts.

### Response and remediation

- If unauthorized, revoke the minted token and the requesting identity's credentials, and review the RBAC that permitted
  token creation.
- Audit actions performed with the target service account's identity after the request.
- Collect kube-audit and identity artifacts per incident response procedures.
"""
references = [
    "https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-request-v1/",
    "https://microsoft.github.io/Threat-Matrix-for-Kubernetes/",
    "https://github.com/inguardians/peirates",
]
risk_score = 47
rule_id = "95db6791-8e88-47d0-81c9-531ff79c0e60"
setup = """
The Azure Fleet integration collecting AKS diagnostic logs forwarded through Event Hub into the `azure.platformlogs`
data stream is required for this rule. Enable either the `kube-audit` or the `kube-audit-admin` log category (Microsoft
recommends `kube-audit-admin` alone to reduce volume, as it only drops read-only get/list events). TokenRequest is a
mutating create recorded in both categories with the same `auditID`, so clusters that enable both categories may
generate two alerts per request.
"""
severity = "medium"
tags = [
    "Domain: Cloud",
    "Domain: Kubernetes",
    "Data Source: Azure",
    "Data Source: Azure Platform Logs",
    "Data Source: Kubernetes",
    "Use Case: Threat Detection",
    "Tactic: Credential Access",
    "Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "query"

query = '''
data_stream.dataset:azure.platformlogs and
    event.action:"Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" and
    azure.platformlogs.category:("kube-audit" or "kube-audit-admin") and
    azure.platformlogs.properties.log.stage:"ResponseComplete" and
    azure.platformlogs.properties.log.objectRef.resource:"serviceaccounts" and
    azure.platformlogs.properties.log.objectRef.subresource:"token" and
    azure.platformlogs.properties.log.verb:"create" and
    azure.platformlogs.properties.log.responseStatus.code:("200" or "201") 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.namespace",
    "azure.platformlogs.properties.log.objectRef.name",
    "azure.platformlogs.properties.log.objectRef.subresource",
    "azure.platformlogs.properties.log.requestURI",
    "azure.platformlogs.properties.log.responseStatus.code",
]

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

[[rule.threat.technique]]
id = "T1528"
name = "Steal Application Access Token"
reference = "https://attack.mitre.org/techniques/T1528/"

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

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" or "kube-audit-admin") and
    azure.platformlogs.properties.log.stage:"ResponseComplete" and
    azure.platformlogs.properties.log.objectRef.resource:"serviceaccounts" and
    azure.platformlogs.properties.log.objectRef.subresource:"token" and
    azure.platformlogs.properties.log.verb:"create" and
    azure.platformlogs.properties.log.responseStatus.code:("200" or "201") 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.