Nodes
| Operation | Description | Sample | Rule |
|---|---|---|---|
| get-nodes | Reads a single Node object: a worker's capacity, labels, taints, and addresses. Elastic's new-terms rule flags a not-previously-seen identity reading node inventory. | Y | Y |
| list-nodes | Lists all Nodes, mapping the cluster's infrastructure (IPs, capacity, labels) in one call, a classic reconnaissance step before targeting a specific node. | Y | Y |
| watch-nodes | Opens a long-lived watch on Node changes cluster-wide. Elastic's new-terms user-agent rule flags a not-previously-seen identity doing this. | Y | Y |
| create-nodes | N | Y | |
| update-nodes | Y | Y | |
| patch-nodes | Modifies a Node's labels or taints, which can affect pod scheduling (e.g. clearing a taint to land a pod on a hardened node) or spoof node metadata. | Y | Y |
| delete-nodes | N | N | |
| deletecollection-nodes | N | N | |
| get-nodes-proxy | Proxy request to node API endpoint (privilege escalation: node-proxy allows kubelet API access). | N | Y |
| create-nodes-proxy | N | Y | |
| update-nodes-proxy | N | Y | |
| patch-nodes-proxy | N | Y | |
| delete-nodes-proxy | N | Y | |
| get-nodes-status | Y | N | |
| update-nodes-status | Y | N | |
| patch-nodes-status | Y | N |
get nodes
#Description
Reads a single Node object: a worker's capacity, labels, taints, and addresses. Elastic's new-terms rule flags a not-previously-seen identity reading node inventory.
Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 1 detection rule | Elastic |
stage | 1 detection rule | Elastic |
verb | 1 detection rule | Elastic |
Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes/node-control-plane",
"verb": "get",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=9bb0383c49b319fbf6b5ed61ab944378956d4292c784d32244ce2fa4dd846a3c"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"name": "node-control-plane",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2026-07-02T04:49:00.942261Z",
"stageTimestamp": "2026-07-02T04:49:00.944470Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. This rule detects interactive commands executed inside containers that use atypical utilities to hit the Kubernetes API, paired with near-simultaneous API activity on pods, secrets, service accounts, roles/bindings, or pod exec/attach/log/portforward. It surfaces hands-on-keyboard discovery and lateral movement using custom scripts that evade common tool allowlists; for example, an intruder opens a shell in a pod, uses Python to query the in-cluster API to list secrets, then triggers pods/exec to pivot into another workload. The rule groups GKE audit get/list events on namespaces, nodes, pods, configmaps, serviceaccounts, roles, rolebindings, clusterroles, and clusterrolebindings into one-minute windows per Elastic #
T1059, T1059.004, T1069, T1087, T1609, T1610↳ also matches list-nodes: list nodes, watch-nodes: watch nodes, create-nodes: create nodes, update-nodes: update nodes, patch-nodes: patch nodes Investigation guide
Triage and analysis#
Investigating Direct Interactive Kubernetes API Request by Unusual Utilities#
Possible investigation steps#
False positive analysis#
Response and remediation#
T1613↳ also matches list-nodes: list nodes Investigation guide
Triage and analysis#
Investigating GKE Multi-Resource Discovery#
client.user.email, source.ip, and user_agent.original. It alerts when five or more distinct resource kinds appear and the burst includes both cluster-layout kinds (namespaces, pods, or nodes) and RBAC kinds. Allowed and denied authorizations are both included: failures still signal probing.Possible investigation steps#
Esql.enumerated_resources, Esql.enumerated_namespaces, and Esql.enumerated_resource_names for ordering and targeted APIs.source.ip and user_agent.original match expected admin or automation clients.False positive analysis#
Response and remediation#
list nodes
#Description
Lists all Nodes, mapping the cluster's infrastructure (IPs, capacity, labels) in one call, a classic reconnaissance step before targeting a specific node.
Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 1 detection rule | Elastic |
stage | 1 detection rule | Elastic |
verb | 1 detection rule | Elastic |
Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes?limit=500",
"verb": "list",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=9bb0383c49b319fbf6b5ed61ab944378956d4292c784d32244ce2fa4dd846a3c"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2026-07-02T04:49:00.881187Z",
"stageTimestamp": "2026-07-02T04:49:00.883360Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. This rule detects interactive commands executed inside containers that use atypical utilities to hit the Kubernetes API, paired with near-simultaneous API activity on pods, secrets, service accounts, roles/bindings, or pod exec/attach/log/portforward. It surfaces hands-on-keyboard discovery and lateral movement using custom scripts that evade common tool allowlists; for example, an intruder opens a shell in a pod, uses Python to query the in-cluster API to list secrets, then triggers pods/exec to pivot into another workload. The rule groups GKE audit get/list events on namespaces, nodes, pods, configmaps, serviceaccounts, roles, rolebindings, clusterroles, and clusterrolebindings into one-minute windows per Elastic #
T1059, T1059.004, T1069, T1087, T1609, T1610↳ also matches get-nodes: get nodes, watch-nodes: watch nodes, create-nodes: create nodes, update-nodes: update nodes, patch-nodes: patch nodes Investigation guide
Triage and analysis#
Investigating Direct Interactive Kubernetes API Request by Unusual Utilities#
Possible investigation steps#
False positive analysis#
Response and remediation#
T1613↳ also matches get-nodes: get nodes Investigation guide
Triage and analysis#
Investigating GKE Multi-Resource Discovery#
client.user.email, source.ip, and user_agent.original. It alerts when five or more distinct resource kinds appear and the burst includes both cluster-layout kinds (namespaces, pods, or nodes) and RBAC kinds. Allowed and denied authorizations are both included: failures still signal probing.Possible investigation steps#
Esql.enumerated_resources, Esql.enumerated_namespaces, and Esql.enumerated_resource_names for ordering and targeted APIs.source.ip and user_agent.original match expected admin or automation clients.False positive analysis#
Response and remediation#
watch nodes
#Description
Opens a long-lived watch on Node changes cluster-wide. Elastic's new-terms user-agent rule flags a not-previously-seen identity doing this.
Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 1 detection rule | Elastic |
stage | 1 detection rule | Elastic |
verb | 1 detection rule | Elastic |
Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes?resourceVersion=1480&timeout=3s&watch=true",
"verb": "watch",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=97ca5ec05d5b7c1923d58d85f4449a4c26b2df61defa2a59b4045149ffed589e"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2026-07-02T22:49:24.869155Z",
"stageTimestamp": "2026-07-02T22:49:27.883684Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. This rule detects interactive commands executed inside containers that use atypical utilities to hit the Kubernetes API, paired with near-simultaneous API activity on pods, secrets, service accounts, roles/bindings, or pod exec/attach/log/portforward. It surfaces hands-on-keyboard discovery and lateral movement using custom scripts that evade common tool allowlists; for example, an intruder opens a shell in a pod, uses Python to query the in-cluster API to list secrets, then triggers pods/exec to pivot into another workload.Elastic #
T1059, T1059.004, T1069, T1087, T1609, T1610↳ also matches get-nodes: get nodes, list-nodes: list nodes, create-nodes: create nodes, update-nodes: update nodes, patch-nodes: patch nodes Investigation guide
Triage and analysis#
Investigating Direct Interactive Kubernetes API Request by Unusual Utilities#
Possible investigation steps#
False positive analysis#
Response and remediation#
create nodes
#Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 1 detection rule | Elastic |
stage | 1 detection rule | Elastic |
verb | 1 detection rule | Elastic |
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. This rule detects interactive commands executed inside containers that use atypical utilities to hit the Kubernetes API, paired with near-simultaneous API activity on pods, secrets, service accounts, roles/bindings, or pod exec/attach/log/portforward. It surfaces hands-on-keyboard discovery and lateral movement using custom scripts that evade common tool allowlists; for example, an intruder opens a shell in a pod, uses Python to query the in-cluster API to list secrets, then triggers pods/exec to pivot into another workload.Elastic #
T1059, T1059.004, T1069, T1087, T1609, T1610↳ also matches get-nodes: get nodes, list-nodes: list nodes, watch-nodes: watch nodes, update-nodes: update nodes, patch-nodes: patch nodes Investigation guide
Triage and analysis#
Investigating Direct Interactive Kubernetes API Request by Unusual Utilities#
Possible investigation steps#
False positive analysis#
Response and remediation#
update nodes
#Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 1 detection rule | Elastic |
stage | 1 detection rule | Elastic |
verb | 1 detection rule | Elastic |
Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes/node-control-plane?fieldManager=kubectl-replace&fieldValidation=Strict",
"verb": "update",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=97ca5ec05d5b7c1923d58d85f4449a4c26b2df61defa2a59b4045149ffed589e"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"apiVersion": "v1",
"resourceVersion": "1488"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestObject": {
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"resourceVersion": "1488",
"creationTimestamp": "2026-07-02T22:44:51Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/arch": "amd64",
"kubernetes.io/hostname": "node-control-plane",
"kubernetes.io/os": "linux",
"node-role.kubernetes.io/control-plane": ""
},
"annotations": {
"node.alpha.kubernetes.io/ttl": "0",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
}
},
"spec": {
"podCIDR": "10.244.0.0/24",
"podCIDRs": [
"10.244.0.0/24"
],
"providerID": "kind://docker/dw-k8s-harness/node-control-plane"
},
"status": {
"capacity": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"allocatable": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"conditions": [
{
"type": "MemoryPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientMemory",
"message": "kubelet has sufficient memory available"
},
{
"type": "DiskPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasNoDiskPressure",
"message": "kubelet has no disk pressure"
},
{
"type": "PIDPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientPID",
"message": "kubelet has sufficient PID available"
},
{
"type": "Ready",
"status": "True",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:45:13Z",
"reason": "KubeletReady",
"message": "kubelet is posting ready status"
}
],
"addresses": [
{
"type": "InternalIP",
"address": "172.19.0.2"
},
{
"type": "Hostname",
"address": "node-control-plane"
}
],
"daemonEndpoints": {
"kubeletEndpoint": {
"Port": 10250
}
},
"nodeInfo": {
"machineID": "815df19d528a443e902d7ee3648f1bf5",
"systemUUID": "00000000-0000-0000-0000-000000000000",
"bootID": "00000000-0000-0000-0000-000000000000",
"kernelVersion": "6.1.0-41-amd64",
"osImage": "Debian GNU/Linux 13 (trixie)",
"containerRuntimeVersion": "containerd://2.3.1",
"kubeletVersion": "v1.36.1",
"kubeProxyVersion": "",
"operatingSystem": "linux",
"architecture": "amd64"
},
"images": [
{
"names": [
"docker.io/library/import-2026-06-02@sha256:48e12aa71c24cf624334ae6f0373f1e1b85825254085475eda149111a926e33c",
"registry.k8s.io/kube-apiserver-amd64:v1.36.1",
"registry.k8s.io/kube-apiserver:v1.36.1"
],
"sizeBytes": 96683252
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:3fb749e08554fac4cde5dc53397de761b92939d34ead7e3c89248a8bf5b621e4",
"registry.k8s.io/kube-controller-manager-amd64:v1.36.1",
"registry.k8s.io/kube-controller-manager:v1.36.1"
],
"sizeBytes": 85870692
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:834d6b8414308aed626e67979c4665f21b3651e5d8d04ae68d960a4f844b4e81",
"registry.k8s.io/kube-proxy-amd64:v1.36.1",
"registry.k8s.io/kube-proxy:v1.36.1"
],
"sizeBytes": 79126247
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:77add4a58677c7fa1a02b42381a024adc860f8d6bbdf38a89d7f8803c116e43c",
"registry.k8s.io/kube-scheduler-amd64:v1.36.1",
"registry.k8s.io/kube-scheduler:v1.36.1"
],
"sizeBytes": 60683997
},
{
"names": [
"docker.io/kindest/kindnetd:v20260528-9350166c"
],
"sizeBytes": 39749049
},
{
"names": [
"registry.k8s.io/coredns/coredns:v1.14.2"
],
"sizeBytes": 23257541
},
{
"names": [
"registry.k8s.io/etcd:3.6.8-0"
],
"sizeBytes": 22885795
},
{
"names": [
"docker.io/kindest/local-path-provisioner:v20260521-9fb22683"
],
"sizeBytes": 15864063
},
{
"names": [
"docker.io/kindest/local-path-helper:v20260131-7181c60a"
],
"sizeBytes": 2872608
},
{
"names": [
"docker.io/library/busybox@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662",
"docker.io/library/busybox:1.36"
],
"sizeBytes": 2217006
},
{
"names": [
"registry.k8s.io/pause:3.10"
],
"sizeBytes": 320368
}
],
"runtimeHandlers": [
{
"name": "",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "runc",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "test-handler",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
}
],
"features": {
"supplementalGroupsPolicy": true
},
"declaredFeatures": [
"ExtendWebSocketsToKubelet",
"InPlacePodLevelResourcesVerticalScaling",
"InPlacePodVerticalScalingInitContainers",
"RestartAllContainersOnContainerExits"
]
}
},
"responseObject": {
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"resourceVersion": "1488",
"creationTimestamp": "2026-07-02T22:44:51Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/arch": "amd64",
"kubernetes.io/hostname": "node-control-plane",
"kubernetes.io/os": "linux",
"node-role.kubernetes.io/control-plane": ""
},
"annotations": {
"node.alpha.kubernetes.io/ttl": "0",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
}
},
"spec": {
"podCIDR": "10.244.0.0/24",
"podCIDRs": [
"10.244.0.0/24"
],
"providerID": "kind://docker/dw-k8s-harness/node-control-plane"
},
"status": {
"capacity": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"allocatable": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"conditions": [
{
"type": "MemoryPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientMemory",
"message": "kubelet has sufficient memory available"
},
{
"type": "DiskPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasNoDiskPressure",
"message": "kubelet has no disk pressure"
},
{
"type": "PIDPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientPID",
"message": "kubelet has sufficient PID available"
},
{
"type": "Ready",
"status": "True",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:45:13Z",
"reason": "KubeletReady",
"message": "kubelet is posting ready status"
}
],
"addresses": [
{
"type": "InternalIP",
"address": "172.19.0.2"
},
{
"type": "Hostname",
"address": "node-control-plane"
}
],
"daemonEndpoints": {
"kubeletEndpoint": {
"Port": 10250
}
},
"nodeInfo": {
"machineID": "815df19d528a443e902d7ee3648f1bf5",
"systemUUID": "00000000-0000-0000-0000-000000000000",
"bootID": "00000000-0000-0000-0000-000000000000",
"kernelVersion": "6.1.0-41-amd64",
"osImage": "Debian GNU/Linux 13 (trixie)",
"containerRuntimeVersion": "containerd://2.3.1",
"kubeletVersion": "v1.36.1",
"kubeProxyVersion": "",
"operatingSystem": "linux",
"architecture": "amd64"
},
"images": [
{
"names": [
"docker.io/library/import-2026-06-02@sha256:48e12aa71c24cf624334ae6f0373f1e1b85825254085475eda149111a926e33c",
"registry.k8s.io/kube-apiserver-amd64:v1.36.1",
"registry.k8s.io/kube-apiserver:v1.36.1"
],
"sizeBytes": 96683252
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:3fb749e08554fac4cde5dc53397de761b92939d34ead7e3c89248a8bf5b621e4",
"registry.k8s.io/kube-controller-manager-amd64:v1.36.1",
"registry.k8s.io/kube-controller-manager:v1.36.1"
],
"sizeBytes": 85870692
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:834d6b8414308aed626e67979c4665f21b3651e5d8d04ae68d960a4f844b4e81",
"registry.k8s.io/kube-proxy-amd64:v1.36.1",
"registry.k8s.io/kube-proxy:v1.36.1"
],
"sizeBytes": 79126247
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:77add4a58677c7fa1a02b42381a024adc860f8d6bbdf38a89d7f8803c116e43c",
"registry.k8s.io/kube-scheduler-amd64:v1.36.1",
"registry.k8s.io/kube-scheduler:v1.36.1"
],
"sizeBytes": 60683997
},
{
"names": [
"docker.io/kindest/kindnetd:v20260528-9350166c"
],
"sizeBytes": 39749049
},
{
"names": [
"registry.k8s.io/coredns/coredns:v1.14.2"
],
"sizeBytes": 23257541
},
{
"names": [
"registry.k8s.io/etcd:3.6.8-0"
],
"sizeBytes": 22885795
},
{
"names": [
"docker.io/kindest/local-path-provisioner:v20260521-9fb22683"
],
"sizeBytes": 15864063
},
{
"names": [
"docker.io/kindest/local-path-helper:v20260131-7181c60a"
],
"sizeBytes": 2872608
},
{
"names": [
"docker.io/library/busybox@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662",
"docker.io/library/busybox:1.36"
],
"sizeBytes": 2217006
},
{
"names": [
"registry.k8s.io/pause:3.10"
],
"sizeBytes": 320368
}
],
"runtimeHandlers": [
{
"name": "",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "runc",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "test-handler",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
}
],
"features": {
"supplementalGroupsPolicy": true
},
"declaredFeatures": [
"ExtendWebSocketsToKubelet",
"InPlacePodLevelResourcesVerticalScaling",
"InPlacePodVerticalScalingInitContainers",
"RestartAllContainersOnContainerExits"
]
}
},
"requestReceivedTimestamp": "2026-07-02T22:49:28.246601Z",
"stageTimestamp": "2026-07-02T22:49:28.251154Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. This rule detects interactive commands executed inside containers that use atypical utilities to hit the Kubernetes API, paired with near-simultaneous API activity on pods, secrets, service accounts, roles/bindings, or pod exec/attach/log/portforward. It surfaces hands-on-keyboard discovery and lateral movement using custom scripts that evade common tool allowlists; for example, an intruder opens a shell in a pod, uses Python to query the in-cluster API to list secrets, then triggers pods/exec to pivot into another workload.Elastic #
T1059, T1059.004, T1069, T1087, T1609, T1610↳ also matches get-nodes: get nodes, list-nodes: list nodes, watch-nodes: watch nodes, create-nodes: create nodes, patch-nodes: patch nodes Investigation guide
Triage and analysis#
Investigating Direct Interactive Kubernetes API Request by Unusual Utilities#
Possible investigation steps#
False positive analysis#
Response and remediation#
patch nodes
#Description
Modifies a Node's labels or taints, which can affect pod scheduling (e.g. clearing a taint to land a pod on a hardened node) or spoof node metadata.
Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 1 detection rule | Elastic |
stage | 1 detection rule | Elastic |
verb | 1 detection rule | Elastic |
Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes/node-control-plane?fieldManager=kubectl-patch",
"verb": "patch",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=9bb0383c49b319fbf6b5ed61ab944378956d4292c784d32244ce2fa4dd846a3c"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"name": "node-control-plane",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestObject": {
"metadata": {
"labels": {
"dw-harn-probe": "1"
}
}
},
"responseObject": {
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"resourceVersion": "1862",
"creationTimestamp": "2026-07-02T04:36:42Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"dw-harn-probe": "1",
"kubernetes.io/arch": "amd64",
"kubernetes.io/hostname": "node-control-plane",
"kubernetes.io/os": "linux",
"node-role.kubernetes.io/control-plane": ""
},
"annotations": {
"node.alpha.kubernetes.io/ttl": "0",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
}
},
"spec": {
"podCIDR": "10.244.0.0/24",
"podCIDRs": [
"10.244.0.0/24"
],
"providerID": "kind://docker/dw-k8s-harness/node-control-plane"
},
"status": {
"capacity": {
"cpu": "10",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "82361532Ki",
"pods": "110"
},
"allocatable": {
"cpu": "10",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "82361532Ki",
"pods": "110"
},
"conditions": [
{
"type": "MemoryPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T04:45:24Z",
"lastTransitionTime": "2026-07-02T04:36:41Z",
"reason": "KubeletHasSufficientMemory",
"message": "kubelet has sufficient memory available"
},
{
"type": "DiskPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T04:45:24Z",
"lastTransitionTime": "2026-07-02T04:36:41Z",
"reason": "KubeletHasNoDiskPressure",
"message": "kubelet has no disk pressure"
},
{
"type": "PIDPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T04:45:24Z",
"lastTransitionTime": "2026-07-02T04:36:41Z",
"reason": "KubeletHasSufficientPID",
"message": "kubelet has sufficient PID available"
},
{
"type": "Ready",
"status": "True",
"lastHeartbeatTime": "2026-07-02T04:45:24Z",
"lastTransitionTime": "2026-07-02T04:37:03Z",
"reason": "KubeletReady",
"message": "kubelet is posting ready status"
}
],
"addresses": [
{
"type": "InternalIP",
"address": "172.19.0.2"
},
{
"type": "Hostname",
"address": "node-control-plane"
}
],
"daemonEndpoints": {
"kubeletEndpoint": {
"Port": 10250
}
},
"nodeInfo": {
"machineID": "644a23c05a804d8abdd101de8fc3821c",
"systemUUID": "00000000-0000-0000-0000-000000000000",
"bootID": "00000000-0000-0000-0000-000000000000",
"kernelVersion": "6.1.0-41-amd64",
"osImage": "Debian GNU/Linux 13 (trixie)",
"containerRuntimeVersion": "containerd://2.3.1",
"kubeletVersion": "v1.36.1",
"kubeProxyVersion": "",
"operatingSystem": "linux",
"architecture": "amd64"
},
"images": [
{
"names": [
"docker.io/library/import-2026-06-02@sha256:48e12aa71c24cf624334ae6f0373f1e1b85825254085475eda149111a926e33c",
"registry.k8s.io/kube-apiserver-amd64:v1.36.1",
"registry.k8s.io/kube-apiserver:v1.36.1"
],
"sizeBytes": 96682870
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:3fb749e08554fac4cde5dc53397de761b92939d34ead7e3c89248a8bf5b621e4",
"registry.k8s.io/kube-controller-manager-amd64:v1.36.1",
"registry.k8s.io/kube-controller-manager:v1.36.1"
],
"sizeBytes": 85870301
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:834d6b8414308aed626e67979c4665f21b3651e5d8d04ae68d960a4f844b4e81",
"registry.k8s.io/kube-proxy-amd64:v1.36.1",
"registry.k8s.io/kube-proxy:v1.36.1"
],
"sizeBytes": 79126247
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:77add4a58677c7fa1a02b42381a024adc860f8d6bbdf38a89d7f8803c116e43c",
"registry.k8s.io/kube-scheduler-amd64:v1.36.1",
"registry.k8s.io/kube-scheduler:v1.36.1"
],
"sizeBytes": 60683997
},
{
"names": [
"docker.io/kindest/kindnetd:v20260528-9350166c"
],
"sizeBytes": 39749049
},
{
"names": [
"registry.k8s.io/coredns/coredns:v1.14.2"
],
"sizeBytes": 23257541
},
{
"names": [
"registry.k8s.io/etcd:3.6.8-0"
],
"sizeBytes": 22885795
},
{
"names": [
"docker.io/kindest/local-path-provisioner:v20260521-9fb22683"
],
"sizeBytes": 15864063
},
{
"names": [
"docker.io/kindest/local-path-helper:v20260131-7181c60a"
],
"sizeBytes": 2872608
},
{
"names": [
"docker.io/library/busybox@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662",
"docker.io/library/busybox:1.36"
],
"sizeBytes": 2217006
},
{
"names": [
"registry.k8s.io/pause:3.10"
],
"sizeBytes": 320368
}
],
"runtimeHandlers": [
{
"name": "",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "runc",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "test-handler",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
}
],
"features": {
"supplementalGroupsPolicy": true
},
"declaredFeatures": [
"ExtendWebSocketsToKubelet",
"InPlacePodLevelResourcesVerticalScaling",
"InPlacePodVerticalScalingInitContainers",
"RestartAllContainersOnContainerExits"
]
}
},
"requestReceivedTimestamp": "2026-07-02T04:49:01.007690Z",
"stageTimestamp": "2026-07-02T04:49:01.014428Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. This rule detects interactive commands executed inside containers that use atypical utilities to hit the Kubernetes API, paired with near-simultaneous API activity on pods, secrets, service accounts, roles/bindings, or pod exec/attach/log/portforward. It surfaces hands-on-keyboard discovery and lateral movement using custom scripts that evade common tool allowlists; for example, an intruder opens a shell in a pod, uses Python to query the in-cluster API to list secrets, then triggers pods/exec to pivot into another workload.Elastic #
T1059, T1059.004, T1069, T1087, T1609, T1610↳ also matches get-nodes: get nodes, list-nodes: list nodes, watch-nodes: watch nodes, create-nodes: create nodes, update-nodes: update nodes Investigation guide
Triage and analysis#
Investigating Direct Interactive Kubernetes API Request by Unusual Utilities#
Possible investigation steps#
False positive analysis#
Response and remediation#
delete nodes
#deletecollection nodes
#get nodes/proxy
#Description
Proxy request to node API endpoint (privilege escalation: node-proxy allows kubelet API access).
Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 3 detection rules | Elastic |
objectRef.subresource | 3 detection rules | Elastic |
requestURI | 2 detection rules | Elastic |
user.username | 2 detection rules | Elastic |
Common Indicators #
Positive field/value combinations most frequently checked by detection rules attached to this catalog entry, derived from cross-vendor predicate analysis. This is separate from Fields accounting, which also includes exclusions and counts distinct attached rules.
| Field | Kind | Value | Rules | Vendors |
|---|---|---|---|---|
EventType (elastic rule field) | eq | Microsoft.ContainerService/managedClusters/diagnosticLogs/Read | 2 rules | elastic |
azure.platformlogs.category (elastic rule field) | eq | kube-audit | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.resource (elastic rule field) | eq | nodes | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.subresource (elastic rule field) | eq | proxy | 2 rules | elastic |
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → AKS kube-audit events are carried under the flattened AKS kube-audit events are carried under the flattened Review Elastic #
T1210, T1609↳ also matches create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, patch-nodes-proxy: patch nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS Kubelet Proxy to Command Execution Endpoint#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. This rule keys on the Kubelet endpoint in azure.platformlogs.properties.log.requestURI: /proxy/run, /proxy/exec, /proxy/attach, /proxy/portforward, and /proxy/cri execute commands in a pod on the target node, whereas monitoring uses /metrics and /stats. Any hit here is high-signal command execution regardless of the acting identity, including a stolen monitoring service-account token.Possible investigation steps#
azure.platformlogs.properties.log.requestURI (the path encodes /<endpoint>/<namespace>/<pod>/<container>) and the acting identity in azure.platformlogs.properties.log.user.username.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP and the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal./proxy/pods, /proxy/runningpods) and follow-on RBAC changes, secret reads, or token requests from the same identity.False positive analysis#
Response and remediation#
nodes/proxy and remove it from workload identities that do not require it.T1210, T1609↳ also matches create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, patch-nodes-proxy: patch nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS API Server Proxying Request to Kubelet#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. The nodes/proxy subresource tunnels a request through the API server to a node's Kubelet. An identity with this permission can enumerate pods (/proxy/pods, /proxy/runningpods) or run commands (/proxy/run, /proxy/exec) on nodes without direct network access to the Kubelet port. This rule excludes the node, control-plane, and kube-system service-account identities that routinely proxy for monitoring, so remaining matches are workload identities or users that should rarely, if ever, reach the Kubelet.Possible investigation steps#
azure.platformlogs.properties.log.user.username and whether a workload service account or user should reach the Kubelet at all. Compromised pod service accounts (system:serviceaccount:<ns>:<name>) are the primary vehicle for this technique.azure.platformlogs.properties.log.requestURI. /metrics and /stats are monitoring; /pods and /runningpods are reconnaissance; /run, /exec, /attach, and /portforward are command execution and warrant immediate escalation.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP, while the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal. In-cluster pivots show only internal addresses, so absence of an external IP does not clear the event.azure.platformlogs.properties.log.objectRef.name and correlate with subsequent activity on that node's workloads (secret reads, RBAC changes, new pods).False positive analysis#
Response and remediation#
nodes/proxy.T1550, T1550.001, T1611, T1613↳ also matches create-nodes-proxy: create nodes/proxy Investigation guide
Triage and analysis#
Investigating GKE API Server Proxying Request to Kubelet#
client.user.email, source.ip, and user_agent.original to determine who initiated the proxy request. Examine gcp.audit.resource_name and event.action to identify which Kubelet path was accessed after /proxy/.Possible investigation steps#
/proxy/pods — pod spec enumeration, including environment variable secrets/proxy/exec or /proxy/run — command execution inside containers on that node/proxy/configz — Kubelet configuration and authentication settings/proxy/runningpods — active workload enumeration/proxy/containerLogs — log harvesting for leaked credentialsnodes/proxy permission by reviewing RBAC bindings.False positive analysis#
Response and remediation#
nodes/proxy./proxy/pods was accessed, rotate secrets and credentials that may have been exposed via environment variables on that node./proxy/exec or /proxy/run was accessed, treat the node as compromised and isolate it.nodes/proxy to infrastructure automation only.
create nodes/proxy
#Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 3 detection rules | Elastic |
objectRef.subresource | 3 detection rules | Elastic |
requestURI | 2 detection rules | Elastic |
user.username | 2 detection rules | Elastic |
Common Indicators #
Positive field/value combinations most frequently checked by detection rules attached to this catalog entry, derived from cross-vendor predicate analysis. This is separate from Fields accounting, which also includes exclusions and counts distinct attached rules.
| Field | Kind | Value | Rules | Vendors |
|---|---|---|---|---|
EventType (elastic rule field) | eq | Microsoft.ContainerService/managedClusters/diagnosticLogs/Read | 2 rules | elastic |
azure.platformlogs.category (elastic rule field) | eq | kube-audit | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.resource (elastic rule field) | eq | nodes | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.subresource (elastic rule field) | eq | proxy | 2 rules | elastic |
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → AKS kube-audit events are carried under the flattened AKS kube-audit events are carried under the flattened Review Elastic #
T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, update-nodes-proxy: update nodes/proxy, patch-nodes-proxy: patch nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS Kubelet Proxy to Command Execution Endpoint#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. This rule keys on the Kubelet endpoint in azure.platformlogs.properties.log.requestURI: /proxy/run, /proxy/exec, /proxy/attach, /proxy/portforward, and /proxy/cri execute commands in a pod on the target node, whereas monitoring uses /metrics and /stats. Any hit here is high-signal command execution regardless of the acting identity, including a stolen monitoring service-account token.Possible investigation steps#
azure.platformlogs.properties.log.requestURI (the path encodes /<endpoint>/<namespace>/<pod>/<container>) and the acting identity in azure.platformlogs.properties.log.user.username.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP and the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal./proxy/pods, /proxy/runningpods) and follow-on RBAC changes, secret reads, or token requests from the same identity.False positive analysis#
Response and remediation#
nodes/proxy and remove it from workload identities that do not require it.T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, update-nodes-proxy: update nodes/proxy, patch-nodes-proxy: patch nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS API Server Proxying Request to Kubelet#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. The nodes/proxy subresource tunnels a request through the API server to a node's Kubelet. An identity with this permission can enumerate pods (/proxy/pods, /proxy/runningpods) or run commands (/proxy/run, /proxy/exec) on nodes without direct network access to the Kubelet port. This rule excludes the node, control-plane, and kube-system service-account identities that routinely proxy for monitoring, so remaining matches are workload identities or users that should rarely, if ever, reach the Kubelet.Possible investigation steps#
azure.platformlogs.properties.log.user.username and whether a workload service account or user should reach the Kubelet at all. Compromised pod service accounts (system:serviceaccount:<ns>:<name>) are the primary vehicle for this technique.azure.platformlogs.properties.log.requestURI. /metrics and /stats are monitoring; /pods and /runningpods are reconnaissance; /run, /exec, /attach, and /portforward are command execution and warrant immediate escalation.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP, while the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal. In-cluster pivots show only internal addresses, so absence of an external IP does not clear the event.azure.platformlogs.properties.log.objectRef.name and correlate with subsequent activity on that node's workloads (secret reads, RBAC changes, new pods).False positive analysis#
Response and remediation#
nodes/proxy.T1550, T1550.001, T1611, T1613↳ also matches get-nodes-proxy: get nodes/proxy Investigation guide
Triage and analysis#
Investigating GKE API Server Proxying Request to Kubelet#
client.user.email, source.ip, and user_agent.original to determine who initiated the proxy request. Examine gcp.audit.resource_name and event.action to identify which Kubelet path was accessed after /proxy/.Possible investigation steps#
/proxy/pods — pod spec enumeration, including environment variable secrets/proxy/exec or /proxy/run — command execution inside containers on that node/proxy/configz — Kubelet configuration and authentication settings/proxy/runningpods — active workload enumeration/proxy/containerLogs — log harvesting for leaked credentialsnodes/proxy permission by reviewing RBAC bindings.False positive analysis#
Response and remediation#
nodes/proxy./proxy/pods was accessed, rotate secrets and credentials that may have been exposed via environment variables on that node./proxy/exec or /proxy/run was accessed, treat the node as compromised and isolate it.nodes/proxy to infrastructure automation only.
update nodes/proxy
#Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 3 detection rules | Elastic |
objectRef.subresource | 3 detection rules | Elastic |
requestURI | 2 detection rules | Elastic |
user.username | 2 detection rules | Elastic |
Common Indicators #
Positive field/value combinations most frequently checked by detection rules attached to this catalog entry, derived from cross-vendor predicate analysis. This is separate from Fields accounting, which also includes exclusions and counts distinct attached rules.
| Field | Kind | Value | Rules | Vendors |
|---|---|---|---|---|
EventType (elastic rule field) | eq | Microsoft.ContainerService/managedClusters/diagnosticLogs/Read | 2 rules | elastic |
azure.platformlogs.category (elastic rule field) | eq | kube-audit | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.resource (elastic rule field) | eq | nodes | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.subresource (elastic rule field) | eq | proxy | 2 rules | elastic |
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → AKS kube-audit events are carried under the flattened AKS kube-audit events are carried under the flattened Review the user.name, source.ip, and user_agent.original fields to determine who initiated the proxy request and from where. Examine kubernetes.audit.requestURI to identify which Kubelet endpoint was proxied — the path after /proxy/ maps directly to the Kubelet API path the attacker accessed.Elastic #
T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, patch-nodes-proxy: patch nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS Kubelet Proxy to Command Execution Endpoint#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. This rule keys on the Kubelet endpoint in azure.platformlogs.properties.log.requestURI: /proxy/run, /proxy/exec, /proxy/attach, /proxy/portforward, and /proxy/cri execute commands in a pod on the target node, whereas monitoring uses /metrics and /stats. Any hit here is high-signal command execution regardless of the acting identity, including a stolen monitoring service-account token.Possible investigation steps#
azure.platformlogs.properties.log.requestURI (the path encodes /<endpoint>/<namespace>/<pod>/<container>) and the acting identity in azure.platformlogs.properties.log.user.username.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP and the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal./proxy/pods, /proxy/runningpods) and follow-on RBAC changes, secret reads, or token requests from the same identity.False positive analysis#
Response and remediation#
nodes/proxy and remove it from workload identities that do not require it.T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, patch-nodes-proxy: patch nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS API Server Proxying Request to Kubelet#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. The nodes/proxy subresource tunnels a request through the API server to a node's Kubelet. An identity with this permission can enumerate pods (/proxy/pods, /proxy/runningpods) or run commands (/proxy/run, /proxy/exec) on nodes without direct network access to the Kubelet port. This rule excludes the node, control-plane, and kube-system service-account identities that routinely proxy for monitoring, so remaining matches are workload identities or users that should rarely, if ever, reach the Kubelet.Possible investigation steps#
azure.platformlogs.properties.log.user.username and whether a workload service account or user should reach the Kubelet at all. Compromised pod service accounts (system:serviceaccount:<ns>:<name>) are the primary vehicle for this technique.azure.platformlogs.properties.log.requestURI. /metrics and /stats are monitoring; /pods and /runningpods are reconnaissance; /run, /exec, /attach, and /portforward are command execution and warrant immediate escalation.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP, while the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal. In-cluster pivots show only internal addresses, so absence of an external IP does not clear the event.azure.platformlogs.properties.log.objectRef.name and correlate with subsequent activity on that node's workloads (secret reads, RBAC changes, new pods).False positive analysis#
Response and remediation#
nodes/proxy.T1550, T1550.001, T1611, T1613↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, patch-nodes-proxy: patch nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Kubernetes API Server Proxying Request to Kubelet#
Possible investigation steps#
False positive analysis#
Response and remediation#
patch nodes/proxy
#Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 3 detection rules | Elastic |
objectRef.subresource | 3 detection rules | Elastic |
requestURI | 2 detection rules | Elastic |
user.username | 2 detection rules | Elastic |
Common Indicators #
Positive field/value combinations most frequently checked by detection rules attached to this catalog entry, derived from cross-vendor predicate analysis. This is separate from Fields accounting, which also includes exclusions and counts distinct attached rules.
| Field | Kind | Value | Rules | Vendors |
|---|---|---|---|---|
EventType (elastic rule field) | eq | Microsoft.ContainerService/managedClusters/diagnosticLogs/Read | 2 rules | elastic |
azure.platformlogs.category (elastic rule field) | eq | kube-audit | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.resource (elastic rule field) | eq | nodes | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.subresource (elastic rule field) | eq | proxy | 2 rules | elastic |
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → AKS kube-audit events are carried under the flattened AKS kube-audit events are carried under the flattened Review the user.name, source.ip, and user_agent.original fields to determine who initiated the proxy request and from where. Examine kubernetes.audit.requestURI to identify which Kubelet endpoint was proxied — the path after /proxy/ maps directly to the Kubelet API path the attacker accessed.Elastic #
T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS Kubelet Proxy to Command Execution Endpoint#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. This rule keys on the Kubelet endpoint in azure.platformlogs.properties.log.requestURI: /proxy/run, /proxy/exec, /proxy/attach, /proxy/portforward, and /proxy/cri execute commands in a pod on the target node, whereas monitoring uses /metrics and /stats. Any hit here is high-signal command execution regardless of the acting identity, including a stolen monitoring service-account token.Possible investigation steps#
azure.platformlogs.properties.log.requestURI (the path encodes /<endpoint>/<namespace>/<pod>/<container>) and the acting identity in azure.platformlogs.properties.log.user.username.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP and the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal./proxy/pods, /proxy/runningpods) and follow-on RBAC changes, secret reads, or token requests from the same identity.False positive analysis#
Response and remediation#
nodes/proxy and remove it from workload identities that do not require it.T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS API Server Proxying Request to Kubelet#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. The nodes/proxy subresource tunnels a request through the API server to a node's Kubelet. An identity with this permission can enumerate pods (/proxy/pods, /proxy/runningpods) or run commands (/proxy/run, /proxy/exec) on nodes without direct network access to the Kubelet port. This rule excludes the node, control-plane, and kube-system service-account identities that routinely proxy for monitoring, so remaining matches are workload identities or users that should rarely, if ever, reach the Kubelet.Possible investigation steps#
azure.platformlogs.properties.log.user.username and whether a workload service account or user should reach the Kubelet at all. Compromised pod service accounts (system:serviceaccount:<ns>:<name>) are the primary vehicle for this technique.azure.platformlogs.properties.log.requestURI. /metrics and /stats are monitoring; /pods and /runningpods are reconnaissance; /run, /exec, /attach, and /portforward are command execution and warrant immediate escalation.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP, while the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal. In-cluster pivots show only internal addresses, so absence of an external IP does not clear the event.azure.platformlogs.properties.log.objectRef.name and correlate with subsequent activity on that node's workloads (secret reads, RBAC changes, new pods).False positive analysis#
Response and remediation#
nodes/proxy.T1550, T1550.001, T1611, T1613↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, delete-nodes-proxy: delete nodes/proxy Investigation guide
Triage and analysis#
Investigating Kubernetes API Server Proxying Request to Kubelet#
Possible investigation steps#
False positive analysis#
Response and remediation#
delete nodes/proxy
#Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 3 detection rules | Elastic |
objectRef.subresource | 3 detection rules | Elastic |
requestURI | 2 detection rules | Elastic |
user.username | 2 detection rules | Elastic |
Common Indicators #
Positive field/value combinations most frequently checked by detection rules attached to this catalog entry, derived from cross-vendor predicate analysis. This is separate from Fields accounting, which also includes exclusions and counts distinct attached rules.
| Field | Kind | Value | Rules | Vendors |
|---|---|---|---|---|
EventType (elastic rule field) | eq | Microsoft.ContainerService/managedClusters/diagnosticLogs/Read | 2 rules | elastic |
azure.platformlogs.category (elastic rule field) | eq | kube-audit | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.resource (elastic rule field) | eq | nodes | 2 rules | elastic |
azure.platformlogs.properties.log.objectRef.subresource (elastic rule field) | eq | proxy | 2 rules | elastic |
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → AKS kube-audit events are carried under the flattened AKS kube-audit events are carried under the flattened Review the user.name, source.ip, and user_agent.original fields to determine who initiated the proxy request and from where. Examine kubernetes.audit.requestURI to identify which Kubelet endpoint was proxied — the path after /proxy/ maps directly to the Kubelet API path the attacker accessed.Elastic #
T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, patch-nodes-proxy: patch nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS Kubelet Proxy to Command Execution Endpoint#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. This rule keys on the Kubelet endpoint in azure.platformlogs.properties.log.requestURI: /proxy/run, /proxy/exec, /proxy/attach, /proxy/portforward, and /proxy/cri execute commands in a pod on the target node, whereas monitoring uses /metrics and /stats. Any hit here is high-signal command execution regardless of the acting identity, including a stolen monitoring service-account token.Possible investigation steps#
azure.platformlogs.properties.log.requestURI (the path encodes /<endpoint>/<namespace>/<pod>/<container>) and the acting identity in azure.platformlogs.properties.log.user.username.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP and the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal./proxy/pods, /proxy/runningpods) and follow-on RBAC changes, secret reads, or token requests from the same identity.False positive analysis#
Response and remediation#
nodes/proxy and remove it from workload identities that do not require it.T1210, T1609↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, patch-nodes-proxy: patch nodes/proxy Investigation guide
Triage and analysis#
Investigating Azure AKS API Server Proxying Request to Kubelet#
azure.platformlogs.properties.log.* subtree and share the ARM operation event.action: Microsoft.ContainerService/managedClusters/diagnosticLogs/Read. The nodes/proxy subresource tunnels a request through the API server to a node's Kubelet. An identity with this permission can enumerate pods (/proxy/pods, /proxy/runningpods) or run commands (/proxy/run, /proxy/exec) on nodes without direct network access to the Kubelet port. This rule excludes the node, control-plane, and kube-system service-account identities that routinely proxy for monitoring, so remaining matches are workload identities or users that should rarely, if ever, reach the Kubelet.Possible investigation steps#
azure.platformlogs.properties.log.user.username and whether a workload service account or user should reach the Kubelet at all. Compromised pod service accounts (system:serviceaccount:<ns>:<name>) are the primary vehicle for this technique.azure.platformlogs.properties.log.requestURI. /metrics and /stats are monitoring; /pods and /runningpods are reconnaissance; /run, /exec, /attach, and /portforward are command execution and warrant immediate escalation.azure.platformlogs.properties.log.sourceIPs. This is an array; for an externally operated attack the first element is the operator's real client IP, while the trailing entry is the internal API-server/konnectivity hop (172.31.x). A first entry that is not the cluster's own egress is a strong signal. In-cluster pivots show only internal addresses, so absence of an external IP does not clear the event.azure.platformlogs.properties.log.objectRef.name and correlate with subsequent activity on that node's workloads (secret reads, RBAC changes, new pods).False positive analysis#
Response and remediation#
nodes/proxy.T1550, T1550.001, T1611, T1613↳ also matches get-nodes-proxy: get nodes/proxy, create-nodes-proxy: create nodes/proxy, update-nodes-proxy: update nodes/proxy, patch-nodes-proxy: patch nodes/proxy Investigation guide
Triage and analysis#
Investigating Kubernetes API Server Proxying Request to Kubelet#
Possible investigation steps#
False positive analysis#
Response and remediation#
get nodes/status
#Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes/node-control-plane/status",
"verb": "get",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=9bb0383c49b319fbf6b5ed61ab944378956d4292c784d32244ce2fa4dd846a3c"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"name": "node-control-plane",
"apiVersion": "v1",
"subresource": "status"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2026-07-02T04:49:01.144634Z",
"stageTimestamp": "2026-07-02T04:49:01.146884Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
update nodes/status
#Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes/node-control-plane/status?fieldManager=kubectl-replace&fieldValidation=Strict",
"verb": "update",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=97ca5ec05d5b7c1923d58d85f4449a4c26b2df61defa2a59b4045149ffed589e"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"apiVersion": "v1",
"resourceVersion": "1488",
"subresource": "status"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestObject": {
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"resourceVersion": "1488",
"creationTimestamp": "2026-07-02T22:44:51Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/arch": "amd64",
"kubernetes.io/hostname": "node-control-plane",
"kubernetes.io/os": "linux",
"node-role.kubernetes.io/control-plane": ""
},
"annotations": {
"node.alpha.kubernetes.io/ttl": "0",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
}
},
"spec": {
"podCIDR": "10.244.0.0/24",
"podCIDRs": [
"10.244.0.0/24"
],
"providerID": "kind://docker/dw-k8s-harness/node-control-plane"
},
"status": {
"capacity": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"allocatable": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"conditions": [
{
"type": "MemoryPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientMemory",
"message": "kubelet has sufficient memory available"
},
{
"type": "DiskPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasNoDiskPressure",
"message": "kubelet has no disk pressure"
},
{
"type": "PIDPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientPID",
"message": "kubelet has sufficient PID available"
},
{
"type": "Ready",
"status": "True",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:45:13Z",
"reason": "KubeletReady",
"message": "kubelet is posting ready status"
}
],
"addresses": [
{
"type": "InternalIP",
"address": "172.19.0.2"
},
{
"type": "Hostname",
"address": "node-control-plane"
}
],
"daemonEndpoints": {
"kubeletEndpoint": {
"Port": 10250
}
},
"nodeInfo": {
"machineID": "815df19d528a443e902d7ee3648f1bf5",
"systemUUID": "00000000-0000-0000-0000-000000000000",
"bootID": "00000000-0000-0000-0000-000000000000",
"kernelVersion": "6.1.0-41-amd64",
"osImage": "Debian GNU/Linux 13 (trixie)",
"containerRuntimeVersion": "containerd://2.3.1",
"kubeletVersion": "v1.36.1",
"kubeProxyVersion": "",
"operatingSystem": "linux",
"architecture": "amd64"
},
"images": [
{
"names": [
"docker.io/library/import-2026-06-02@sha256:48e12aa71c24cf624334ae6f0373f1e1b85825254085475eda149111a926e33c",
"registry.k8s.io/kube-apiserver-amd64:v1.36.1",
"registry.k8s.io/kube-apiserver:v1.36.1"
],
"sizeBytes": 96683252
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:3fb749e08554fac4cde5dc53397de761b92939d34ead7e3c89248a8bf5b621e4",
"registry.k8s.io/kube-controller-manager-amd64:v1.36.1",
"registry.k8s.io/kube-controller-manager:v1.36.1"
],
"sizeBytes": 85870692
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:834d6b8414308aed626e67979c4665f21b3651e5d8d04ae68d960a4f844b4e81",
"registry.k8s.io/kube-proxy-amd64:v1.36.1",
"registry.k8s.io/kube-proxy:v1.36.1"
],
"sizeBytes": 79126247
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:77add4a58677c7fa1a02b42381a024adc860f8d6bbdf38a89d7f8803c116e43c",
"registry.k8s.io/kube-scheduler-amd64:v1.36.1",
"registry.k8s.io/kube-scheduler:v1.36.1"
],
"sizeBytes": 60683997
},
{
"names": [
"docker.io/kindest/kindnetd:v20260528-9350166c"
],
"sizeBytes": 39749049
},
{
"names": [
"registry.k8s.io/coredns/coredns:v1.14.2"
],
"sizeBytes": 23257541
},
{
"names": [
"registry.k8s.io/etcd:3.6.8-0"
],
"sizeBytes": 22885795
},
{
"names": [
"docker.io/kindest/local-path-provisioner:v20260521-9fb22683"
],
"sizeBytes": 15864063
},
{
"names": [
"docker.io/kindest/local-path-helper:v20260131-7181c60a"
],
"sizeBytes": 2872608
},
{
"names": [
"docker.io/library/busybox@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662",
"docker.io/library/busybox:1.36"
],
"sizeBytes": 2217006
},
{
"names": [
"registry.k8s.io/pause:3.10"
],
"sizeBytes": 320368
}
],
"runtimeHandlers": [
{
"name": "",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "runc",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "test-handler",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
}
],
"features": {
"supplementalGroupsPolicy": true
},
"declaredFeatures": [
"ExtendWebSocketsToKubelet",
"InPlacePodLevelResourcesVerticalScaling",
"InPlacePodVerticalScalingInitContainers",
"RestartAllContainersOnContainerExits"
]
}
},
"responseObject": {
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"resourceVersion": "1488",
"creationTimestamp": "2026-07-02T22:44:51Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/arch": "amd64",
"kubernetes.io/hostname": "node-control-plane",
"kubernetes.io/os": "linux",
"node-role.kubernetes.io/control-plane": ""
},
"annotations": {
"node.alpha.kubernetes.io/ttl": "0",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
}
},
"spec": {
"podCIDR": "10.244.0.0/24",
"podCIDRs": [
"10.244.0.0/24"
],
"providerID": "kind://docker/dw-k8s-harness/node-control-plane"
},
"status": {
"capacity": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"allocatable": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"conditions": [
{
"type": "MemoryPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientMemory",
"message": "kubelet has sufficient memory available"
},
{
"type": "DiskPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasNoDiskPressure",
"message": "kubelet has no disk pressure"
},
{
"type": "PIDPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientPID",
"message": "kubelet has sufficient PID available"
},
{
"type": "Ready",
"status": "True",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:45:13Z",
"reason": "KubeletReady",
"message": "kubelet is posting ready status"
}
],
"addresses": [
{
"type": "InternalIP",
"address": "172.19.0.2"
},
{
"type": "Hostname",
"address": "node-control-plane"
}
],
"daemonEndpoints": {
"kubeletEndpoint": {
"Port": 10250
}
},
"nodeInfo": {
"machineID": "815df19d528a443e902d7ee3648f1bf5",
"systemUUID": "00000000-0000-0000-0000-000000000000",
"bootID": "00000000-0000-0000-0000-000000000000",
"kernelVersion": "6.1.0-41-amd64",
"osImage": "Debian GNU/Linux 13 (trixie)",
"containerRuntimeVersion": "containerd://2.3.1",
"kubeletVersion": "v1.36.1",
"kubeProxyVersion": "",
"operatingSystem": "linux",
"architecture": "amd64"
},
"images": [
{
"names": [
"docker.io/library/import-2026-06-02@sha256:48e12aa71c24cf624334ae6f0373f1e1b85825254085475eda149111a926e33c",
"registry.k8s.io/kube-apiserver-amd64:v1.36.1",
"registry.k8s.io/kube-apiserver:v1.36.1"
],
"sizeBytes": 96683252
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:3fb749e08554fac4cde5dc53397de761b92939d34ead7e3c89248a8bf5b621e4",
"registry.k8s.io/kube-controller-manager-amd64:v1.36.1",
"registry.k8s.io/kube-controller-manager:v1.36.1"
],
"sizeBytes": 85870692
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:834d6b8414308aed626e67979c4665f21b3651e5d8d04ae68d960a4f844b4e81",
"registry.k8s.io/kube-proxy-amd64:v1.36.1",
"registry.k8s.io/kube-proxy:v1.36.1"
],
"sizeBytes": 79126247
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:77add4a58677c7fa1a02b42381a024adc860f8d6bbdf38a89d7f8803c116e43c",
"registry.k8s.io/kube-scheduler-amd64:v1.36.1",
"registry.k8s.io/kube-scheduler:v1.36.1"
],
"sizeBytes": 60683997
},
{
"names": [
"docker.io/kindest/kindnetd:v20260528-9350166c"
],
"sizeBytes": 39749049
},
{
"names": [
"registry.k8s.io/coredns/coredns:v1.14.2"
],
"sizeBytes": 23257541
},
{
"names": [
"registry.k8s.io/etcd:3.6.8-0"
],
"sizeBytes": 22885795
},
{
"names": [
"docker.io/kindest/local-path-provisioner:v20260521-9fb22683"
],
"sizeBytes": 15864063
},
{
"names": [
"docker.io/kindest/local-path-helper:v20260131-7181c60a"
],
"sizeBytes": 2872608
},
{
"names": [
"docker.io/library/busybox@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662",
"docker.io/library/busybox:1.36"
],
"sizeBytes": 2217006
},
{
"names": [
"registry.k8s.io/pause:3.10"
],
"sizeBytes": 320368
}
],
"runtimeHandlers": [
{
"name": "",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "runc",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "test-handler",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
}
],
"features": {
"supplementalGroupsPolicy": true
},
"declaredFeatures": [
"ExtendWebSocketsToKubelet",
"InPlacePodLevelResourcesVerticalScaling",
"InPlacePodVerticalScalingInitContainers",
"RestartAllContainersOnContainerExits"
]
}
},
"requestReceivedTimestamp": "2026-07-02T22:49:28.523884Z",
"stageTimestamp": "2026-07-02T22:49:28.528919Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
patch nodes/status
#Example Audit Event #
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "00000000-0000-0000-0000-000000000000",
"stage": "ResponseComplete",
"requestURI": "/api/v1/nodes/node-control-plane/status?fieldManager=kubectl-patch",
"verb": "patch",
"user": {
"username": "kubernetes-admin",
"groups": [
"kubeadm:cluster-admins",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"X509SHA256=97ca5ec05d5b7c1923d58d85f4449a4c26b2df61defa2a59b4045149ffed589e"
]
}
},
"sourceIPs": [
"203.0.113.10"
],
"userAgent": "kubectl/v1.36.2 (linux/amd64) kubernetes/24e2b02",
"objectRef": {
"resource": "nodes",
"name": "node-control-plane",
"apiVersion": "v1",
"subresource": "status"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestObject": {},
"responseObject": {
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "node-control-plane",
"uid": "00000000-0000-0000-0000-000000000000",
"resourceVersion": "1488",
"creationTimestamp": "2026-07-02T22:44:51Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/arch": "amd64",
"kubernetes.io/hostname": "node-control-plane",
"kubernetes.io/os": "linux",
"node-role.kubernetes.io/control-plane": ""
},
"annotations": {
"node.alpha.kubernetes.io/ttl": "0",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
}
},
"spec": {
"podCIDR": "10.244.0.0/24",
"podCIDRs": [
"10.244.0.0/24"
],
"providerID": "kind://docker/dw-k8s-harness/node-control-plane"
},
"status": {
"capacity": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"allocatable": {
"cpu": "18",
"ephemeral-storage": "514938800Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "128807008Ki",
"pods": "110"
},
"conditions": [
{
"type": "MemoryPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientMemory",
"message": "kubelet has sufficient memory available"
},
{
"type": "DiskPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasNoDiskPressure",
"message": "kubelet has no disk pressure"
},
{
"type": "PIDPressure",
"status": "False",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:44:50Z",
"reason": "KubeletHasSufficientPID",
"message": "kubelet has sufficient PID available"
},
{
"type": "Ready",
"status": "True",
"lastHeartbeatTime": "2026-07-02T22:49:19Z",
"lastTransitionTime": "2026-07-02T22:45:13Z",
"reason": "KubeletReady",
"message": "kubelet is posting ready status"
}
],
"addresses": [
{
"type": "InternalIP",
"address": "172.19.0.2"
},
{
"type": "Hostname",
"address": "node-control-plane"
}
],
"daemonEndpoints": {
"kubeletEndpoint": {
"Port": 10250
}
},
"nodeInfo": {
"machineID": "815df19d528a443e902d7ee3648f1bf5",
"systemUUID": "00000000-0000-0000-0000-000000000000",
"bootID": "00000000-0000-0000-0000-000000000000",
"kernelVersion": "6.1.0-41-amd64",
"osImage": "Debian GNU/Linux 13 (trixie)",
"containerRuntimeVersion": "containerd://2.3.1",
"kubeletVersion": "v1.36.1",
"kubeProxyVersion": "",
"operatingSystem": "linux",
"architecture": "amd64"
},
"images": [
{
"names": [
"docker.io/library/import-2026-06-02@sha256:48e12aa71c24cf624334ae6f0373f1e1b85825254085475eda149111a926e33c",
"registry.k8s.io/kube-apiserver-amd64:v1.36.1",
"registry.k8s.io/kube-apiserver:v1.36.1"
],
"sizeBytes": 96683252
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:3fb749e08554fac4cde5dc53397de761b92939d34ead7e3c89248a8bf5b621e4",
"registry.k8s.io/kube-controller-manager-amd64:v1.36.1",
"registry.k8s.io/kube-controller-manager:v1.36.1"
],
"sizeBytes": 85870692
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:834d6b8414308aed626e67979c4665f21b3651e5d8d04ae68d960a4f844b4e81",
"registry.k8s.io/kube-proxy-amd64:v1.36.1",
"registry.k8s.io/kube-proxy:v1.36.1"
],
"sizeBytes": 79126247
},
{
"names": [
"docker.io/library/import-2026-06-02@sha256:77add4a58677c7fa1a02b42381a024adc860f8d6bbdf38a89d7f8803c116e43c",
"registry.k8s.io/kube-scheduler-amd64:v1.36.1",
"registry.k8s.io/kube-scheduler:v1.36.1"
],
"sizeBytes": 60683997
},
{
"names": [
"docker.io/kindest/kindnetd:v20260528-9350166c"
],
"sizeBytes": 39749049
},
{
"names": [
"registry.k8s.io/coredns/coredns:v1.14.2"
],
"sizeBytes": 23257541
},
{
"names": [
"registry.k8s.io/etcd:3.6.8-0"
],
"sizeBytes": 22885795
},
{
"names": [
"docker.io/kindest/local-path-provisioner:v20260521-9fb22683"
],
"sizeBytes": 15864063
},
{
"names": [
"docker.io/kindest/local-path-helper:v20260131-7181c60a"
],
"sizeBytes": 2872608
},
{
"names": [
"docker.io/library/busybox@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662",
"docker.io/library/busybox:1.36"
],
"sizeBytes": 2217006
},
{
"names": [
"registry.k8s.io/pause:3.10"
],
"sizeBytes": 320368
}
],
"runtimeHandlers": [
{
"name": "",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "runc",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
},
{
"name": "test-handler",
"features": {
"recursiveReadOnlyMounts": true,
"userNamespaces": true
}
}
],
"features": {
"supplementalGroupsPolicy": true
},
"declaredFeatures": [
"ExtendWebSocketsToKubelet",
"InPlacePodLevelResourcesVerticalScaling",
"InPlacePodVerticalScalingInitContainers",
"RestartAllContainersOnContainerExits"
]
}
},
"requestReceivedTimestamp": "2026-07-02T22:49:28.602803Z",
"stageTimestamp": "2026-07-02T22:49:28.606679Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"kubeadm:cluster-admins\" of ClusterRole \"cluster-admin\" to Group \"kubeadm:cluster-admins\""
}
}
any verb on nodes (synthetic aggregation)
#Scope grouping: This repository-authored catalog entry represents a broad attribution scope, not a distinct emitted event or operation. Any sample below is a representative record from that scope; attached rules, if any, are listed separately.
Description
Synthetic aggregation for rules that filter the nodes resource with no specific verb. Not a distinct audit record; hosts rule listings that key on objectRef.resource alone.
Rule-derived Detection Fields #
Fields referenced by at least one attached detection rule. This view counts distinct rules and is not a complete schema for this catalog entry.
| Name | Rules | Vendors |
|---|---|---|
objectRef.resource | 1 detection rule | Elastic |
user.username | 1 detection rule | Elastic |
Detection Rules #
Full rule details for this catalog entry, including ATT&CK technique mappings and native queries → The rule groups Kubernetes audit Elastic #
get/list traffic across distinct API resource kinds that answer those questions (namespaces, workloads, roles, cluster-wide roles) is a common setup and orientation pattern for both interactive attackers and automated recon scripts. It is less typical for steady-state controllers, which usually touch a narrow set of resources repeatedly. This rule highlights that cross-resource burst from a single client fingerprint within a one-minute bucket so analysts can separate routine automation from potential discovery and permission reconnaissance ahead of follow-on actions.T1613Investigation guide
Triage and analysis#
Investigating Kubernetes Multi-Resource Discovery#
get/list events on namespaces, pods, roles, and clusterroles into one-minute windows per user.name, source.ip, user_agent.original, and flags windows where three or more distinct resource types appear. That combination is consistent with someone sketching cluster layout and privilege structure rather than touching a single resource type. Allowed and denied authorizations are both included: failures still signal probing and validate which object types the caller attempted to reach.Possible investigation steps#
Esql.time_interval and the same identity or IP in raw audit logs to see ordering (e.g. namespaces first, then roles, then pods) and whether calls succeeded.Esql.decisions and namespaces touched; correlate with RBAC for that identity to see if scope matches a known job or breaks least-privilege expectations.False positive analysis#
Response and remediation#