Techniques
Sample rules
Kubernetes Secret or ConfigMap Access via Azure Arc Proxy
- source: elastic
- technicques:
- T1530
- T1552
Description
Detects when secrets or configmaps are accessed, created, modified, or deleted in a Kubernetes cluster by the Azure Arc
AAD proxy service account. When operations are routed through the Azure Arc Cluster Connect proxy, the Kubernetes audit
log records the acting user as system:serviceaccount:azure-arc:azure-arc-kube-aad-proxy-sa with the actual caller
identity in the impersonatedUser field. This pattern indicates that someone is accessing the cluster through the Azure
ARM API rather than directly via kubectl against the API server. While legitimate for Arc-managed workflows, adversaries
with stolen service principal credentials can abuse Arc Cluster Connect to read, exfiltrate, or modify secrets and
configmaps while appearing as the Arc proxy service account in K8s audit logs.
Detection logic
FROM logs-kubernetes.audit_logs-* metadata _id, _version, _index
| WHERE STARTS_WITH(kubernetes.audit.user.username, "system:serviceaccount:azure-arc:")
AND kubernetes.audit.objectRef.resource IN ("secrets", "configmaps")
AND kubernetes.audit.verb IN ("get", "list", "create", "update", "patch", "delete")
AND kubernetes.audit.objectRef.namespace NOT IN ("azure-arc", "azure-arc-release", "kube-system")
AND NOT STARTS_WITH(kubernetes.audit.objectRef.name, "sh.helm.release.v1")
| STATS
Esql.verb_values = VALUES(kubernetes.audit.verb),
Esql.resource_type_values = VALUES(kubernetes.audit.objectRef.resource),
Esql.resource_name_values = VALUES(kubernetes.audit.objectRef.name),
Esql.namespace_values = VALUES(kubernetes.audit.objectRef.namespace),
Esql.acting_user_values = VALUES(kubernetes.audit.user.username),
Esql.user_agent_values = VALUES(kubernetes.audit.userAgent),
Esql.source_ips_values = VALUES(kubernetes.audit.sourceIPs),
Esql.response_code_values = VALUES(kubernetes.audit.responseStatus.code),
Esql.timestamp_first_seen = MIN(@timestamp),
Esql.timestamp_last_seen = MAX(@timestamp),
Esql.event_count = COUNT(*)
BY kubernetes.audit.impersonatedUser.username
| WHERE Esql.timestamp_first_seen >= NOW() - 9 minutes
| KEEP *