Secrets management in Docker is not fun. I've taken a couple of approaches in the past.
1) Store the secret in a file that is ignored by Git by adding a reference in .gitignore. Declare a build arg in the Dockerfile and inject the file path into the arg at build time. Instruct Docker to copy the file into the image. Remove the file when it's no longer necessary. Note that the key file must reside at location with the Docker context, so that usually means no higher than the project root. This approach is useful for a local development environment because you can avoid needing to set an environment variable again and again.
Dockerfile
FROM node:8.7.0
ARG GITLAB_KEY_FILE
RUN mkdir -p /keys
ADD $GITHUB_KEY_FILE /keys/gitlab_rsa
RUN \
chmod 600 /keys/gitlab_rsa && \
eval $(ssh-agent) && \
ssh-add /keys/gitlab_rsa && \
mkdir ~/.ssh && \
ssh-keyscan gitlab.com >> ~/.ssh/known_hosts && \
## Do the things && \
rm /keys/gitlab_rsa
Command
docker build --build-arg GITLAB_KEY_FILE=path_to_gitlab_key_file .
2) Similar to how you described, declare a build arg into which the secret can be injected. Set the build arg from an environment variable at the command line or within docker-compose.yml. Use the value stored in the build arg to populate a key file within the image. Delete the key file with it is no longer needed. This approach is useful for CI/CD servers and usage with docker-compose because environment variables will remain static.
docker-compose.yml
version: '3.2'
services:
nginx:
build:
context: .
args:
GITLAB_KEY: ${GITLAB_KEY_FROM_ENV}
ports:
- 80:80
Command
docker build --build-arg GITLAB_KEY=$GITLAB_KEY_FROM_ENV .
Be mindful also of how Docker treats the RUN directive. Docker will create an intermediate partition in the resulting image for each RUN directive (this is how it can intelligently cache steps in the build process). Therefore, each RUN behaves like a new shell. Shell variables and certain processes, like ssh-agent,will not persist between RUN 's.
Emil Moe
Senior Data Engineer