I've been experimenting with Docker recently on building some services to play around with and one thing that keeps nagging me has been putting passwords in a Dockerfile. I'm a developer so storing passwords in source feels like a punch in the face. Should this even be a concern? Are there any good conventions on how to handle passwords in Dockerfiles?
相关问题
- Docker task in Azure devops won't accept "$(pw
- “Zero out” sensitive String data in Swift
- Unable to run mariadb when mount volume
- High cost encryption but less cost decryption
- Unspecified error (0x80004005) while running a Doc
My approach seems to work, but is probably naive. Tell me why it is wrong.
ARGs set during docker build are exposed by the history subcommand, so no go there. However, when running a container, environment variables given in the run command are available to the container, but are not part of the image.
So, in the Dockerfile, do setup that does not involve secret data. Set a CMD of something like
/root/finish.sh
. In the run command, use environmental variables to send secret data into the container.finish.sh
uses the variables essentially to finish build tasks.To make managing the secret data easier, put it into a file that is loaded by docker run with the
--env-file
switch. Of course, keep the file secret..gitignore
and such.For me,
finish.sh
runs a Python program. It checks to make sure it hasn't run before, then finishes the setup (e.g., copies the database name into Django'ssettings.py
).Docker now (version 1.13 or 17.06 and higher) has support for managing secret information. Here's an overview and more detailed documentation
Similar feature exists in kubernetes and DCOS
run-time only solution
docker-compose also provides a non-swarm mode solution (since v1.11: Secrets using bind mounts).
The secrets are mounted as files below
/run/secrets/
by docker-compose. This solves the problem at run-time (running the container), but not at build-time (building the image), because/run/secrets/
is not mounted at build-time. Furthermore this behavior depends on running the container with docker-compose.Example:
Dockerfile
docker-compose.yml
To build, execute:
Further reading:
Our team avoids putting credentials in repositories, so that means they're not allowed in
Dockerfile
. Our best practice within applications is to use creds from environment variables.We solve for this using
docker-compose
.Within
docker-compose.yml
, you can specify a file that contains the environment variables for the container:Make sure to add
.env
to.gitignore
, then set the credentials within the.env
file like:Store the
.env
file locally or in a secure location where the rest of the team can grab it.See: https://docs.docker.com/compose/environment-variables/#/the-env-file
You should never add credentials to a container unless you're OK broadcasting the creds to whomever can download the image. In particular, doing and
ADD creds
and laterRUN rm creds
is not secure because the creds file remains in the final image in an intermediate filesystem layer. It's easy for anyone with access to the image to extract it.The typical solution I've seen when you need creds to checkout dependencies and such is to use one container to build another. I.e., typically you have some build environment in your base container and you need to invoke that to build your app container. So the simple solution is to add your app source and then
RUN
the build commands. This is insecure if you need creds in thatRUN
. Instead what you do is put your source into a local directory, run (as indocker run
) the container to perform the build step with the local source directory mounted as volume and the creds either injected or mounted as another volume. Once the build step is complete you build your final container by simplyADD
ing the local source directory which now contains the built artifacts.I'm hoping Docker adds some features to simplify all this!
Update: looks like the method going forward will be to have nested builds. In short, the dockerfile would describe a first container that is used to build the run-time environment and then a second nested container build that can assemble all the pieces into the final container. This way the build-time stuff isn't in the second container. This of a Java app where you need the JDK for building the app but only the JRE for running it. There are a number of proposals being discussed, best to start from https://github.com/docker/docker/issues/7115 and follow some of the links for alternate proposals.
Definitely it is a concern. Dockerfiles are commonly checked in to repositories and shared with other people. An alternative is to provide any credentials (usernames, passwords, tokens, anything sensitive) as environment variables at runtime. This is possible via the
-e
argument (for individual vars on the CLI) or--env-file
argument (for multiple variables in a file) todocker run
. Read this for using environmental with docker-compose.Using
--env-file
is definitely a safer option since this protects against the secrets showing up inps
or in logs if one usesset -x
.However, env vars are not particularly secure either. They are visible via
docker inspect
, and hence they are available to any user that can rundocker
commands. (Of course, any user that has access todocker
on the host also has root anyway.)My preferred pattern is to use a wrapper script as the
ENTRYPOINT
orCMD
. The wrapper script can first import secrets from an outside location in to the container at run time, then execute the application, providing the secrets. The exact mechanics of this vary based on your run time environment. In AWS, you can use a combination of IAM roles, the Key Management Service, and S3 to store encrypted secrets in an S3 bucket. Something like HashiCorp Vault or credstash is another option.AFAIK there is no optimal pattern for using sensitive data as part of the build process. In fact, I have an SO question on this topic. You can use docker-squash to remove layers from an image. But there's no native functionality in Docker for this purpose.
You may find shykes comments on config in containers useful.