Kubernetes security in practice: implications of running containers as root

Introduction

In the world of Kubernetes security, one commonly heard recommendation is to run containers as non-root users. This best practice is often emphasized in Docker images and Kubernetes configurations. In Kubernetes manifests it can be done with the following code:

securityContext: runAsUser: 1000 # Override to a non-root user
Enter fullscreen mode Exit fullscreen mode

But what are the real security implications of running as root within containers?

Let’s explore practical experiments.

Why running as root in containers can be dangerous? ⚠️

There are several potential attack vectors, but the most apparent ones that come to mind are outlined below. Let’s explore these through experimentation.

Setting up the lab 🛠️

To illustrate the risks of running containers as root, we’ll conduct a practical test using two similar containers:

  1. An alpine:3.20.2 container running as root by default.
  2. A custom alpine:3.20.2 container configured to run as a non-root user.

Here’s the Dockerfile for the non-root container:

# Use the Alpine image as the base
FROM alpine:3.20.2 # Add a non-root user named 'nonroot' with user ID 1000
RUN adduser -D -u 1000 nonroot # Set the user to 'nonroot' for subsequent commands
USER nonroot # Optional: Set a default command
CMD ["sh"] 
Enter fullscreen mode Exit fullscreen mode

Using Minikube 1.32.0 for my local setup, I build the image and make it accessible to my Minikube cluster with:

eval $(minikube docker-env)
docker build . -t nonroot:1.0.0 
Enter fullscreen mode Exit fullscreen mode

Next, I deploy these containers in Kubernetes. For this demonstration, I use a hostPath volume to test privileges, though I strongly advise against using hostPath outside your homelab! The root pod definition is:

apiVersion: v1
kind: Pod
metadata: name: root
spec: containers: - name: alpine image: alpine:3.20.2 command: ["/bin/sh", "-c"] args: ["while true; do sleep 100; done"] volumeMounts: - mountPath: /data name: host volumes: - name: host hostPath: path: /testDir type: Directory
Enter fullscreen mode Exit fullscreen mode

And the nonroot pod definition is:

apiVersion: v1
kind: Pod
metadata: name: nonroot
spec: containers: - name: alpine image: nonroot:1.0.0 command: ["/bin/sh", "-c"] args: ["while true; do sleep 100; done"] securityContext: runAsUser: 1000 # Ensure the container runs as non-root user with UID 1000 volumeMounts: - mountPath: /data name: host volumes: - name: host hostPath: path: /testDir type: Directory
Enter fullscreen mode Exit fullscreen mode

Testing potential attacks 🧪

Downloading malware 🦠

One common attack vector is downloading and executing malicious packages. I tested this by attempting to just fetch some data from https://dev.to.

Attempt to run curl

Since curl was not initially installed in the containers, I tried to install it:

Installing curl in containers

The installation succeeded in the root container but failed in the nonroot. Let’s try to fetch the data.

Fetching the data

It worked correctly. This indicates that running as a non-root user can effectively mitigate this attack vector. Of course, other measures, such as using a read-only filesystem, can further enhance security. I will cover that in a future article.

Access to host resources 🔒

I have a host directory mounted to the pod (again – please do not do that outside of your homelabs!). With this kind of access attacker can try to access the directory with the static pods manifests and try to run the malicious pods (downloading malicious images should be blocked by your cluster policies though). Another thing that attacker can try to do is to access /etc/passwd file on the host machine. This file does not contain the password in plain text, but it gives attacker a knowledge about users existing in a system. This knowledge combined with some other data sources may let the attacker exploit the system further.

Privilege Escalation 🚫

Can’t you just change the non-root user to root and do exactly the same? Let’s try it.

Trying to switch to root

No, you can’t. The attempt to switch from non-root to root failed, demonstrating that without sudo access, privilege escalation is not feasible. Therefore, if a non-root user isn’t in the sudoers list, the risk is mitigated.

How to prevent? 🛡️

To prevent security issues related to running containers as root, follow these best practices:

  1. Use non-root users: Always define and use non-root users in your Docker container. 🧑‍💻
  2. Leverage Kubernetes Security Context: Specify the user for container execution using Kubernetes security contexts. 🔐

Conclusion ✨

I hope this article has shed light on the importance of running containers as non-root users within Kubernetes.

I’d love to hear your thoughts and insights – drop a comment below or share your feedback! Stay tuned for more insights as I continue to explore and describe various aspects of Kubernetes security.

Stay secure!🔐

References

  1. Understanding the Docker USER instruction
  2. Kubernetes Security Context
  3. Alpine Docker images on Docker Hub

Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top