Note perev. : This note was written by an IT security researcher from Aqua Security, a company specializing in DevSecOps. She is an excellent illustration of the subtleties in Kubernetes configuration that it is important to always keep in mind when serving clusters in production. Of course, if you think about their safety ...
Kubernetes consists of many components, and sometimes combining them in a certain way leads to unexpected results. In this article I will show how a pod launched with root privileges and a mounted
/var/log
directory of a node can
expand the contents of the entire host file system to a user with access to his logs. We will also discuss solutions to this problem.
How Kubernetes sees logs
Have you ever wondered how
kubectl logs <pod_name>
extracts logs from pod? Who is responsible for collecting logs from containers? And how do they get to your computer?
The following diagram illustrates the process:
Kubelet creates a structure inside the
/var/log
directory on the host that represents the pods on the host. There is a file
0.log
(1) in the directory for our
0.log
, but in fact it is a symlink to the container log located in
/var/lib/docker/containers
. This is all from the point of view of the host.
Kubelet opens endpoint
/logs/
(2), which simply works with the HTTP file server in directory (3), making logs available for requests coming from the API server.
Now imagine that we deployed pod with
hostPath
mounted in
/var/log
. Such a pod will have access to all the log files on the host. Although this in itself is a potential problem, we can take the next logical step. What if we replace
0.log
with a symlink to ... say,
/etc/shadow
?
β βββ var β βββ logs β β βββ pods β β β βββ default_mypod_e7869b14-abca-11e8-9888-42010a8e020e β β β β βββ mypod β β β β β βββ 0.log -> /etc/shadow β β β β β β
Now, trying to download the logs using
kubectl logs
on the client machine, we get:
$ kubectl logs mypod failed to get parse function: unsupported log format: "root:*:18033:0:99999:7:::\n"
Kubelet follows the link and reads the contents of the file that it points to (it can be any file on the node).
Since JSON was expected, kubectl crashed after the first line, however, we can easily read the specific lines of the
shadow
file by running the command with the
β-tail=-<line_number>
.
This is amazing. Since kubelet follows the symlink, you can use its root privileges to read any file on the node, simply creating a symbolic link inside the pod.
Escape from the pod
Let's go even further. We know that when a pod is launched in Kubernetes, the ServiceAccount token is installed in it. Thus, if the service account allows access to the logs, we can directly access the kubelet and root privileges on the node.
I wrote a proof of concept (POC) demonstrating this attack vector:
- deployment of pod with mount point
/var/log
; - creating a symbolic link to the root directory of the host;
- reading the user's ssh private key on the host.
The
following video shows two specific commands that run inside a pod:
-
lsh == ls
(on the host file system); -
cath == cat
(on the host file system).
Note perev. : Unfortunately, the insertion of content with asciinema was never repaired on the hub, although we have already addressed this problem, therefore we are forced to βembedβ the video with the simple link above.
All files involved in this POC can be found in the
corresponding GitHub repository . There is another POC script that automatically collects private keys and ServiceAccount tokens from the host file system.
Mounting directories can be dangerous
So is this a vulnerability or just bad practice?
Deploying a pod with a write-open
hostPath
in
/var/log
is rare (in addition, there are other ways to abuse the mounting of host secret directories in pod). But even if you knew that mounting
/var/log
was a dubious practice, you probably did not expect it to allow you to take over the node with such ease.
Before publishing, we contacted the Kubernetes security team to find out if they consider this a vulnerability. They concluded that this was just a sad consequence of mounting a private host directory with write permissions: the risks involved are well
documented . However, this vulnerability is quite easy to exploit. In the world there are
many projects that use this mount. If you are using one of these projects, remember that your deployment will be vulnerable to this way of hijacking the host.
This method has been tested on Kubernetes 1.15 and 1.13, but most likely affects other versions.
Elimination
Such an βescapeβ is only possible if pod is running as root. This
should generally
be avoided . Aqua CSP allows you to set a policy with a minimum of effort that prevents containers from running as root or grants permissions only to a specific group of images that really require root.
Another way is to simply not deploy pods with
hostPath
with write permissions in
/var/log
. This approach is not set by default and is not a usual practice, therefore it is necessary to consciously determine it (however, the possibility still remains). But how to check?
We added a new script (hunter) to
kube-hunter - our lightweight Open Source tool for testing Kubernetes - which checks the cluster for pods with such dangerous mount points.
( Note : Kube-hunter was present in a recent review of K8s security utilities that we posted on our blog.)
Aqua users can protect themselves from this risk by using the runtime policy to prevent certain volumes from being mounted:
Note perev. : Part of this problem can be solved using Pod Security Policies , namely AllowedHostPaths
. However, this is also not protection against symlinks. Finally, as the comments suggest, we can simply limit the launch as root, again guided by the PSP .
Total
Kubernetes is a complex system with a lot of subtleties in security settings, which are not always obvious to the average and even experienced user. In this article, I have shown how, under certain circumstances, innocent logging can lead to potential vulnerability. In most cases, this is not possible, but Kubernetes offers users greater freedom of action that may affect security. It is important to keep this in mind and implement appropriate controls to prevent such errors.
PS from the translator
Read also in our blog: