Azure AKS Multi-Resource Setup Discovery

Last updated 3 months ago on 2026-08-04
Created 3 months ago on 2026-08-04

About

Detects an AKS (Azure Kubernetes Service) identity that lists or gets multiple distinct Kubernetes API resource types associated with cluster orientation (namespaces, nodes, pods, roles, clusterroles, configmaps, serviceaccounts, rolebindings, clusterrolebindings) within a short window. Cardinality of distinct resources touched, not raw event count, is the signal that separates recon/orientation behavior from steady-state controllers that repeatedly touch a narrow set of resources. Known platform and control-plane identities are excluded.
Tags
Domain: CloudDomain: KubernetesData Source: AzureData Source: Azure Platform LogsData Source: KubernetesUse Case: Threat DetectionTactic: DiscoveryRule Type: ESQLPlatform: AzurePlatform: KubernetesLanguage: esql
Severity
medium
Risk Score
47
MITRE ATT&CK™

Discovery (TA0007)(external, opens in a new tab or window)

False Positive Examples
GitOps, backup, and platform operators may span these resource types during sync. Exclude validated service accounts or raise the cardinality threshold after baselining.
License
Elastic License v2(external, opens in a new tab or window)

Definition

Integration Pack
Prebuilt Security Detection Rules
Related Integrations

azure(external, opens in a new tab or window)

Query
text code block:
from logs-azure.platformlogs-* metadata _id, _index, _version | where data_stream.dataset == "azure.platformlogs" and event.action == "Microsoft.ContainerService/managedClusters/diagnosticLogs/Read" and azure.platformlogs.category == "kube-audit" | eval Esql.stage = field_extract(azure.platformlogs.properties, "log.stage"), Esql.verb = field_extract(azure.platformlogs.properties, "log.verb"), Esql.resource = field_extract(azure.platformlogs.properties, "log.objectRef.resource"), Esql.namespace = field_extract(azure.platformlogs.properties, "log.objectRef.namespace"), Esql.username = field_extract(azure.platformlogs.properties, "log.user.username"), Esql.user_agent = field_extract(azure.platformlogs.properties, "log.userAgent"), Esql.source_ips = field_extract(azure.platformlogs.properties, "log.sourceIPs") | where Esql.stage == "ResponseComplete" and Esql.verb in ("list", "get") and Esql.resource in ("namespaces", "nodes", "pods", "roles", "clusterroles", "configmaps", "serviceaccounts", "rolebindings", "clusterrolebindings") and Esql.username is not null and (Esql.namespace is null or Esql.namespace != "elastic-system") and not Esql.username rlike "system:node:.*|system:serviceaccount:kube-system:.*|system:serviceaccount:elastic-system:.*" and not Esql.username in ("aksService", "hcpService", "readinessChecker", "acsService", "system:apiserver", "system:kube-controller-manager", "system:kube-scheduler") and not Esql.user_agent rlike """(resourcesyncoperator|identityOperator|telegraf|clustermetadatasync|ConfigurationAgent|manager|extensionmanager)/.*\(linux/amd64\) kubernetes/\$Format|Helm/.*|.*Terraform.*|OpenAPI-Generator/.*""" | eval Esql.namespace = coalesce(Esql.namespace, "(cluster-scoped)") | stats Esql.unique_resources = count_distinct(Esql.resource), Esql.enumerated_resources = values(Esql.resource), Esql.enumerated_namespaces = values(Esql.namespace), Esql.source_ip_values = values(Esql.source_ips), Esql.username_values = values(Esql.username), Esql.event_count = count(*), Esql.earliest_timestamp = min(@timestamp), Esql.latest_timestamp = max(@timestamp) by Esql.username, Esql.user_agent, azure.resource.id | where Esql.unique_resources >= 3 | keep Esql.*, azure.resource.id

Install detection rules in Elastic Security

Detect Azure AKS Multi-Resource Setup Discovery in the Elastic Security detection engine by installing this rule into your Elastic Stack.

To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).