Unauthorized Kubelet API Or Proxy Access
Query
let Lookback = 1d;
let AllowedNamespaces = dynamic(["kube-system", "calico-system", "gatekeeper-system", "monitoring"]);
let AllowedImages = dynamic(["prometheus", "metrics-server", "node-exporter", "kube-state-metrics", "otel", "datadog", "dynatrace"]);
let AllowedProxyIdentities = dynamic(["system:serviceaccount:monitoring:prometheus"]);
let ClassifyEndpoint = (s:string) {
case(s has_any ("/run/", "/exec/", "/attach/", "/portforward/"), "RemoteExec",
s has_any ("/runningpods", "/pods"), "PodDiscovery",
s has_any ("/containerlogs/", "/logs/"), "LogAccess",
s has_any ("/configz", "/debug/", "/checkpoint/"), "ConfigOrDebug",
"Other")
};
let FromPod = CloudProcessEvents
| where Timestamp > ago(Lookback)
| where isnotempty(KubernetesPodName) and ContainerName != "host"
| where KubernetesNamespace !in (AllowedNamespaces)
| where not(ContainerImageName has_any (AllowedImages))
| extend Cmd = tolower(ProcessCommandLine)
| where Cmd matches regex @":1025[05]\b" or Cmd has "kubeletctl"
| where not(Cmd has_any ("/metrics", "/stats/summary", "/healthz"))
| project Timestamp, Source = "PodToKubelet", AzureResourceId, Identity = strcat(KubernetesNamespace, "/", KubernetesPodName),
Detail = ProcessCommandLine, Endpoint = ClassifyEndpoint(Cmd), ContainerImageName, ParentProcessName, HostName;
let ViaApiServer = CloudAuditEvents
| where Timestamp > ago(Lookback)
| where DataSource =~ "Kubernetes Audit"
| extend Resource = tolower(tostring(RawEventData.objectRef.resource)),
SubResource = tolower(tostring(RawEventData.objectRef.subresource))
| where Resource == "nodes" and SubResource == "proxy"
| extend User = tostring(RawEventData.user.username),
RequestUri = tolower(tostring(RawEventData.requestURI)),
Code = toint(RawEventData.responseStatus.code)
| where not(User startswith "system:") or User startswith "system:serviceaccount:"
| where User !in (AllowedProxyIdentities)
| where not(RequestUri has_any ("/metrics", "/stats/summary", "/healthz"))
| project Timestamp, Source = "NodesProxyViaApiServer", AzureResourceId, Identity = User,
Detail = strcat(tostring(RawEventData.verb), " ", RequestUri, " (", Code, ")"),
Endpoint = ClassifyEndpoint(RequestUri), SourceIp = tostring(RawEventData.sourceIPs[0]);
union FromPod, ViaApiServer
| extend Severity = case(Endpoint == "RemoteExec", "High",
Endpoint in ("PodDiscovery", "ConfigOrDebug", "LogAccess"), "Medium",
"Low")
| where Severity != "Low"
| order by Timestamp descAbout this query
Unauthorized Kubelet API or Proxy Access
Query Information
MITRE ATT&CK Technique(s)
| Technique ID | Title | Link |
|---|---|---|
| T1613 | Container and Resource Discovery | https://attack.mitre.org/techniques/T1613 |
| T1611 | Escape to Host | https://attack.mitre.org/techniques/T1611 |
Description
Detects unauthorized attempts to interact with the Kubelet API directly from pods or via the Kubernetes API server proxy. This includes potential remote execution, container discovery, log access, or debug/config endpoint access by non-authorized service accounts or processes, which may indicate container breakout attempts or lateral movement within a cluster.
Author <Optional>
- Name: Benjamin Zulliger
- Github: https://github.com/benscha/KQLAdvancedHunting
- LinkedIn: https://www.linkedin.com/in/benjamin-zulliger/
Defender XDR
Explanation
This KQL query is designed to detect unauthorized access attempts to the Kubelet API or through the Kubernetes API server proxy. Here's a simplified breakdown:
-
Purpose: The query aims to identify potential security threats within a Kubernetes environment, specifically unauthorized interactions with the Kubelet API, which could indicate attempts at remote execution, container discovery, or other malicious activities.
-
Lookback Period: The query examines events from the past day (
1d). -
Allowed Entities: It defines lists of allowed namespaces, container images, and proxy identities to filter out legitimate activities:
- AllowedNamespaces: Namespaces like "kube-system" and "monitoring" are considered safe.
- AllowedImages: Images such as "prometheus" and "datadog" are allowed.
- AllowedProxyIdentities: Specific service accounts like "system:serviceaccount:monitoring:prometheus" are permitted.
-
Endpoint Classification: The query categorizes endpoints based on the type of access:
- RemoteExec: Indicates potential remote execution attempts.
- PodDiscovery: Involves discovering pods.
- LogAccess: Accessing container logs.
- ConfigOrDebug: Accessing configuration or debug endpoints.
-
Detection from Pods: It checks for unauthorized commands executed from within pods that are not in allowed namespaces or using allowed images. It looks for specific command patterns that suggest unauthorized Kubelet API access.
-
Detection via API Server: It also monitors Kubernetes audit logs for unauthorized proxy access through the API server, filtering out allowed identities and benign requests.
-
Severity Levels: The query assigns severity levels to the detected activities:
- High: For remote execution attempts.
- Medium: For pod discovery, config/debug access, or log access.
- Low: Other activities, which are filtered out.
-
Output: The results are sorted by timestamp, showing the most recent unauthorized access attempts first, excluding low-severity events.
In summary, this query helps security teams identify and respond to unauthorized access attempts to critical Kubernetes components, potentially indicating security breaches or lateral movement within the cluster.