Containers have revolutionized the tech industry in recent years for many reasons. Because of their properties of encapsulating dependencies into a portable container image, many organizations have adopted them as the primary method of developing, building, and deploying production applications.
As a Software Engineer and a Security Engineer, I cannot even begin to express my excitement for the game-changing potential of containers and orchestrators, namely Kubernetes. However, due to the chaotic (good) nature of open-source and the speed by which projects move and evolve, many organizations are simply unable or unequipped to properly secure these technologies.
This article aims to provide a list of common security mistakes and security best-practices/recommendations in 2018.
In the next article, I will offer the same insights for Kubernetes.
Legend:
Icon | Meaning |
---|---|
β | Not Recommended |
ποΈ | Rationale |
β | Recommendation |
β Running Docker on an unsecured, unhardened host
ποΈ Docker is only as secure as the underlying host
β
Make sure you follow OS security best-practices to harden your infrastructure. If you dole out root
access to every user in your organization, then it doesnβt matter how secure Docker is.
β The Center for Internet Security (CIS) puts out documents detailing security best-practices, recommendations, and actionable steps to achieve a hardened baseline. The best part: theyβre free.
β Better yet, docker-bench-security is an automated checker based on the CIS benchmarks.
# recommended
$ docker run \
-it \
--net host \
--pid host \
--userns host \
--cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /var/lib:/var/lib \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib/systemd:/usr/lib/systemd \
-v /etc:/etc --label docker_bench_security \
docker/docker-bench-security
Docker Engine is an API that listens for incoming requests and, in turn, interfaces with the underlying host kernel to accomplish its job. Docker Engine supports communications on 3 different sockets: unix
, tcp
, and fd
.
β Running Docker Engine (aka the Docker daemon, aka dockerd
) on tcp
or any networked socket
ποΈ If anyone can reach the networked socket that Docker is listening on, they potentially have access to Docker and, since Docker needs to run as root, to the underlying host
β
The default docker behavior today is the safest assumption, which is to listen on a unix
socket
# not recommended
$ dockerd -H "tcp://1.2.3.4:8080"
# recommended
$ dockerd -H "unix:///var/run/docker.sock"
β Mounting the Docker socket into the container
ποΈ Mounting /var/run/docker.sock
inside the container is a common, yet very dangerous practice. An attacker can execute any command that the docker service can run, which generally provides access to the whole host system as the docker service runs as root.
β
Short of just saying βDonβt mount the docker socketβ, carefully consider the use-cases that require this giant loophole. For example, many tutorials for running a Jenkins master in a container will instruct you to mount the docker socket so that Jenkins can spin up other containers to run your tests in. This is dangerous as that means anyone can execute any shell commands from Jenkins to gain unauthorized access to sensitive information or secrets (e.g. API tokens, environment variables) from other containers, or launch privileged containers and mount /etc/shadow
to extract all usersβ passwords.
# not recommended
$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock ubuntu /bin/bash
β Running privileged containers
ποΈ Containers would have full access to the underlying host
β If needed by a container, grant it only the specific capabilities that it needs
# not recommended
$ docker run -d --privileged ubuntu
# recommended
$ docker run -d --cap-add SYS_PTRACE ubuntu
β Running containers as root users
ποΈ This is a system administration standard best-practice. There is little to no reason for running software in containers as root
.
β Run containers as non-root users
# not recommended (runtime example)
$ docker run -d ubuntu sleep infinity
$ ps aux | grep sleep
root ... sleep infinity
# recommended (runtime example)
$ docker run -d -u 1000 ubuntu sleep infinity
$ ps aux | grep sleep
1000 ... sleep infinity
# recommended (build-time example)
FROM ubuntu:latest
USER 1000
β Pulling and running containers from public registries
ποΈ Recently, security researchers found 17 cryptomining containers on Docker Hub
β Scan container images to detect and prevent containers with known vulnerabilities or malicious packages from getting deployed on your infrastructure
β Sign container images
β
Attach seccomp
, apparmor
, or selinux
profiles to your containers
seccomp
, apparmor
, and selinux
add stronger security boundaries around the container to prevent it for making a SYSCALL it is not explicitly allowed to makeβ Monitor, detect, and alert on anomalous, suspicious, and malicious container behavior
β Consider running containers in a container runtime sandbox, like gvisor
Container technology is not inherently more or less secure than traditional virtualization technologies. Containers are enabled by Linux features, such as namespace isolation and cgroups to control to control system resources. Securing container workloads and the systems underneath them require an understanding of Linux as a platform.