When you’re building your container image there are at least two effortless practices that you can follow:
- Prefer minimal base images
- Run process with Least privileged user
Prefer minimal base images
Base images not only help speed up your CI/CD pipelines, reduce storage space and network traffic. They also help you reduce the attack surface of your container.
Your container should only have the dependencies that it needs to run and nothing more.
I know, we all love to ssh into the container and use vim, ping, or some other tool to debug it. But being lazy can get us into trouble very quickly 😊.
Explore the following base image options:
- Scratch If you are going to run a binary that doesn’t need any other libs (GO programs for example).
- Alpine The image is only 5 MB in size and has access to a package repository to install what you need.
- If you want/need more, you can also try images with -slim version or even with -alpine.
Run process with Least Privileged User
Your process inside the container shouldn’t run as root unless is mandatory.
Having a process running as root means that an attacker could gain root access and perform an attack on the host.
Imagine that someone mounts a volume to the container and an attacker was able to gain access to the container by the process running as root. They would be able to manipulate that external volume with no issues at all.
What if that container has been launched using --privileged
flag?
The –privileged flag gives all capabilities to the container. When the operator executes docker run –privileged, Docker will enable access to all devices on the host as well as set some configuration in AppArmor or SELinux to allow the container nearly all the same access to the host as processes running outside containers on the host. Additional information about running with –privileged is available on the Docker Blog. https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
As you can see, potential issues begin to emerge very quickly.
How do you run a process as non-root?
In your Dockerfile
make sure you create a new regular user and then activate it.
Here’s an example of how it can be done
...
# crate a non-root user
ENV NONROOT_USER myappser
ENV NONROOT_UID 1000
ENV HOME /app
RUN adduser --disabled-password \
--gecos "Default user" \
--uid ${NONROOT_UID} \
${NONROOT_USER}
USER root
# all files in the home folder will
# be owned by the non-root user
RUN chown -R ${NONROOT_USER}:${NONROOT_USER} ${HOME}
USER ${NONROOT_USER}
# You can add your CMD after this if you want to
...
Photo credit: Francesco Ungaro