Manipulating Signed Docker Images
Docker Content Trust (DCT) is Docker’s mechanism for code signing. Developers can sign images they create and people using these images can verify if they have been manipulated somewhere on their way from the developer to the docker host.
Recently we looked at DCT more closely and were surprised to find out that signed images can be manipulated locally on a docker host!
We will give you a short proof-of-concept. We did our tests using Docker 19.03.5 (both, server and client).
First we check that DCT is enabeld and the alpine:latest image is digitally signed:
root@ubuntu:~# echo $DOCKER_CONTENT_TRUST 1 root@ubuntu:~# notary -s https://notary.docker.io -d ~/.docker/trust/ list docker.io/library/alpine | grep latest latest 2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 1638
Next, we pull the signed alpine image:
root@ubuntu:~# docker pull alpine:latest Pull (1 of 1): alpine:latest@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78: Pulling from library/alpine e6b0cf9c0882: Pull complete Digest: sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 Status: Downloaded newer image for alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 Tagging alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 as alpine:latest docker.io/library/alpine:latest
Here we manipulate the image and add a new file:
root@ubuntu:/var/lib/docker/overlay2/488bf1a003eb59f32d2783b8b9cdddb73948fa9553384560e7073e36b3cbf862/diff# cat > testfile.txt This file changes the image and should invalidate the signature ^C root@ubuntu:/var/lib/docker/overlay2/488bf1a003eb59f32d2783b8b9cdddb73948fa9553384560e7073e36b3cbf862/diff# ls bin etc lib mnt proc run srv testfile.txt usr dev home media opt root sbin sys tmp var
We expected a signature verification error when we try to run this manipulated image. But as you can see, nothing happens and docker starts the manipulated container:
root@ubuntu:~# docker run -it alpine:latest /bin/sh / # ls bin lib proc srv usr dev media root sys var etc mnt run testfile.txt home opt sbin tmp / # cat testfile.txt This file changes the image and should invalidate the signature
Assuming this is vulnerability, we contacted the Docker security team and were told that this is works-as-designed. This is because the packed image is digitally signed. After the image is pulled, it gets unpacked and there is no signature for the unpacked version. So, the threat model of DCT is mainly about the registry being compromised.
However, one would generally assume that image signing is an end-to-end security mechanism protecting the image from the time it is signed until the time it is started. Also the documentation is not very clear about that and says that signatures are verified upon docker run. But, actually protection stops as soon as the image is pulled on the docker host.
We created a pull request to update the Docker documentation and make this a bit clearer.