Kubernetes API Visibility Gaps Can Hide Non-Standard Pods and Containers

Summary
Kubernetes API queries may miss some static and pause containers. The article explains how to identify other non-standard pods and containers and how attackers could abuse these visibility gaps for stealth or persistence.
Key points
- Static pods are managed by the kubelet, not the Kubernetes API; mirror pods can make them visible when kubelet reporting is configured.
- Attackers with access to a static pod manifest location could create privileged pods or alter existing static pods for stealthy persistence.
- Init containers appear under spec.initContainers and should be monitored because they can affect application setup.
- Pause containers are not reported through the Kubernetes API; identifying them requires node-level access and querying the container runtime.
- The article demonstrates how replacing the kubelet’s pause-container image could cause an attacker-controlled container to run with each new pod on that node.
- Ephemeral containers can be attached to running pods for debugging and may provide access to pod data and secrets; they appear under ephemeralContainers.
- The article recommends supplementing Kubernetes API monitoring with workload runtime agents and checking which users can attach ephemeral containers in production.
Article Details
- Defense Focus
- Improve visibility into Kubernetes pods and containers that the Kubernetes API may omit, and detect anomalous use of them for stealth or persistence.
- Detection Methods
- Inspect kubelet command-line arguments and configuration for static pod manifest locations and reporting settings.
- Identify mirror pods through their ownerReferences.kind attribute and distinguish them from other pods.
- Review pod specifications for initContainers and ephemeralContainers, and compare them with expected deployment contents.
- Use node-level access to query the container runtime for pause containers that are not visible through Kubernetes clients.
- Check the configured pause-container image, its source, and whether it has changed.
- Data Sources
- Kubernetes API workload and pod objects
- Pod specification fields, including containers, initContainers, and ephemeralContainers
- Pod status
- Kubelet command line and configuration file
- Node-level container runtime inventory
- Rule Types
- kubectl queries using jq filters over Kubernetes JSON output
- kubectl JSONPath queries
- Platforms
- Kubernetes clusters
- Kubernetes nodes and their container runtimes
- Defensive Actions
- Do not rely solely on the Kubernetes API for complete pod and container visibility; supplement it with workload runtime agents.
- Monitor static pod manifest locations and determine whether kubelets report static pods through mirror pods.
- Review static pods for unexpected privileged settings or added containers, including changes to existing pods such as kube-proxy.
- Investigate unexpected pause-container images or changes to the configured image.
- Monitor init containers for unexpected setup activity.
- Restrict and review who can attach ephemeral containers to production pods.
MITRE ATT&CK
T1610 · Deploy ContainerThe article describes attackers creating static pods or using an attacker-controlled pause-container image to run containers on a Kubernetes node.T1611 · Escape to HostThe article says an attacker with access to a static pod manifest path or URL could create a privileged static pod for an escape-to-host attack.
People
Vendors
Amazon Web ServicesFirst, we identify the current pod infra container that is specified by inspecting the kubelet daemon on the AWS EKS node. This requires node-level access or a pod that allows movement to the node.GoogleOn a default Google Kubernetes Engine (GKE) setup the kubelet config path is configured at /home/kubernetes/kubelet-config.yaml to monitor the /etc/kubernetes/manifests path.
Products
AWS EKSFirst, we identify the current pod infra container that is specified by inspecting the kubelet daemon on the AWS EKS node. This requires node-level access or a pod that allows movement to the node.DockerTo replace the existing pause image, the new image must specify a default command in its Docker file, and this intended process should be long-lived by default.Google Kubernetes EngineOn a default Google Kubernetes Engine (GKE) setup the kubelet config path is configured at /home/kubernetes/kubelet-config.yaml to monitor the /etc/kubernetes/manifests path.KubernetesThe adoption rate of Kubernetes is a testament to the benefits it provides to CI/CD pipelines, such as faster build and deployment times. According to the Cloud Native Computing Foundation, 96% of organizations are
Tools
jqkubectl get pods --all-namespaces -o json | jq -r '.items | map(select(.metadata.ownerReferences[]?.kind == "Node" ) | .metadata.name) | .[]'kubectlAPI for existing workload resources such as pods, deployments or by directly querying pods via kubectl get and describe commands. Standard containers can usually be identified in the spec.container key when