Secure filesystem in docker
I wanted to explore docker container security, so I started out with looking at filesystem security. This is what I learned!
Read-only filesystem in docker
One can start a container with
docker run --read-only to make the whole container read-only. This is great if you know the container won't need to write anything so use this whenever you can.
Here is an example:
$ docker run \ --rm \ --read-only \ busybox touch /tmp/hello touch: /tmp/hello: Read-only file system
Allow write on specific paths
Some containers require writable paths for temporary data, for that, we can use the
--tmpfs flag to mount a writable path.
Allow writes to
$ docker run \ --rm \ --read-only \ --tmpfs /tmp \ busybox touch /tmp/hello
No errors this time, so it works as intended!
Limit write size
A malicious actor could put fishy stuff in the writable paths, so no reason to allow for more space than we need.
size=64K to limit the writable disk space to 64 KB:
$ docker run \ --rm \ --read-only \ --tmpfs /tmp:size=64k \ busybox sh -c "dd if=/dev/zero of=/tmp/hello bs=1MB count=1; du -h /tmp/hello" dd: error writing '/tmp/hello': No space left on device 1+0 records in 0+0 records out 65536 bytes (64.0KB) copied, 0.000302 seconds, 207.0MB/s 64.0K /tmp/hello
As you can see the command fails and the file is only 64KB rather than the 1MB we asked for.
By default docker mounts tmpfs with:
noexec- forbids any binaries in the mount point to be executed
nosuid- ignores the
setgidbits on binaries, which prevents privilege escalations
nodev- ignores device files
You can verify this by running
mount in the container.
Figure out where write access is needed
Start a container without
--read-only and run
docker diff on it:
$ docker diff $(docker run -d busybox sh -c "mktemp; rm /bin/df") C /bin D /bin/df C /tmp A /tmp/tmp.gi3M65
A- added file/directory
C- changed file/directory
D- deleted file/directory
This shows what has changed on the filesystem since the container started. This method isn't foolproof though. It doesn't catch modified files even if it seems to indicate so.
$ docker diff $(docker run -d busybox sh -c "echo hello > /etc/hosts")
This won't show any diff at all. If we instead delete a file and create a new file with the same name, it'll show up as changed.
$ docker diff $(docker run -d busybox sh -c "rm /bin/df; touch /bin/df") C /bin C /bin/df
Another way is the good ol' trial and horror! Run the container with a read-only filesystem and see what makes your program crash, and iterate that way.