我最近一直在尝试使用Docker构建一些服务,有一件事一直困扰着我,那就是把密码放在Dockerfile中。我是一名开发人员,所以在源代码中存储密码感觉就像在脸上打了一拳。这值得担心吗?Dockerfiles中有什么好的处理密码的约定吗?


当前回答

我的方法似乎有效,但可能有些幼稚。告诉我为什么这是错的。

在docker构建过程中设置的arg是由history子命令公开的,所以不要去那里。但是,在运行容器时,run命令中给出的环境变量对容器是可用的,但不是映像的一部分。

因此,在Dockerfile中,执行不涉及秘密数据的设置。设置一个类似于/root/finish.sh的CMD。在run命令中,使用环境变量将秘密数据发送到容器中。sh使用这些变量来完成构建任务。

为了更容易地管理秘密数据,将其放入一个文件中,由docker使用——env-file开关加载。当然,要保密。gitignore之类的。

对我来说,finish.sh运行一个Python程序。它检查以确保之前没有运行过,然后完成设置(例如,将数据库名称复制到Django的settings.py中)。

其他回答

第13490期“秘密:记录最佳实践,做什么和不做什么,路线图”在2020年9月刚刚得到了新的更新,来自塞巴斯蒂安·范·斯泰因:

当使用buildkit作为构建器时,构建时间秘密现在是可能的;请参阅2018年11月Tõnis Tiigi的博客文章“在Docker 18.09中构建秘密和SSH转发”。

文档更新:“用BuildKit构建图像”

用于秘密的RUN——mount选项将很快升级为默认的(稳定的)Dockerfile语法。

最后一部分是新的(2020年9月)

New Docker Build secret information The new --secret flag for docker build allows the user to pass secret information to be used in the Dockerfile for building docker images in a safe way that will not end up stored in the final image. id is the identifier to pass into the docker build --secret. This identifier is associated with the RUN --mount identifier to use in the Dockerfile. Docker does not use the filename of where the secret is kept outside of the Dockerfile, since this may be sensitive information. dst renames the secret file to a specific file in the Dockerfile RUN command to use. For example, with a secret piece of information stored in a text file: $ echo 'WARMACHINEROX' > mysecret.txt And with a Dockerfile that specifies use of a BuildKit frontend docker/dockerfile:1.0-experimental, the secret can be accessed. For example:

# syntax = docker/dockerfile:1.0-experimental
FROM alpine

# shows secret from default secret location:
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret

# shows secret from custom secret location:
RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar

这个Dockerfile只是为了证明这个秘密可以被访问。正如您可以在构建输出中看到的那样。最终构建的图像将没有秘密文件:

$ docker build --no-cache --progress=plain --secret id=mysecret,src=mysecret.txt .
...
#8 [2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
#8       digest: sha256:5d8cbaeb66183993700828632bfbde246cae8feded11aad40e524f54ce7438d6
#8         name: "[2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret"
#8      started: 2018-08-31 21:03:30.703550864 +0000 UTC
#8 1.081 WARMACHINEROX
#8    completed: 2018-08-31 21:03:32.051053831 +0000 UTC
#8     duration: 1.347502967s
#9 [3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
#9       digest: sha256:6c7ebda4599ec6acb40358017e51ccb4c5471dc434573b9b7188143757459efa
#9         name: "[3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar"
#9      started: 2018-08-31 21:03:32.052880985 +0000 UTC
#9 1.216 WARMACHINEROX
#9    completed: 2018-08-31 21:03:33.523282118 +0000 UTC
#9     duration: 1.470401133s
...

从版本20.10开始,除了使用secret-file,您还可以直接使用env提供秘密。

Buildkit: secrets:允许提供秘密与env moby/moby#41234 docker/cli#2656 moby/ Buildkit #1534 支持——secret id=foo,env=MY_ENV作为将秘密值存储到文件的替代方案。 ——secret id=GIT_AUTH_TOKEN将加载env,如果它存在,而文件不存在。

秘密文件:

THIS IS SECRET

Dockerfile:

# syntax = docker/dockerfile:1.3
FROM python:3.8-slim-buster
COPY build-script.sh .
RUN --mount=type=secret,id=mysecret ./build-script.sh

build-script.sh:

cat /run/secrets/mysecret

执行:

$ export MYSECRET=theverysecretpassword
$ export DOCKER_BUILDKIT=1
$ docker build --progress=plain --secret id=mysecret,env=MYSECRET -t abc:1 . --no-cache
......
#9 [stage-0 3/3] RUN --mount=type=secret,id=mysecret ./build-script.sh
#9 sha256:e32137e3eeb0fe2e4b515862f4cd6df4b73019567ae0f49eb5896a10e3f7c94e
#9 0.931 theverysecretpassword#9 DONE 1.5s
......

While I totally agree there is no simple solution. There continues to be a single point of failure. Either the dockerfile, etcd, and so on. Apcera has a plan that looks like sidekick - dual authentication. In other words two container cannot talk unless there is a Apcera configuration rule. In their demo the uid/pwd was in the clear and could not be reused until the admin configured the linkage. For this to work, however, it probably meant patching Docker or at least the network plugin (if there is such a thing).

有一个新的docker命令用于“秘密”管理。但这只适用于蜂群。

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 

永远不要向容器添加凭据,除非您可以将凭据广播给任何可以下载映像的人。特别是,执行并添加creds并随后运行rm creds是不安全的,因为creds文件仍然保存在中间文件系统层的最终映像中。任何能接触到图像的人都能很容易地提取出来。

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 that RUN. Instead what you do is put your source into a local directory, run (as in docker 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 simply ADDing the local source directory which now contains the built artifacts.

我希望Docker添加一些功能来简化这一切!

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.