Red Green Repeat Adventures of a Spec Driven Junkie

Testing Docker Image Secrets

I was looking into solutions into using a Dockerfile to build a Docker image while secrets inside the build process, like a private SSH key, which is typically used to pull code from private repositories.

Top
Secret

This post mentions different solutions on how to use a secret key in a Docker image build:

  • include the ssh key, then remove the file
  • same as above, but use the --squash option when building

After reading these, I had the idea of using a ramdisk for the Docker image build process to see if that would prevent writing the secret to the Docker image during the build process.

Long story short: I wasn’t able to get a ramdisk setup in the Docker image build, so the build would not complete. :-/

tmpfs Docker Errors

The error I encountered when trying to mount the tmpfs sytem is:

Step 3/5 : RUN mount -t tmpfs -o size=512k tmpfs /mnt/ramdisk
---> Running in 56570970c119
mount: permission denied
The command '/bin/sh -c mount -t tmpfs -o size=512k tmpfs /mnt/ramdisk' returned a non-zero code: 32

I think there is an incompatibility with how the filesystem is already setup in Docker in a container or during a build. Docker may be using a combination of tmpfs and ext4 to abstract filesystems already, so another tmpfs might not be possible.

If you know of how to get tmpfs going in a Dockerfile, I would [love to hear from you](http://redgreenrepeat.com/contact]!!!

Skills Gained

Although my idea didn’t work out, One thing I did learn is how to work with Docker images at the file level and test out my hypothesis by searching through the Docker image.

Instead of just letting this information disappear as part of the experiment, I will write it up so others can use the techniques if anything ever changes in the future.

Requirements

If you would like to follow along and test out my work, these are the tools I used in this experiment:

I have included a script that will generate all the files needed at this git repository.

Docker Image, where art tho?

Accessing a Docker image locally is pretty tricky because of the abstractions used. Docker images are not written to the filesystem of the host computer directly, but into a virtual file for all the images.

To extract the image from the virtual file, this is the command:

$ docker save -o <output filename> <image ID>

source

This is the easiest way to put a local Docker image into a file that is easily accessible on the filesystem. I want to do this so I can perform a search inside the file.

Searching Docker Image

To test whether a string is in the Docker image or not, I had to scan inside the image. To do this, I use my favorite file scan tool: ag.

$ ag --search-binary "<string>" file

This allows ag-the-silveer-searcher to search inside a binary file for a string that matches.

Searching with grep

To search binary files with grep, the command is:

$ grep -ali -- "SUPER_SECRET_FILE_CONTENTS" images/*

source

Testing Script

I wrote a script to generate all the Docker images, make them accessible, and search through them to verify whether a string matches or not.

#!/usr/bin/env bash

content=SUPER_SECRET_FILE_CONTENTS
secret_file=super_secret_file

echo $content > $secret_file

docker build -f dockerfile_no_write              -t image_no_write                              .
docker build -f dockerfile_with_write            -t image_with_write                            .
docker build -f dockerfile_with_write_and_delete -t image_with_write_and_delete                 .
docker build -f dockerfile_with_write_and_delete -t image_with_write_delete_and_squash --squash .

mkdir images

docker save -o images/image_no_write                     image_no_write
docker save -o images/image_with_write                   image_with_write
docker save -o images/image_with_write_and_delete        image_with_write_and_delete
docker save -o images/image_with_write_delete_and_squash image_with_write_delete_and_squash

echo "====== searching through images ======"
ag --search-binary $content images

Results

Going through known methods of creating an image with a secret and searching for it in cases where it was not written, written, written then removed, and then squashed:

docker image creation text found in docker image?
image without secret written no
image with secret written yes
image with secret written then removed yes
image with secret written, removed, and squashed yes

From the above table, the secret is in the file whenever the Dockerfile COPY the file to the Docker image, even when using the --squash option.

The CMD rm <file> option does not help, the file still remains in the image.

This demonstrates that even when removing the secret directly or using the --squash, a quick scan finds the secret in the image file.

Conclusion

Do not store sensitive information in a Docker image file. The image will always have the information and is accessible.

Althought my initial idea of using an in-memory file system like tmpfs did not work out, I found a great process to validate my hypothesis, which I will use whenever I figure out another way to solve it.

This was a great way in learning how to work with Docker images, creating them with options, and testing my hypothesis on image contents.