为什么不推荐使用DOCKERFILE中的ARG来传递秘密?

在http://docs.docker.com/engine/reference/builder/#arg ,它build议秘密不通过ARGS。

注意:不build议使用构build时间variables来传递秘密,如github密钥,用户凭证等。

什么时候通过构build时variables传递的秘密处于危险之中?

2017年1月更新:

docker(群)1.13有docker secret

不过,正如Steve Hoffman( bacoboy )所评论的bacoboy

secret命令只能帮助swarm用户不是一个更通用的解决scheme(就像他们附加持久性卷一样)。
你如何pipe理你的秘密(他们是什么以及谁有权访问他们)是非常依赖系统的,并且取决于你付出的和/或OSS的哪些东西你凑在一起做出你的“平台”。
随着Docker公司开始提供一个平台,我不惊讶他们的第一个实现是基于群集,就像Hashicorp正在将Vault集成到Atlas中一样 – 这是有道理的。

真的如何通过docker run的空间之外的秘密。
AWS使用angular色和策略来授予/拒绝权限和SDK。
厨师使用encryption数据包和encryption“引导”进行身份validation。
K8S有他们自己版本的1.13版本。
我相信mesos会及时添加类似的实现。

这些实现似乎落入2个阵营。

  • 通过“平台”提供的体积安装或(厨师/docker机密/ k8s
  • 通过凭据与外部服务通话来获取引导(iam / credstash / etc)

原始答案:2015年11月

这是在承诺54240f8 (docker1.9,2015年11月),从PR 15182 ,

构build环境预先添加到中间continer的命令string中,以帮助caching查找。
它也有助于构build可追溯性。 但是这也使得从构build时间秘密的angular度来看,这个特性不太安全。

问题13490重申:

构build时环境variables :构build时环境variables不是为了处理秘密而devise的。 由于缺乏其他select,人们正在计划使用它。 为了避免给人一种他们适合秘密的印象,决定在这个过程中刻意不encryption这些variables。

正如9176所述 :

envvariables是传递秘密的错误方法。 我们不应该试图重新发明轮子,并提供一个开箱即用的安全分配机制。

当你把密钥存储在环境中的时候,你很容易意外暴露他们 – 正是我们想要避免的:

  • 考虑到这个过程隐含着环境的可能性,即使不是不可能,也很难跟踪访问以及内容是如何暴露的
  • 应用程序抓住整个环境并将其打印出来是非常常见的,因为它可以用于debugging,甚至作为错误报告的一部分发送。 如此多的秘密泄露给PagerDuty,他们有一个良好的内部过程,以擦除他们的基础设施。
  • 环境variables传递给subprocess,允许意外的访问并打破最小权限的原则。 想象一下,作为应用程序的一部分,你打电话给第三方工具来执行一些操作,突然间第三方工具可以访问你的环境,上帝知道它将如何处理。
  • 崩溃的应用程序将日志文件中的环境variables存储起来以供以后debugging是非常常见的。 这意味着磁盘上的纯文本的秘密。
  • 把envvariables的秘密很快变成部落的知识。 新的工程师不知道他们在那里,并没有意识到他们应该小心处理环境variables(过滤到子过程等)。

总体而言,环境variables中的秘密违反了最less突击的原则,是一种不好的做法,并会导致秘密的最终泄漏。

简单的原因是,只要在图像上运行history ,任何人都可以看到秘密的价值。

以下示例docker文件:

 FROM alpine ARG secret RUN echo "${secret}" 

(尼斯和简单,只是为了说明你如何使用一个秘密。)

那么我们build立它$ docker build --build-arg secret=S3CR3T - < Dockerfile

 Sending build context to Docker daemon 2.048 kB Step 1 : FROM alpine ---> 13e1761bf172 Step 2 : ARG secret ---> Running in 695b7a931445 ---> 5414c15a1cb6 Removing intermediate container 695b7a931445 Step 3 : RUN echo "${secret}" ---> Running in c90cf0d1414b s3cr3t ---> f2bcff49ac09 Removing intermediate container c90cf0d1414b Successfully built f2bcff49ac09 

以及如何取回“秘密”的例子(在第一行寻找|1 secret= ):

 $ docker history f2bcff49ac09 IMAGE CREATED CREATED BY SIZE COMMENT f2bcff49ac09 8 seconds ago |1 secret=S3CR3T /bin/sh -c echo "${secret}" 0 B 5414c15a1cb6 8 seconds ago /bin/sh -c #(nop) ARG secret 0 B 13e1761bf172 6 months ago /bin/sh -c #(nop) ADD file:614a9122187935fccf 4.797 MB 

如果您已经在本地构build了映像或从registry中将其拉出,则是这种情况。

如果您的目标是保持正在运行的容器的构build时机密,那么使用ARG确实有助于您 – 考虑这一点:

 $ docker run --rm -ti f2bcff49ac09 sh / # env HOSTNAME=7bc772fd0f56 SHLVL=1 HOME=/root TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ $ # Note no secret in the above output 

我认为新的(17.05)dockerfunction多阶段构build( https://docs.docker.com/engine/userguide/eng-image/multistage-build/ )减轻了这些(有效的)关于简单地使用–build- ARG。

 FROM mybuildertools ADD my-git-creds /root/.ssh RUN git clone git@bitbucket.org:example/foo /src FROM mybuildertools COPY --from=0 /src /src RUN ...build /src with no git credentials ending up in final image... 

不幸的是,除非你有“my-git-creds”目录,否则似乎没有一个简单的方法来允许后续的重build(例如更改Dockerfile中的构build步骤)。

我写了https://github.com/abourget/secrets-bridge来解决构build时间秘密问题&#x3002;

它会创build一个可以作为构buildparameter passing的丢弃configuration,在构build过程中,它将连接到主机并获取秘密,使用它们,然后可以终止主桥。 即使构build参数保存在某个地方,在服务器退出的时候也是无用的。

该服务器支持SSH代理转发,通过TLS websocket通信进行隧道传输。 它也适用于Windows!

希望这可以帮助。