Securing Docker containers - part II
Container runtimes like Docker and K8s are not entirely secure by default, so extra effort is required by devops engineers. This is the second in a series of blog posts with practical advise on how to reduce your container’s attack surface by revoking service
In the first post we saw there are fundamental differences between VMs and containers, and DevOps engineers should take active measures to improve container runtime security. And specifically how to mount a container image read-only at runtime to make it default immutable, and handling temporary and persistent volumes.
Another interesting default for containers is that Docker and K8s runs with
root privileges. Not just inside the
container, but also on the host.
Without containers, you would probably not be running your services as
root. That is because you want to limit the
blast radius from vulnerabilities in your service. For the exact same reason, containers should run as a user with the
least privileges possible.
If an attacker manage to exploit a container escape volunerability to access the host, they would have complete control over the host to deploy persistent backdoors, clean up audit logs.
Dockerfile can specify a low privilege user to be used to run the service. The following snippet from a
Aspnet Core service create a new
appuser that owns the
app directory, where the service binaries are deployed. The
USER command drops
root privileges by changing to
appuser security context.
The image is Alpine-based.
WORKDIR /app RUN adduser -D appuser && chown -R appuser /app COPY --chown=appuser:appuser --from=publish /app/publish . USER appuser
Developers tend to follow the path of least resistance, so default insecure behavior completely dominate public images on Docker Hub.
While the container process has now dropped the
root privileges, the runtime daemon is still default executing as
root. The container community is working on changing this behavior but at the time of writing it still “experimental”,
i.e. has some road ahead to go before it can become default.
- To run a rootless Docker daemon please refer to https://docs.docker.com/engine/security/rootless/
- Kubernetes has a “usernetes” initiative going on at https://github.com/rootless-containers/usernetes
The community is also working on splitting build tools from the Docker daemon. If you want to run rootless build
pipeline have a look at Podman and Buildah. Note the latter use an
Dockerfile-syntax to build OCI compliant container images.
This blog post displayed a big issue with container default privileges and how to fix it by dropping
unprivileges user to reduce the blast radius of your container.