【问题标题】:Why is ARG in a DOCKERFILE not recommended for passing secrets?为什么不建议将 DOCKERFILE 中的 ARG 用于传递秘密?
【发布时间】:2018-08-20 05:24:49
【问题描述】:

http://docs.docker.com/engine/reference/builder/#arg 中,建议不要通过 ARGS 传递秘密。

注意:不建议使用构建时变量来传递 github 密钥、用户凭据等秘密。

什么时候通过构建时变量传递秘密有危险?

【问题讨论】:

  • 当你以明文形式将它们输入终端时?
  • 这也适用于将文件添加到环境变量并通过环境变量传递它吗?
  • 我认为 cat-ing 文件很好。有些人将他们的密钥(例如 AWS)放在 .bashrc 中,以便在每个 bash 会话中加载它们。我只是认为该注释指的是docker build --build-arg param=...
  • 我试图在构建时传递一个 ssh 密钥而不留下密钥的层历史记录。添加、删除和压缩是一种选择,但理想情况下,我不必为了隐藏秘密而这样做。
  • 注意:使用 docker 18.09+,您现在拥有 docker build --secret id=mysecret,src=/secret/file。见stackoverflow.com/a/51921954/6309

标签: docker credentials dockerfile


【解决方案1】:

2018 年 8 月更新:

您现在拥有 docker build --secret id=mysecret,src=/secret/file
请参阅“safe way to use build-time argument in Docker”。

2017 年 1 月更新:

Docker (swarm) 1.13 有docker secret

但是,作为commented Steve Hoffman (bacoboy)

[...]secret 命令仅帮助 swarm 用户不是更通用的解决方案(就像他们在附加持久卷时所做的那样)。
您如何管理您的秘密(它们是什么以及谁可以访问它们)非常依赖于系统,并且取决于您拼凑哪些付费和/或 OSS 来构建您的“平台”。
随着 Docker 公司开始提供平台,我并不惊讶他们的第一个实施是基于 swarm 的,就像 Hashicorp 将 Vault 集成到 Atlas 中一样——这是有道理的。

真正传递秘密的方式超出了docker run的空间。
AWS 使用角色和策略来授予/拒绝权限以及开发工具包来执行此类操作。
Chef 使用加密的数据包和加密“引导”进行身份验证。
K8S 有自己的 1.13 版本。
我相信 mesos 会及时添加类似的实现。

这些实现似乎分为两个阵营。

  • 通过“平台”提供的卷挂载或(chef/docker secret/k8s)传递秘密
  • 传递凭据以与外部服务通信以在启动时获取内容 (iam/credstash/etc)

原始答案:2015 年 11 月

这是在 commit 54240f8(docker 1.9,2015 年 11 月)中引入的,来自 PR 15182

构建环境被添加到中间 continer 的命令字符串之前,以帮助进行缓存查找。
它还有助于建立可追溯性。但是,从传递构建时间机密的角度来看,这也会降低该功能的安全性。

issue 13490 重申:

构建时环境变量:构建时环境变量不是为处理机密而设计的。由于缺乏其他选择,人们正计划为此使用它们。为了防止给人以它们适合秘密的印象,我们决定在此过程中故意不对这些变量进行加密。

9176comments中提到的:

env 变量是传递秘密的错误方式。我们不应该试图重新发明轮子并提供开箱即用的残缺安全分发机制。

当您将密钥存储在环境中时,您很容易意外暴露它们——这正是我们想要避免的:

  • 鉴于环境对进程隐式可用,因此很难(即使不是不可能)跟踪访问以及内容是如何暴露的
  • 让应用程序抓取整个环境并将其打印出来是非常常见的,因为它可以用于调试,甚至可以将其作为错误报告的一部分发送。如此多的秘密被泄露给 PagerDuty,以至于他们有一个很好的内部流程来清除他们的基础设施。
  • 环境变量被传递给子进程,这允许意外访问并打破最小权限原则。想象一下,作为应用程序的一部分,您调用第三方工具来执行某些操作,突然间,第三方工具可以访问您的环境,天知道它会用它做什么。
  • 对于崩溃的应用程序来说,将环境变量存储在日志文件中以供以后调试是很常见的。这意味着磁盘上的纯文本机密。
  • 将秘密放入环境变量中很快就会变成部落知识。新工程师不知道他们在那里,也不知道他们在处理环境变量时应该小心(将它们过滤到子流程等)。

总体而言,环境变量中的秘密违反了最小意外原则,是一种不好的做法,最终会导致秘密泄露。

【讨论】:

  • 这个答案是我见过的最好的,但是很多这些 cmets 指的是 ENV 而不是 ARG。此外,没有提及将秘密传递给构建的推荐方式实际上是什么推荐方式......
  • 进一步阅读issue 13490 表明实际上还没有推荐的解决方案,但有几个(包括使用密码库)正在探索中。
  • 我知道 VonC [尊重 :] ] 回答了这个问题,但仍然存在一个问题,即我们应该如何管理秘密并将其传递给 dockerfiles 和/或最终撰写...
  • 那么你应该在哪里存储秘密呢?我认为环境变量是最佳实践,至少根据 Heroku 的 12 要素应用原则:12factor.net/config
  • @Murmel 我明白了,由于这些 cmets,我一定考虑过“进化”这个问题。无论如何,我会把它留在这里。
【解决方案2】:

原因很简单,只要在图像上运行history,任何拥有图像的人都可以看到密钥的值。

获取此示例 docker 文件:

FROM alpine

ARG secret

RUN echo "${secret}"

(很好,很简单,只是为了说明如何使用秘密。)

然后我们构建它$ 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

如果您在本地构建映像或从注册表中提取映像,就会出现这种情况。

如果您的目标是在运行的容器之外隐藏构建时间的秘密,那么使用 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

【讨论】:

  • 我可以做些什么来防止 docker 历史显示 Dockerfile ARG。
  • 我认为你唯一真正的选择是export,然后是import(这也称为压缩层)
【解决方案3】:

我认为新的 (17.05) docker 功能 Multi-stage Builds (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”目录,否则似乎没有一种简单的方法来允许后续重建(例如更改 Dockerfile 中的构建步骤)。

【讨论】:

  • 这是正确的吗?即使使用多阶段构建,构建映像的机器最终仍会包含包含密钥的缓存层,即使应用程序执行映像没有它。似乎这仍然是一个问题,具体取决于您的构建基础架构......
  • 没错,只有将最终映像推送到 docker 注册表时才是安全的。
【解决方案4】:

我写了https://github.com/abourget/secrets-bridge 来解决构建时机密问题。

它创建了一个一次性配置,您可以将其作为构建参数传递,在构建过程中,它将连接到主机并获取秘密,使用它们,然后您可以终止主机桥。即使 build-args 保存在某个地方,它们在服务器退出的那一刻就变得毫无用处。

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

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2021-04-25
    • 1970-01-01
    • 2020-03-27
    • 2021-10-29
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    相关资源
    最近更新 更多