Moby: 秘密:写出最佳实践、做与不做、路线图

创建于 2015-05-26  ·  203评论  ·  资料来源: moby/moby

在 Docker 中处理秘密(密码、密钥和相关的)是一个反复出现的话题。 许多拉取请求已被想要(错误)使用特定功能来处理机密的人“劫持”。

到目前为止,我们只_劝阻_人们使用这些功能,因为它们要么被证明是不安全的,要么不是为处理机密而设计的,因此“可能”不安全。 我们_不_为他们提供真正的替代方案,至少,不是针对所有情况和_if_,然后没有实际示例。

我只是认为“秘密”已经存在太久了。 这会导致用户(错误地)使用不是为此设计的功能(副作用是讨论会被该区域的功能请求所污染)并使他们跳过箍只是为了能够处理秘密。

被(误)用于秘密的功能/黑客

这份清单可能不完整,但值得一提

  • 环境变量。 可能是最常用的,因为它是“12 因素应用程序”的一部分。 不鼓励使用环境变量,因为它们是;

    • 容器中的任何进程都可以访问,因此很容易“泄漏”

    • 保存在图像的中间层,在 docker inspect 中可见

    • 与链接到容器的任何容器共享

  • 构建时环境变量(https://github.com/docker/docker/pull/9176,https://github.com/docker/docker/pull/15182)。 构建时环境变量并非旨在处理机密。 由于缺乏其他选择,人们正计划为此使用它们。 为了防止给人留下它们适用于秘密的_印象_,我们决定在此过程中故意加密这些变量。
  • 标记.. 挤压/展平层。 (https://github.com/docker/docker/issues/332、https://github.com/docker/docker/pull/12198、https://github.com/docker/docker/pull/4232、https ://github.com/docker/docker/pull/9591)。 压缩层将从最终图像中删除中间层,但是,在这些中间层中使用的秘密最终仍将保留在构建缓存中。
  • 。 IIRC 一些人能够利用为每个构建步骤重新创建卷的事实,允许他们存储秘密。 我不确定这是否真的有效,也找不到关于如何完成的参考。
  • 手动构建容器。 跳过使用 Dockerfile 并手动构建容器,将结果提交到图像
  • 自定义黑客。 例如,在服务器上托管机密, curl对机密进行处理,然后将其删除,所有这些都在一个层中。 (另见 https://github.com/dockito/vault)

那么,需要什么?

  • 在处理机密时添加有关“做”和“不做”的文档; @diogomonicahttps://github.com/docker/docker/pull/9176#issuecomment -99542089 中提出了一些很好的观点
  • 如果可能,使用_current_ 功能描述官方“认可”/批准的处理机密的方式
  • 提供官方处理机密的路线图/设计,我们可能希望使其可插入,以便我们不必重新发明轮子并使用该领域的现有产品,例如VaultKeywizSneaker

以上应该在编写/设计时考虑到构建时运行时的秘密

@calavera创建了一个关于如何使用新的 Volume-Drivers (https://github.com/docker/docker/pull/13161) 的快速而肮脏的概念验证; https://github.com/calavera/docker-volume-keywhiz-fs

注意:环境变量被用作事实上的标准来传递配置/设置,包括容器的MySQLWordPressPostgreSQL )。 这些图像在编写/实施时应采用新的“最佳实践”。

按照良好的传统,这里有一些处理机密的较旧的建议;

aresecurity statuneeds-attention

最有用的评论

我知道这是题外话,但有没有其他人注意到这个问题已经活跃了将近一整年了! 明天是它的周年纪念日。 👏

所有203条评论

ping @ewindisch @diogomonica @NathanMcCauley这只是一篇简短的文章。 如果您认为有必要,请随时修改/更新描述:)

@dreamcat4有一些计划来实现一个通用的“秘密 API”,它允许你使用 Vault、或 Keywiz 或你命名的 Docker,但都以相同的方式。 这只是一个早期的想法,因此需要额外的研究。

@thaJeztah 是的,对不起,我不想以任何方式减损这些努力/讨论。 我更多地在想,看看我们现在能走多远,这也许也是一个有用的练习(作为较长过程的一部分,并且在我们等待的过程中)。 然后它更清楚地向其他人展示了当前流程的局限性和不足。 底层缺少什么并且最需要添加以改进秘密。

另外值得考虑的是运行时机密与构建时机密的不同情况。 其中也有一个区域重叠区域。

也许(对于 docker)我们也可能值得考虑解决方案之间的限制(优点/缺点),这些解决方案提供了一种机制来处理“内存中”的秘密。 与更严重的基于文件的机密方法或基于网络的方法(例如本地机密服务器)相反。 哪些是当前桌面上的黑客(直到正确的秘密 API)。 这可以帮助我们了解 docker secrets API 添加的一些独特价值(例如更强的安全性),否则无法通过在当前 docker 功能集之上使用 hacks 来实现。 但是,我不是安全专家。 所以我不能非常肯定地评论这些事情。

@dreamcat4是的,你说得对; 就短期而言,这些链接确实有用。

另外值得考虑的是运行时机密与构建时机密的不同情况。 其中也有一个区域重叠区域。

谢谢! 我想我在最初的描述中有那个,一定是在这个过程中迷路了。 我会添加一个项目符号

但是,我不是安全专家。

我也不是,这就是我“ping”安全维护人员的原因; IMO,这应该是他们写的东西😇

@thaJeztah很棒的总结。 每当我找到一些时间时,我都会尝试戳一下。

@diogomonica虽然不是 _directly_ 相关的,但在构建期间转发 SSH 密钥代理有一个很长的开放功能请求; https://github.com/docker/docker/issues/6396鉴于评论的数量,最好也考虑一下。 (如果甚至决定是否可以/应该实施)

假设您可以以 root 以外的用户身份挂载卷(我知道这是不可能的,但请逗笑我),这是否是将机密放入容器的有利方法?

如果是这样,我提倡-v host_dir:image_dir的替代方案,它期望使用仅数据容器,并且可能看起来像-vc host_dir:image_dir (即卷复制),其中 host_dir 的内容是复制到仅数据容器上的 image_dir 卷中。

然后我们可以强调secure-data-only containers范式并允许对这些卷进行加密

我最近从@jrslv读到了一篇关于这一点的好文章,他建议构建一个带有秘密的特殊

所以你有两个 Dockerfile:

  • Dockerfile.build(在这里你只需复制你所有的秘密)
  • Dockerfile.dist(您将推送到注册表的这个)

现在我们可以像这样构建我们的发行版:

# !/bin/sh
docker build -t hello-world-build -f Dockerfile.build .
docker run hello-world-build >build.tar.gz 
docker build -t hello-world -f Dockerfile.dist ^

您的秘密是安全的,因为您从不推送hello-world-build图像。

我建议阅读@jrslv文章以获取更多详细信息http://resources.codeship.com/ebooks/continuous-integration-continuous-delivery-with-docker

感谢分享@kepkin
刚看完文章。 真的很简洁!

我喜欢导出文件并通过单独的 Dockerfile 加载它们的想法。 感觉就像在没有“构建缓存中的中间层”问题的情况下挤压。

但是,我担心它会使开发复杂化,并且为了简单起见可能需要第三个 Dockerfile。

@kepkin无意冒犯,但这没有任何意义。 秘密绝对是不安全的,因为它们在 tarball 中,并且 tarball 被ADD编辑到生产映像中——即使你删除了 tarball,没有压缩,它也会在某些层泄漏。

@TomasTomecek如果我正确理解了这个例子,tarball https://github.com/docker-library/hello-world/blob/master/update.sh (这里不涉及任何秘密,只是构建容器的一个简单示例)

@TomasTomecek我在谈论构建 Docker 镜像的秘密。 例如,您需要传递 ssh 密钥以从您的私有 GitHub 存储库中检出源代码。 并且 tarball 仅包含构建工件,但不包含 GitHub 密钥。

@kepkin对,现在我又看了你的帖子,可以看到了。 对于那个很抱歉。 不幸的是,当您在部署/构建分发映像(例如,获取工件和使用工件服务进行身份验证)期间需要秘密时,它并没有解决问题。 但是对于构建过程和发布过程的分离来说,它绝对是一个很好的解决方案。

@TomasTomecek这正是我实际获取工件的方式。

在 Docker.build 映像中,我从需要 AWS 密钥和机密的 Amazon S3 映像下载了一些二进制依赖项。 在检索和构建之后,我创建了一个包含我需要的一切的 tarball。

是否有一篇规范的“最佳实践”文章——“做”与“不该做”的区别——你们都推荐阅读?

值得注意的是(对于像我这样遇到这个问题的其他人)Docker Compose 支持env_file选项。

https://docs.docker.com/compose/compose-file/#env -file

@afeld docker本身也具有此功能,请参阅http://docs.docker.com/engine/reference/commandline/run/#set -environment-variables-e-env-env-file 但那些 env-vars 仍然会出现在相同的地方,所以不要因为“泄漏”而有所不同

我偶然发现了这个备忘单: http :

@kepkin这就是我将 ssh-key 传递给docker build

# serve the ssh private key once over http on a private port.
which ncat
if [ "$?" = "0" ]; then
  ncat -lp 8000 < $HOME/.ssh/id_rsa &
else
  nc -lp 8000 < $HOME/.ssh/id_rsa &
fi
nc_pid=$!
docker build --no-cache -t bob/app .
kill $nc_pid || true

在 Dockerfile 中,其中 172.17.0.1 是 docker 网关 IP:

RUN \
  mkdir -p /root/.ssh && \
  curl -s http://172.17.0.1:8000 > /root/.ssh/id_rsa && \
  chmod 600 /root/.ssh/id_rsa && chmod 700 /root/.ssh && \
  ssh-keyscan -t rsa,dsa github.com > ~/.ssh/known_hosts && \
  git clone --depth 1 --single-branch --branch prod [email protected]/app.git . && \
  npm i --production && \
  ... && \
  rm -rf /root/.npm /root/.node-gyp /root/.ssh

如果有人有更简单的东西,请告诉我们。

那么这件事的现状如何呢?

整个夏天都有很长的对话链,表明这种担忧是多么普遍。 这是五月份提交的,现在仍然开放。 例如,我将如何设置 Postgres 的密码?

@thaJeztah可以进程? 我猜不同下游项目的许多人都在关注这个问题...... ej。 https://github.com/rancher/rancher/issues/1269

我猜这里正在做的事情是_秘密_ :D

这是我们将 Docker 集成到我们的生产堆栈中的最大痛点。 是否有路线图或其他文档指向这方面的任何进展?

来自k8s 的一些有关此主题的相关内容。

您认为这是解决运行时机密的一种潜在方式吗?
https://github.com/docker/docker/issues/19508

我觉得解决这个问题的最好方法是专注于需要支持的几个场景,并确保每个场景都有一组说明。 它们如何实施不如在流程结束时是否有一组连贯的功能可以组合以满足需求更重要。

我所看到的一些似乎非常合理的问题包括:

运行时凭证

  • 在共享link两个容器之间协调的用户/密码信息
  • 信息很容易远离你的 git 存储库
  • 信息很容易隐藏在你推送的图像之外(本地容器呢?)
  • 信息很容易被排除在 .bash_history 之外(可能是桥太远了?)
  • 某些应用程序希望将机密作为包含其他信息的配置文件的一部分
  • 一些应用程序希望将机密作为环境变量
  • 一些应用程序允许

当我说“简单”时,我的意思是有一种符合人体工程学的合理方法来处理这些变量,以防止用户意外做错事并触发安全公告。 经验的压力通常与(阅读:归咎于)错误所涉及的工具有关。

构建时凭据

  • 项目是从一个或多个私有存储库构建的(例如:package.json 允许使用 git url)
  • Builder 可能位于受密码保护的代理后面
  • Builder 可能正在使用受密码保护的缓存
  • 最终用户只关心工作图像(即,他们将使用 pull 或 FROM,从不使用docker build
  • 信息很容易隐藏在您推送的图像之外

第一次编辑:

什么是什么不“泄漏”到典型图像、容器中的文档

  • 图像中出现了哪些文件(只是 COPY 和 ADD?还有什么?)
  • 构建镜像后docker-machine保留了什么(尤其是boot2docker,但其他人呢?)
  • 如何在映像中捕获环境和命令行变量,以及捕获它们的位置
  • 对公关发行人改变这些行为的期望

我觉得我在这里错过了几个大人物。 有人有我忘记的东西吗?

任何 json 服务的 API 密钥。

例如(这是我的真实用例),Docker 构建编译一个程序,API 密钥是对我进行身份验证并将构建产品上传到 Bintray.com 所必需的。

@dreamcat4我可能和你说的

您是在谈论使用 docker 镜像进行持续部署构建,并在成功构建结束时将构建工件推送到存档中吗? 就我个人而言,我更喜欢在上游执行此操作(例如,Jenkins 中的后期构建脚本),但如果您进行交叉编译,那可能会有点棘手。

在我的世界中,构建代理只是构建二进制文件/存档并将它们保留为构建过程的“工件”,其他东西将它们推送到基础设施,标记 git 存储库等。如果我,这给了我工件的紧急备份有生产问题,比如我的 npm、docker 或 Artifactory 存储库因升级而停机,或者网络出现故障。

我试图提出的观点是关于 API 密钥的一般使用。 容器可能需要与之交互(在构建时或运行时)的许多不同且多种多样的在线 JSON/rest 服务......这需要 API 密钥。 不必专门与构建相关。

@dreamcat哦,那么 REST 端点的身份验证令牌? 您认为这些处理方式与 conf 文件中的 postgres 密码有很大不同,还是您会以类似方式处理它们?

是的,我认为在评估它们的基本最低安全级别方面应该对这两种类型进行不同的考虑。

API 身份验证令牌往往是:

  • 不是密码
  • 可以撤销
  • 一些(少得多的子集)是一次性的——扔掉。 并且基本上使他们自己无效。
  • API 服务的范围通常仅限于功能的一个子集。 (即只读,或只能触发特定动作)。

密码往往是/经常是:

  • 更全面的帐户访问/控制。
  • 一旦受到威胁,攻击者可能会将其更改为其他内容(锁定)。 或者其他后门插入(比如数据库中其他账户的db修改,在SQL的情况下)。
  • 作为密码,在其他帐户中“相同密码重复使用”的风险要高得多。 而 API 密钥往往总是唯一的,不能用于其他任何东西。

所以这并不一定意味着这两种类型的秘密解决方案_必须不同_。 只是 API 密钥可接受的最低安全基​​线级别可能会低一点。

如果强大的安全性设置起来更复杂/有问题,那么这个最低级别很重要。 (这在 docker secrets 的情况下可能是正确的,或者不取决于解决方案的可行性/优雅程度)。

有时密码的 API 密钥可能具有更强/更弱的安全性。 只是如果一刀切是不可能的。

例如 - 我的 bintray API 密钥:与我的 Dockerfile 保存在同一个 .git 存储库中。 因此,为了保证它的安全,它保存在 PRIVATE git repo(通过 SSH 访问)中。 因此,获得访问权限是对那里保护得相对较好的 API 密钥。 然而,如果 docker 没有任何内置的秘密功能/保护自己,构建的 docker 镜像总是以纯文本形式包含 API 密钥。 因此,生成的 Docker 构建映像必须像 git 存储库一样保持私有......这会产生连锁反应(不良影响),其他人无法在那里公开查看/查看构建日志/构建状态。

现在这在很多方面都不理想。 但整体解决方案足够简单并且确实有效(如:昨天)。 如果以后有更好的机制,我会考虑改用它。 但如果该机制比我已经制定的当前解决方案的设置成本更高/更复杂,则不会。 因此,在只有 1 个 api 密钥的情况下,超强的安全性(尽管欢迎)可能会过大。 只需要使用某种新的 NOCAHCE 选项 / Dockerfile 命令将其排除在 docker 的图像层缓存之外。

鉴于密码需要诸如 vault 或 ansible-vault 之类的东西,并且需要使用另一种密码或其他高度安全的身份验证机制进行加密。 (我们不希望这样做,但设置起来可能很复杂)。

我认为用于管理和简化(阅读:审计,打破玻璃)所有秘密相关内容的客户端/服务器模型(如在Vault 中)将是一个很好的实践,并且如果实施经过深思熟虑,它将涵盖大多数用例。 我个人不喜欢采用非整体方法,因为这是提高最佳实践标准的机会。

这意味着长期运行的客户端(部署映像的人的责任)和/或构建时客户端(构建者的责任)。 也许前一个可以以某种方式转移到 docker 守护进程,它在运行时提供授权的秘密。

确实 - 我完全同意之前的评论。 并不是说我不欣赏人们解决问题的创造性方式,但我认为这不是它需要的方式 - 让我们尝试思考一个可以在 CI/D 和运行时使用的解决方案,并考虑到容器可能由 Mesos/Kubernetes 等编排。

好吧,我认为一些文档在这里仍然有用,因为 Docker 在问题空间中提出了一些额外的问题。

看起来也许 Vault 的人也在从他们的角度看这个。 我认为这张票值得一看:

https://github.com/hashicorp/vault/issues/165

也许这是可以合作的东西。

@jdmarshall

也许这是可以合作的东西。

+1

+1 Docker + Hashi Corp Vault

抱歉,但我不喜欢随着更多人加入,解决方案变得越来越复杂。例如,Hashi Corp Vault 是一个完整的客户端服务器解决方案,带有加密的后端存储。 这增加了相当多的移动部件。 我确信有些用例需要这种复杂程度,但我怀疑大多数人会这样做。 如果竞争解决方案是使用主机环境变量,我很确定大多数开发人员最终会使用哪个。

我正在寻找一个涵盖开发(例如:github 密钥)和部署(例如:nginx 证书密钥、数据库凭据)的解决方案。 我不想用 env vars 或构建工具污染主机,当然,任何秘密都不应该出现在 github(未加密)或 docker 镜像目录中,即使是私有的。

@gittycat我同意你的看法,因为可能有几个不同的用例。 因此,某些解决方案应该比其他解决方案更简单。

不过,我们当然应该避免使用 ENV 变量。

我自己的偏好倾向于这样一种想法,即可以通过类似于 ansible 的“保险库”机械主义的东西来实现简单的密钥存储。 您在构建上下文(或构建上下文之外/旁边的源)中保存了加密文本文件。 然后解锁密钥可以解锁该文件中的任何明文密码或 API 密钥等。

我只是说在使用 anisible 自己的“保险库”解决方案之后。 这是相对无痛/简单的。 Hashicorp 的保险库更安全,但也更难设置,而且通常更复杂。 尽管我不知道任何技术原因,为什么您仍然不能最终将其用作后端(将其隐藏/简化在面向 docker 的命令行工具后面)。

我建议使用本地文件存储,因为它避免了需要设置一些复杂且可能不可靠的 HTTP 密钥存储服务器。 秘密存储在很大程度上是一个安全问题,因此应该可供所有用户使用,而不仅仅是企业。 只是我的 2 美分意见。

+1 到本地文件存储后端,对于更高级的用例,我更喜欢 Hashicorp Vault 的全部功能 - 类似解决方案。 当我们谈论部署时,在一个组织中,争论是,提供和控制秘密的人不是使用秘密的人。 这是一种常见的安全措施,可以将控制权的人圈限制在非常值得信赖的安全工程师......

不知道这是否有任何用处或是否可行,但这里有一些左场建议,用于解决我想在运行时将秘密注入容器的情况(例如 postgres 密码)

如果我可以在docker run时间覆盖入口点并将其设置为我选择的脚本,例如 /sbin/get_secrets,在从我选择的机制(例如 KMS)获取机密后,它将执行原始入口点(因此成为一个纯粹的包装器,其唯一目的是在容器内部设置环境变量,其中包含秘密。这样的脚本可以在运行时通过卷挂载提供。这种机制不会涉及将秘密写入磁盘(我的一个宠物讨厌),或者被 docker 泄露(不是 docker inspect 的一部分),但会确保它们只存在于容器内进程 1 的环境中,从而保持 12 因子。

如果在图像元数据中没有使用入口点,你已经可以做到这一点(我相信),但只有 cmd 是,因为入口点然后包装命令。 如前所述,包装器可以在运行时通过 volmount 安装。 如果入口点已在图像元数据中使用,那么我认为您目前无法完成此操作,除非可以从容器内部看到原始入口点(而不是 cmdline 覆盖)-不确定您是否可以这样做.

最后,我认为甚至可以通过传统的 env var 注入提供加密的一次性密钥,外部 /sbin/get_secrets 可以使用它来请求实际的机密(例如 postgres 密码),从而为 docker 添加额外的保护泄露一次性密钥。

我不知道这是否只是层层叠加,或者它是否有可能解决问题……如果只是第一个,我深表歉意。

@thaJeztah - 我可以确认我在上面提出的解决方案有效,秘密在没有被

@gtmtech有趣。 会对您如何从 get secrets 二进制文件中找到原始入口点感兴趣。

也许示例代码文件夹会使该方法更易于演示/理解。

示例代码和工作场景在这里@dreamcat4 @kaos >

https://github.com/gtmtechltd/secret-squirrel

我可能错了,但为什么要使用这些复杂的方法? 我依赖于标准的 unix 文件权限。 将所有机密交给 docker, -v /etc/secrets/docker1:/etc/secrets只能由 root 读取,然后有一个脚本在容器启动时以 root 身份运行,它将机密传递到相关程序的适当位置(例如 apache 配置)。 这些程序在启动时会放弃 root 权限,因此如果被黑客入侵,它们以后将无法读取 root 拥有的秘密。 我使用的这种方法有什么缺陷吗?

谢谢@gtmtech :)
不幸的是,我们没有标准的入口点,我也无法在 docker run 之前以受控方式运行 docker inspect .. 但我喜欢你的方法。

我可能错了,但为什么要使用这些复杂的方法? 我依赖于标准的 unix 文件权限。 使用 -v /etc/secrets/docker1:/etc/secrets 将所有机密移交给 docker 只能由 root 读取,然后有一个脚本在容器启动时以 root 身份运行,它将机密传递到相关程序的适当位置(例如 apache配置)。 这些程序在启动时会放弃 root 权限,因此如果被黑客入侵,它们以后将无法读取 root 拥有的秘密。 我使用的这种方法有什么缺陷吗?

你好,
我同意并认为这种方法 ^^ 通常应该被推荐为 RUNTIME 机密的最佳方法。 除非这里的其他人强烈反对这一点。 之后,随后还可以列出 ^^ 未涵盖的任何剩余的极端情况(在运行时)。

不幸的是,我看不到秘密松鼠起飞,因为对于大多数普通的非技术人员来说,它太复杂了,无法学习和采用一些流行的策略。

那么就这样了(你可能已经猜到了)......
建造时间的秘密!

但我认为这是一个进步! 由于很长一段时间没有真正取得任何进展,因此可能会将事情减半并解决总问题的大约 45-50%。

如果仍然存在围绕秘密的问题,至少它们将是更具体/集中的问题,并且可以在之后继续进步/讨论。

是的,我不会详细介绍,但是这些方法对于我目前正在处理的情况永远不会奏效,因为我需要比它们提供的更高级别的安全性。 例如,磁盘上没有未加密的秘密,一旦在目标进程中被解密,就没有有效的解密密钥,定期加密轮换,以及加密秘密的单一存储库(而不是跨服务器传播)。 因此,对于那些必须执行我建议的可能方法的安全级别的人来说,它更多。

无论如何,secret_squirrel 是在我看不到任何可行解决方案的空间中的一个黑客,围绕 docker 尚未提供秘密 api 或可插拔的秘密驱动程序,希望他们在某个时候会,但也许它有助于说明设置 ENV在进程执行之前容器内的 vars,但不作为 docker create process(或元数据)的一部分,是一种符合 12-factor 机密的安全方式,也许 docker 开发社区可以在他们开始构建时使用这个想法secrets-api/driver 如果他们认为它是一个不错的!

码头快乐!

我们一直在使用@gtmtech所描述的那种方法,并取得了巨大的成功。 我们通过环境变量注入 KMS 加密的机密,然后让容器内的代码根据需要解密。

通常,这涉及应用程序前面的一个简单的 shim 入口点。 我们目前使用 shell 和一个小的 Golang 二进制文件 (https://github.com/realestate-com-au/shush) 的组合来实现该 shim,但我喜欢纯 Go 方法的声音。

@gtmtech @mdub我肯定会很高兴看到更多这样的内容。
@dreamcat4我认为“复杂”的定义可能是路径相关的,这显然是可以的。 然而,它可能不能是一个抽象的判断。 但是,因此,在设计级别,docker 容器中的安全包装器对我来说似乎并不太复杂。 另一个方面是最佳实践:不应仅从开发人员的角度,而是从运营的角度来看待这些。
我的 2 美分

保险库 +1

保险库-1。 Vault 具有一些操作特性(解封),这使得它对很多人来说真的很不受欢迎。

拥有一个可插拔的 API 是最有意义的。

还有ansible的保险库。 那是一种不同的野兽。

@gtmtech感谢您的建议,它激发了我编写此入口点的灵感:

#!/bin/bash

if [ -d "/var/secrets" ]; then
  tmpfile="$(mktemp)"
  for file in /var/secrets/*
  do
    if [ -f $file ]; then
      file_contents=$(cat $file)
      filename=$(basename "$file")
      underscored_filename="${filename//-/_}"
      capitalized_filename=${underscored_filename^^}
      echo "export $capitalized_filename=$file_contents" >> $tmpfile
    fi
  done

  source $tmpfile
  rm -f $tmpfile
fi

exec "$@"

我只是像这样将它添加到Dockerfile (不要忘记在它上面添加chmod + x ):

ENTRYPOINT ["/app/docker-entrypoint.sh"]

瞧。 ENV 变量在运行时可用。 够好了 :)

如果我理解正确, /var/secrets目录应该通过卷安装对吗??
另外,当有人评论说机密没有写入光盘时,将它们写入光盘然后删除它们有多糟糕???

好一个! 不过,您应该使用shred来安全地删除该文件。

2016 年 3 月 3 日星期四,Juan Ignacio Donoso通知@ github.com
写道:

如果我理解正确,/var/secrets 目录应该通过
量对吗??
此外,当有关于未写入光盘的机密的评论时,如何
不好的是将它们写入光盘然后删除它们???


直接回复此邮件或在 GitHub 上查看
https://github.com/docker/docker/issues/13490#issuecomment -191887424。

瑞马里尼奥

受到@gtmtech的“secret-squirrel”的启发,我扩展了我的秘密管理工具“shush”,使其可用作图像入口点:

ADD shush_linux_amd64 /usr/local/bin/shush
ENTRYPOINT ["/usr/local/bin/shush", "exec", "--"]

这会解密任何KMS_ENCRYPTED_xxx变量,并将结果注入到环境中。

https://github.com/realestate-com-au/shush#use -as-a-command-shim

所以线程开始于不要做任何这些事情......

......但我没有看到任何请做这些事情代替......只有大多数被拒绝/关闭的各种提案/黑客。

目前官方的最佳实践是什么? 作为 docker 用户,看到一长串我们不应该做的事情但没有提供官方替代方案,这有点令人沮丧。 我错过了什么吗? 一个不存在吗? 我确信事情正在幕后发生,这是 Docker 团队正在努力的事情,但截至目前,在提出规范解决方案之前,我们如何最好地处理秘密管理?

@亚历克斯科尔森
据我了解,如果您在运行时需要机密,则应该使用卷(文件系统机密)或某些服务,例如 HashiCorp Vault(网络机密)。

对于构建时的秘密,它更复杂。
构建时不支持卷,因此您应该使用容器来执行修改文件系统的命令,并使用 docker commit。

所以缺少的是在构建时使用 Dockerfile 之外的任何东西来管理秘密的能力,而无需使用docker commit

有些人甚至说使用文件系统获取机密是不安全的,docker daemon 应该提供一些 API 来安全地提供机密(使用网络/防火墙/自动挂载卷?)。 但是没有人甚至不知道这个 API 会是什么样子以及人们将如何使用它。

当我想到 env vars 的缺点时,我会想到非 docker 特定的问题,例如:

  1. 聚合日志以捕获所有环境变量或遗留在生产 Web 服务器上的遗忘的 phpinfo - 因此要小心使用机密和正确配置。
  2. 也许是暴露环境变量的木马 - 所以不要运行不受信任的软件。
  3. 利用 sql 注入等弱点的攻击 - 因此验证输入并使用 Web 应用程序防火墙。

此线程顶部显示的弱点:

容器中的任何进程都可以访问,因此很容易“泄漏”

从上面交叉应用 1 和 2。 合法但要小心处理,对吗? 此外,您的 docker 容器运行的进程比全栈 Web 服务器少得多。

环境变量中的配置怎么样,但是秘密环境变量具有加密值并且应用程序具有代码中的密钥? 这只是混淆,因为密钥在代码中,但需要利用漏洞才能访问密钥和环境变量。 也许使用配置管理来管理 docker 主机上的密钥,而不是应用程序代码中的密钥。 可能有助于处理胭脂过程和意外泄漏,但显然不能帮助拥有密钥的人进行注入攻击。

保存在图像的中间层,在 docker inspect 中可见

人们是将 env vars 烘焙到 docker 图像中,而不是在运行时设置,还是我误解了这一点。 永远不要将秘密隐藏在文物中,对吗? 是的sudo docker inspect container_name提供了 env var,但是如果您在我的生产服务器上,那么 iv 已经丢失了。 sudo docker inspect image_name无法访问我在运行时设置的环境变量。

与链接到容器的任何容器共享

不如不使用链接和新网络怎么样?

唯一看起来像 docker 问题而不是普遍的问题是链接......

docker build期间,将我置于需要一种处理秘密的好方法的人的阵营中。 我们在一些 php 项目中使用 composer 并引用一些私有的 github repos 作为依赖项。 这意味着如果我们想在容器内构建所有东西,那么它需要 ssh 密钥来访问这些私有存储库。

我还没有找到一个好的和明智的方法来处理这个困境,而不是打败我认为对 docker 有益的其他一些东西(见: docker squash )。

我现在不得不在容器外构建部分应用程序并使用COPY将最终产品引入容器中。 嗯。

我认为docker build需要一些功能来处理像秘密这样的临时数据,这样它们就不会进入最终的运输容器。

我认为 docker build 需要一些功能来处理诸如机密之类的临时数据

这是一个哲学问题而不是技术问题。 这种短暂的数据会破坏 docker 的基本优势:可重复性。

Docker 的理念是你的 Dockerfile 和上下文足以构建一个镜像。
如果您需要一个位于结果图像之外的上下文,您应该从网络获取它并跳过写入文件系统。 因为每个 Dockerfile 行都会生成一个文件系统快照。

如果秘密不应该是图像的一部分,您可以运行一个临时容器,它将镜像/代理您所有受秘密保护的资源并提供无秘密访问。 镜像,顺便说一句还有另一个理由: https :

您也可以共享 ssh 密钥本身,但您将无法控制其使用。

@bhamilton-idexx 如果您确保对您的私有存储库的身份验证使用短期令牌,您就不必担心秘密保存在 docker 映像中。
您让构建系统生成一个 ttl 为 1 小时的令牌,将其作为环境变量提供给 docker 构建。
您的构建可以获取所需的构建详细信息,但在您的构建完成后不久,秘密就会超时,从而关闭该攻击向量。

现在已经阅读了一堆这样的线程,一个可以解决这里的一些用例并且会有秘密之外的用例的功能是--add标志docker run将文件复制到容器中,就像Dockerfiles 中的ADD语句

这确实是一篇很棒的文章。 非常好读。 而正是我们一直希望看到的那种事情。

顺便提一句:

还发现了其他一些似乎从文章中遗漏的秘密工具。 抱歉任何重复/重复。 也没有注意到他们在这里提到的:

构建时间秘密:

https://github.com/defunctzombie/docket

运行时的秘密:

https://github.com/ehazlett/docker-volume-libsecret

人们怎么看? 非常感谢。

为了我:

这些较新的工具 ^^ 现在看起来非常好。 当我们第一次开始这张票时,它们肯定不存在。 但我现在觉得最重要的事情仍然是:

在 DockerHub 上拥有更好的构建时机密功能。 那里很穷,迫使人们做出非此即彼的选择。 我们必须为了另一种解决方案的好处而放弃一种解决方案的好处。 取决于哪一组特征更重要。 由于本地构建对于保护机密绝对更好,但在其他方面比 Dockerhub 更糟糕是可以理解的。

我们编写了另一个类似于 docket 的工具,它使用了新的图像格式:

https://github.com/AngryBytes/docker-surgery

我们的实现首先创建一个包含注释SECRETS机密的层,然后使用修改后的FROM创建 Dockerfile 的副本,构建并最终从结果图像中删除所有SECRETS层。

破解这个总是有警告的,如果 docker 有内置的 rebase 或层拼接功能,它会膨胀。 现在删除中间层很慢,因为所有解决方案都必须在幕后进行docker save / docker load舞蹈。

此外,构建缓存被破坏。 现在,我们使用docker commit来创建注释的秘密层,但是保持这些层的适当缓存仍然是一堆工作,我们不太可能这样做。 使用 Dockerfile 创建 secrets 层可能会解决这个问题,但没有办法对该层进行评论,因此很难确定之后要删除的内容。

@Vanuan [Dockerfile] 无法重现。 RUN 命令保证您和我不能合理地期望从两次运行中获得完全相同的图像。 为什么? 因为大多数时候人们使用 RUN 来访问网络资源。 如果您想要与我相同的图像,则需要“从”我的图像创建自己的图像。 没有其他安排会给我们相同的图像。 没有其他安排可以为我们提供相同的图像。 所有持久的再现性都来自 Docker Hub,而不是 Dockerfile。

如果我们不能拥有临时数据的唯一辩护是因为 Docker 认为他们可以删除所有临时数据,那么您必须弃用 RUN 指令。

@stephank我已经在工作中实现了一个

那是通过在 VOLUME 中运行带有项目代码的“构建管理器”。 然后,管理器在单独的容器中运行任意数量的构建工具,这些工具使用来自管理器的卷挂载项目代码。 因此,任何构建的工件和其他生成的文件都保存在管理器卷中,并遵循每个构建步骤的构建管道。 最后,经理可以使用生成的构建结果构建最终的生产映像。 一路上需要的任何秘密都在管理器和/或构建容器中可用,但不是最终图像。 没有使用 docker 镜像向导,并且构建缓存按预期工作。

构建管道的外观完全取决于使用配置构建要求的规范文件的项目。

事实上,我对这个工具相当大肆宣传,我只是在等待我们能够将它作为开源发布(等待采用公司政策指南)。

@kaos一方面,我不想偏离现有的 Docker 工具。 另一方面,我觉得图像构建工具之间真的应该有更多的竞争。 所以这听起来很有趣! 😀

@thaJeztah对于环境(12 因素)秘密,我们通过 Twistlock (+Scalock) 锁定 Docker 守护进程,以防止通过检查泄露环境变量。 如果我们有 Docker 原生的能力,不会通过检查泄露尽可能多的特权信息,从而使这成为一个更合适的现实,那就太好了。

@alexkolson我认为这个线程的关键是“不

也许你们中的一些人可以帮助我,因为我对 docker 还没有那么多经验。
我使用了 Hashicorps Vault 来获取我的秘密。

我所做的基本上是将令牌作为构建参数传递,令牌可用于从 Vault 获取敏感信息。 这发生在构建时,并且只有在 Vault 处于“未密封”(打开以获取数据)状态时才能成功。 构建后使用的令牌被撤销。

但我想我仍然面临一些常见的问题。

  • 如果敏感数据发生变化,我必须创建新图像
  • 如果我的图像被盗/黑客攻击,那么敏感数据就在图像中。

可以使用 docker inspect 找到使用过的令牌,但它不能再使用了。
我选择仅在构建时密封和解封 hashicorps 保险库,以尽可能限制对机密存储的访问。 我也没有看到在运行时获取数据时保存机密的选项。

那么我做的有多糟糕(可以说如果我把时间搞砸了;))有没有人有让我更安全的提示和技巧?

@weemen AFAIK 在您的图像中存储秘密也不是一个好主意。 您的图像不应包含任何凭据(包括 Vault 令牌)。 相反,使用 Vault 的 app-id 身份验证后端为您的容器获取加载时间的秘密。 以某种方式将它们存储在容器的内存中,具体取决于您使用的应用程序堆栈。

此外,Vault 正在开发一个 aws auth 后端,如果您将 AWS 用作云提供商,它将在未来提供有用的信息。

@jaredm4你能澄清一下这个说法吗?:

“相反,使用 Vault 的 app-id 身份验证后端为您的容器获取加载时间的秘密。以某种方式将它们存储在容器的内存中,具体取决于您使用的应用程序堆栈。”

我还不清楚何时/何地从 Vault(或 Keywhiz 等)检索机密。 这是在 docker run 之前完成并传递给 run 命令吗? 这是否在容器初始化期间的某个时刻发生(如果是,有任何示例)? 我的应用程序应该在需要时检索这些吗? 例如,我的 rails 应用程序需要 Google API 密钥,当需要密钥时,我是否在 rails 中编写一些内容来调用 vault?

我想我很清楚需要使用 Vault 之类的东西,并且清楚如何配置它,我只是不清楚如何使用该服务并在 rails 启动时更新我的​​ yml 文件。

这里的任何指导将不胜感激。 谢谢

当然@mcmatthew ,但我必须先说我还在努力掌握Vault,所以我的经验很简单。

我一直在尝试编码的方式是,您传递给容器的唯一信息是您的代码能够通过 Vault 进行身份验证所需的信息。 如果您使用 app-id 后端,那将是app-id本身,以及您的 Vault 的地址。

在容器启动时,您的 Rails 应用程序会注意到它还没有机密,并且必须从 Vault 中获取它们。 它具有提供的app-id ,并且需要以某种方式生成它的user-id 。 此用户 ID 生成需要由您确定,但他们的文档提示为“它通常是机器唯一的值,例如 MAC 地址或实例 ID,或从这些唯一值散列的值。”

一旦您的 Rails 应用准备好 app-id 和 user-id,它就可以使用 Vault 的 API 来 /login。 然后,您可以进行 API 调用以获取所需的机密。

现在澄清我将它们存储在内存中的意思——这取决于您使用的应用程序类型,但是对于 Rails,应该有一种方法可以将您的秘密存储在用户空间变量缓存中,这将允许 Rails 访问每个请求都从内存中获取机密,而不是一遍又一遍地从 Vault 获取它们(你可以想象这会很慢)。 看看这个关于在 Rails 中缓存的

最后,请确保无论您如何编码,都在 Rails 中进行,而不是使用特殊的 Docker 入口点脚本或类似脚本。 Rails 应该检测内存中的机密,如果不存在,则获取它们。

我希望这有帮助。 我知道,有点高,但这就是我们计划解决它的方式。

不清楚的是什么应该保密,app-id,user-id 或两者兼而有之。

好的,答案都是https://www.vaultproject.io/docs/auth/app-id.html
但目前还不清楚为什么它比普通的防火墙访问更安全。
也许是每个主机机密都应该与应用程序(策略)机密相关联?
即,如果您可以访问主机的机密,如果您知道它们的机密名称,您就可以访问某些应用程序?

现在我们需要在某处存储 2 个令牌?

@Vanuan他们都应该尽可能保密,是的。

app-id 的主要目的是通过策略限制对 Vault 内某些机密的访问。 任何有权访问 app-id 的人都可以访问该 app-id 的策略的秘密。 app-id 应由您的部署策略提供。 例如,如果使用 Chef,您可以在参数包(或 OpsWorks 的 CustomJSON)中设置它。 但是,就其本身而言,它不会允许任何人访问 Vault。 因此,获得 Chef 访问权限的人将无法访问 Vault。

用户 ID 不是由 Chef 提供的,应该绑定到特定的机器上。 如果您的应用程序跨实例进行冗余扩展,则每个实例都应该有自己的用户 ID。 这个用户 ID 来自哪里并不重要(尽管他们给出了建议),但它不应该来自部署 app-id 的同一个地方(即 Chef)。 正如他们所说,它可以通过其他方式编写脚本。 无论您使用什么软件来扩展实例,都可以为实例/docker 容器提供用户 ID,并将用户 ID 授权给应用 ID。 如果您不动态扩展实例,也可以手动完成。 每次人类添加新实例时,他们都会创建一个新的用户 ID,将其授权给 app-id,并通过最适合他们的任何方式将其提供给实例。

这比防火墙实例更好吗? 猜猜看。 防火墙不限制对 Vault 中机密的访问 (afaik),如果有人获得了对您的实例的访问权限,他们可以轻松进入您的 Vault。

这样一来,他们就很难把拼图的所有部分都弄明白。 更进一步,app-id 还允许使用您应该使用的 CIDR 块。 如果有人以某种方式获得了应用程序 ID 和用户 ID,他们仍然无法在没有该网络的情况下访问 Vault。

(同样,这是我在尽我所能阅读文档后的解释)

@Vanuan @mcmatthew好问题! @jaredm4非常感谢您的澄清,这肯定会对我有所帮助。 这对寻求更实际实现的每个人都非常有用!! 如果我在接下来的两周内有时间,我会再试一次!

@thaJeztah :

容器中的任何进程都可以访问,因此很容易“泄漏”

你能支持这个说法吗? 非特权进程无法访问非父进程的环境变量。 请参阅https://help.ubuntu.com/community/EnvironmentVariables#Process_locality。

为容器设置的环境变量(通过--env--env-file )_are_ 可由容器中的任何进程访问。

当然,因为它们是入口点进程的子进程。 这是该过程的工作,或者您(如果它是一个外壳程序)尽快取消设置秘密环境变量。

更相关的是具有除 0 以外的不同用户 ID 的进程是否可以在容器内部和/或外部访问这些环境变量。 当您在容器内使用的软件正确删除权限时,情况也不应该是这种情况。

我知道这是题外话,但有没有其他人注意到这个问题已经活跃了将近一整年了! 明天是它的周年纪念日。 👏

容器进程是否可以读取进程内存中的 env 变量,然后(在环境中)取消设置它们? 这是否解决了大多数运行时安全问题?

@davibe的问题在于,如果容器或其进程重新启动,那些环境变量就会消失,无法恢复它们。

我试过了,但看起来重新启动后环境变量仍然存在。

dade<strong i="6">@choo</strong>:~/work/grocerest(master)$ cat test.js
console.log("FOO value: " + process.env.FOO);
delete(process.env.FOO);
console.log("FOO value after delete: " + process.env.FOO);

dade<strong i="7">@choo</strong>:~/work/grocerest(master)$ docker run --name test -it -e FOO=BAR -v $(pwd):/data/ node node /data/test.js
FOO value: BAR
FOO value after delete: undefined

dade<strong i="8">@choo</strong>:~/work/grocerest(master)$ docker restart test
test

dade<strong i="9">@choo</strong>:~/work/grocerest(master)$ docker logs test
FOO value: BAR
FOO value after delete: undefined
FOO value: BAR
FOO value after delete: undefined

也许 docker-run 正在执行我作为 bash 的孩子的事情? 我觉得不应该。。

@戴维

unset 'SECRET_ENV_VAR'

我认为这一切的主要问题/功能是您以root身份登录 Docker,因此可以检查您放入容器中的任何内容,无论是令牌、卷、变量还是加密密钥。 .. 任何事物。

所以一个想法是从你的容器中删除sudosu并在任何ENTRYPOINTCMD之前添加一个USER命令。 任何运行你的容器的人现在都应该没有机会以root身份运行(如果我没记错的话),因此你现在实际上可以对他隐藏一些东西。

另一个想法(最好的恕我直言)是将用户和组的概念添加到 Docker 套接字和容器中,这样您就可以告诉 GROUP-A 可以访问带有 TAG-B 的容器,而 USER-C 属于 GROUP- A 所以它可以访问这些容器。 它甚至可以是每个操作的权限(GROUP-A 有权访问 TAG-B 的启动/停止,GROUP-B 有权访问 exec,GROUP-C 有权访问 rm/inspect,等等)。

在研究了几个小时后,我无法相信似乎没有官方推荐的解决方案或构建时秘密的解决方法,而像https://github.com/dockito/vault这样的东西似乎是唯一可行的选择构建时的秘密(没有压缩整个生成的图像或首先手动构建它)。 不幸的是, https://github.com/dockito/vault非常特定于 ssh 密钥,所以我尝试将其调整为托管 git https 凭证存储文件......

在似乎永远之后(最初我听说它定于 2015 年第四季度发布),AWS ECS 似乎终于兑现了他们将IAM 角色引入 docker 应用程序的承诺。 这里也是博客文章

似乎这与一些KMS 优点相结合是一个可行的近期解决方案。 从理论上讲,您只需要将机密绑定到某些委托人/IAM 角色,以防止非身份验证角色要求他们不应该做的事情,并将安全存储留给 KMS。

还没有尝试过,但它在我的候选名单上......

Kubernetes 似乎也有一些秘密处理,让我想起了很多 Chef 加密的数据包。

我知道这不是该线程的重点所在的独立于平台的 OSS 方式,
但想把这两个选项扔给那些在那些需要_NOW_的基础设施领域玩的人

我刚刚遇到了一些可能在这方面有所帮助的东西: https :

这看起来从 docker v1.10.0 开始就可用了,但直到现在我才注意到它。 我认为此时我倾向于使用的解决方案是使用https://www.vaultproject.io/来存储和检索机密,将它们存储在容器内的 tmpfs 文件系统中,该文件系统安装到 /secrets 或类似的东西. 随着新的 ECS 功能在容器上启用 IAM 角色,我相信我应该能够使用保管库的 AWS EC2 身份验证来保护对机密本身的授权。 (对于独立于平台的我可能倾向于使用他们的 App ID 身份验证。)

无论如何,对我来说,丢失的部分是一旦它们被检索到安全地放置秘密的地方。 tmpfs 选项对我来说似乎是一个不错的选择。 唯一缺少的是ECS似乎还不支持这个参数,这就是我今天提交的原因: https :

总之,恕我直言,这似乎是一个非常全面的解决方案。

@CameronGo ,感谢您的指点。 如果我理解正确,这不能用于构建良好,或者可以吗?

@NikolausDemmel抱歉,是的,您是对的。 这只是运行时机密的解决方案,而不是构建时间。 在我们的环境中,构建时机密仅用于从 Git 检索代码。 Jenkins 为我们处理这些并存储 Git 访问的凭据。 我不确定相同的解决方案是否能满足这里每个人的需求,但我不清楚构建时间机密的其他用例。

Jenkins 为我们处理这些并存储 Git 访问的凭据。

这如何与 docker 一起工作? 或者你不在容器内部git clone

在完整阅读此问题后,我相信将其分为“构建时”和“运行时”秘密的单独问题会大有裨益,它们的要求非常不同

如果您像我一样来到这里试图决定现在要做什么,那么 FWIW 我将描述我确定的解决方案,直到出现更好的解决方案。

对于运行时机密,我决定使用http://kubernetes.io/docs/user-guide/secrets/。 这仅在您使用 kubernetes 时有效。 否则保险库看起来不错。 生成的图像或临时层中的任何秘密都是一个坏主意。

关于构建时机密 - 除了分发私有代码之外,我想不出其他构建时机密用例。 在这一点上,我没有看到比在主机端执行任何“秘密”操作更好的解决方案,并添加生成的包/jar/wheel/repo/etc。 到图像。 正如一些评论中所建议的那样,在主机端保存一个生成包的 LOC 不值得冒险暴露 ssh 密钥或运行代理服务器的复杂性。

也许在 docker build 中添加一个“-v”标志,类似于 docker run 标志可以很好地工作? 它会在主机和图像之间临时共享一个目录,但也确保它在缓存或生成的图像中显示为空。

我目前正在研究使用Vault的解决方案:

  1. Builder 机器安装了 Vault 并在本地保存了一个令牌
  2. 当构建开始时,构建器机器请求一个仅在几分钟内有效的新临时令牌(基于构建,1h 甚至可以接受)
  3. 注入令牌作为构建参数
  4. Docker 映像还安装了 Vault(或在构建过程中安装和删除它)并使用此令牌可以获取真正的秘密

重要的是在同一命令中删除秘密,因此当 docker 缓存给定层时,没有剩余。 (这当然只适用于构建时间秘密)

我还没有建立这个,但正在努力。

@kozikow的评论有些相关:“关于构建时机密 - 除了分发私有代码之外,我想不出其他构建时机密用例。”

也许不是专门的构建时间秘密,但我有一个用例需要(保护)在 Dockerfile 中的构建时间期间的密码,以便允许通过 RUN curl 命令下载已经构建的工件。 构建时下载需要用户凭据进行身份验证才能获取工件 - 因此我们现在将密码作为 Dockerfile 中的环境变量传递(我们仍在开发中)。 构建在幕后自动发生,因为我们使用 OpenShift,并且 Dockerfile 中的环境变量在构建期间输出到日志,就像任何 docker build 命令一样。 这使得可以访问日志的任何人(包括我们的开发人员)都可以看到密码。 我一直在拼命想办法发送密码,以便它可以在 docker 构建期间使用,但随后没有将密码输出到日志中或最终出现在任何层中。

我也赞同@wpalmer所说的将这个线程分解为运行时和构建时的内容。

我认为为任何人提出的任何(运行时)秘密机制定义一些测试可能是值得的。 因为这个线程上有很多人提倡非常弱的安全性。

首先,我建议:

  • 秘密没有出现在 docker inspect 中
  • 进程 1 启动后,该机密在可从容器访问的任何文件中不可用(包括卷安装文件)
  • 该秘密在 /proc/1/cmdline 中不可用
  • 秘密以加密形式传输到容器

上面建议的任何违反其中之一的解决方案都是有问题的。

如果我们可以就秘密应该遵循的行为的定义达成一致,那么至少这将淘汰不适合目的的无尽解决方案。

@gtmtech很好的建议:)

进程 1 启动后,该机密在可从容器访问的任何文件中不可用(包括卷安装文件)

我不确定我是否同意这一点。 虽然我确实同意它应该只能从容器(理想情况下在内存中)访问,但在某些情况下,应用程序需要时间来“启动”并且不能从其下删除文件。 我认为在容器运行期间内存中的某些内容(在停止时删除)是更好的方法。

我将添加到运行时要求列表中:

  • 引导第一个秘密时的容器身份验证/授权。

例如,Vault 提供AppRole 后端的授权,但在容器如何识别自己方面是开放式的。

几周前, Nick Sullivan 介绍了 Cloflare 的 PAL 项目,并承诺很快将其开源,这应该会为使用 docker notary 的身份验证问题提供一个潜在的答案。

从应用程序的角度来看,有三种方法可以解决这个问题:

  1. 从环境变量中获取秘密。
  2. 从文件中获取机密。
  3. 从另一个系统获取秘密。

上面的 1 和 #2 通常是最常见的,因为大多数应用程序都支持这种机制。 #3 可能更理想,因为它留下的“碎屑”最少,但应用程序必须专门为此开发,并且通常仍然需要有凭据才能获取秘密。

Docker 是关于多功能性和支持各种各样的用例。 在此基础上,从应用程序的角度来看,1. 和 2. 最有吸引力,尽管它们都在系统上留下了“碎屑”。

我当然使用的一种常见方法是通过入口点脚本注入秘密(例如,在 AWS 中使用 credstash 或普通 KMS 之类的工具并结合 IAM 角色)。 在这方面,您实际上在入口点脚本中执行了上面的 #3,并且执行了 #1(设置环境变量)或 #2(写入文件)。 这种方法是动态的,对于 #1(环境变量),不会在 docker 日志或 docker 检查中公开凭据。

入口点方法的好处是您将机密管理的关注点与应用程序分开。

这是 Docker 可以添加功能以避免必须使用滚动您自己的入口点脚本的区域。 Docker 喜欢插件,并且可以在容器生命周期中提供一个钩子,它可以支持“秘密”提供者插件,它本质上执行手动入口点脚本的功能并将秘密注入容器(通过内部环境变量或文件)。 所以你可以拥有一个 Hashicorp Vault 秘密提供者、一个 AWS KMS 秘密提供者等。Docker 或许可以拥有自己的基于使用 RSA 加密(通过数字证书)的提供者。 整个概念与 Kubernetes 的秘密概念大致相似,后者在容器文件系统上呈现秘密。

当然,您如何授权访问机密提供者是一个复杂的问题,无论如何,这都是您今天面临的问题。 使用 Hashicorp,您可能会发布并传递一次性/限时令牌进行身份验证,使用 AWS 是 IAM 角色,使用我提到的 Docker RSA 加密方法,它可能只是传递使用 Docker 引擎公共证书加密的秘密。

这个线程很棒。 我希望我们能看到更多这样的帖子,来自社区和各行各业的人们能够分享他们的经验、想法和解决方案。

“秘密零”问题是一个棘手的问题。 构建时还是运行时? 两者都有其优点和缺点,以及明显的安全措施和缺陷(以及黑客和变通办法!)。

也就是说,我一直在思考如何将通行证/密钥的管理归结为应用程序和/或服务。

在接下来的几个月里,我们将要做的事情是通过键/值对构建一个共享的全局配置支持服务,由 Consul 分发并作为环境变量提供(或者在不支持使用环境变量的情况下注入)。 这仅支持您的不安全值。 为了安全起见,我们将转移到 Vault 并将其视为支持服务 - 很像数据库或任何其他依赖项。

代码、配置和机密将通过支持服务提供。 在这种情况下,我们使用 Stash、Consul 和 Vault。 只要依赖项存在,就可以根据需要提取配置和机密。

我在任何地方都没有看到这是一个可靠的解决方案,因此我在这里发布它。 但是为了将其带回到本主题的目的,我们将尝试使用一种方法来解决 Docker/secret 问题。 我们将构建本机支持这一点的应用程序,而不是依赖于它们运行的​​框架和平台。

关于构建时的秘密,事实证明, Rocker 的MOUNT指令可用于创建 _only_ 在构建时存在的临时目录和文件。 他们的一些模板功能在这种情况下也可能有所帮助,但我还没有彻底使用它们。

我很想看到这个功能作为 Docker 核心中的 Builder 插件实现(以及 Rockerfiles 的一些其他有用的功能)!

我看到目前在 OP 中的所有 4 个提案都是关于秘密存储的🙁

我想说 docker 应该有助于将秘密/密码传递给 _docker 实例_,但是存储/管理这些秘密是(并且应该)超出了 docker 的范围。

当_传递一个秘密_时,我会说一个运行参数几乎是完美的,除了通常会记录下来。 因此,我会将其范围缩小到非明文参数功能。 一种方法是对每个 docker 实例生成的密钥使用加密。

至于_如何管理机密_,我会说用户想要的任何内容,从自制 bash 脚本到通过Kubernetes 等软件进行集成。

正如@agilgur5之前所说的那样,仅仅像摇杆支架一样实现 MOUNT 有什么问题? 我不敢相信这场争论已经持续了这么久,以至于一个团队不得不有效地分叉docker build命令以满足这个非常简单的用例。 我们需要混合使用另一个 HTTP 服务器吗? 吻。

我在这个subjet上花了很多时间......

目前,我发现在构建阶段管理机密的最佳方法是在两步内构建,因此是两个 docker 文件。 这里有一个很好的例子

[Habitus] (http://www.habitus.io/) 似乎是另一种选择,但就我而言,我不想添加其他工具,主要是因为我希望 CI 服务器和用户计算机上的构建过程保持简单/相同。

那么 docker-in-docker (dind) 方式呢?

这是一个使用 dind 构建的两步示例,就像我上面刚刚谈到的: https :

随意评论...

有趣的。 有点让我想起 OpenShift 是如何构建的。

在我看来,您是在命令行中传递密码。 有什么办法吗?

请注意,此处有一个针对构建时机密的正在进行中的 PR; https://github.com/docker/docker/pull/28079 (服务的运行时机密将在 docker 1.13 中,请参阅 https://github.com/docker/docker/pull/27794)

@thaJeztah :
关于#28079,当我看到过去两年围绕这个主题的如此多的公关失败时,我有点悲观......
我不想将 swarm 作为依赖项。 我的部分客户使用另一个集群协调器。

@卡修萨
我不明白你的意思?
1/ 密码被传递给“容器构建器”,它不是最终图像。 此构建器执行 docker 构建并基于 Dockerfile.realease 生成图像。 最终图像的历史记录中没有存储任何秘密。
2/ 如果您不想将密码传递给命令行,请随意使用 docker-compose(示例

@BenoitNorrin我认为未来可能会扩展到非群体,但@diogomonica可能

听起来像这样:

这目前仅适用于 Swarm 模式,因为后备存储是 Swarm,因此仅适用于 Linux。 这是 Docker 未来秘密支持的基础,具有潜在的改进,例如 Windows 支持、不同的后备存储等。

如果它以与摇杆相同的方式实现,那就太好了,可以
简单,不需要是“企业”。

2016 年 11 月 29 日,星期二,15:53 Michael Warkentin, notifications @github.com
写道:

听起来像这样:

这目前仅适用于 Swarm 模式,因为后备存储是 Swarm 并且作为
这仅适用于 Linux。 这是未来秘密支持的基础
具有潜在改进的 Docker,例如 Windows 支持、不同的
后备店等


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/docker/docker/issues/13490#issuecomment-263608915
或静音线程
https://github.com/notifications/unsubscribe-auth/AAZk5vlLwsBHHTTbUS_vvx-qTuwnkp6Oks5rDEpjgaJpZM4Eq021
.

一个认为的解决方案是加密从docker-compose文件传递的信息的某些部分。

例如,运行docker inspect ,加密信息应显示/标记为 _encrypted_。 然后docker inspect --encryption-key some_key_file将显示所有未加密的加密信息。

另一方面,在容器内部,应用程序应该能够实现不同的机制来访问和解密这些加密信息以供其使用。

我认为加密_是关键_ :)

目的是为了我的(真的,真的,真的很常见)用例是构建一个
来自需要身份验证的 git 服务器的软件项目,两者都用于
项目及其依赖项。 Rocker 通过允许安装来固定它
构建期间的文件或目录(在本例中为 SSH 代理套接字)

2017 年 1 月 3 日星期二 04:14 Hisa, notifications@ github.com 写道:

一个认为解决方案是加密传递的信息的某些部分
来自 docker-compose 文件。

例如,运行 docker inspect ,加密后的信息应该是
显示/标记为已加密。 然后 docker inspect --encryption-key
some_key_file 将显示所有未加密的加密信息。

另一方面,在容器内的应用程序应该能够实现
访问和解密这些加密信息以供他们使用的不同机制。

我认为加密是关键:)


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/docker/docker/issues/13490#issuecomment-270049742
或静音线程
https://github.com/notifications/unsubscribe-auth/AAZk5qEphZo5SR9vOWVL5dck50EPadpVks5rOcsUgaJpZM4Eq021
.

由于我没有看到它提到,这里是另一篇关于在 AWS ECS 中处理机密的好文章: https :

Docker 1.13 中有一个新的“docker secret”命令。 当该功能的文档足以满足此处提到的用例时,应该能够关闭此问题。

docker secret 命令目前看起来仅适用于 Docker Swarm(即 docker 服务),因此目前不适用于通用 Docker 容器。

另外docker secret仅管理运行时机密,而不管理构建时机密。

哇。 就像产品管理团队中没有人考虑过
除了未经身份验证的开源软件之外的任何东西的用例
内置于 docker 容器或除 golang 之外的任何语言,其中所有
依赖项被复制和粘贴,抱歉,“版本化”到 Git 存储库中。

我只是无法理解人们怎么会如此愚蠢。 仅有的
我能想到的解释是产品管理团队不是
从业者从未使用过该产品。 我经常看到这个
特点在组织招聘时表现出来
jira/敏捷技能。

我会一直使用摇杆直到 2019 年,或者每当有人觉得有意义的时候。

2017 年 1 月 22 日星期日,Shane StClair,23:47, notifications@ github.com 写道:

此外,docker secrets 只管理运行时的机密,而不管理构建时的机密。


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/docker/docker/issues/13490#issuecomment-274370450
或静音线程
https://github.com/notifications/unsubscribe-auth/AAZk5vJVJe4OeypWd1Cwqmh8Gzyn8P-mks5rU-qqgaJpZM4Eq021
.

我收回最后一条评论,抱歉,我在发泄。 只是沮丧
简单的边缘案例通常似乎是一个强加一些东西的机会
像 consul 或创建一些真正过度设计的东西,而不仅仅是
实现一些像构建时间挂载一样简单的东西。

2017 年 1 月 23 日星期一09:31 Bryan Hunt,

哇。 就像产品管理团队中没有人考虑过
除了未经身份验证的开源软件之外的任何东西的用例
内置于 docker 容器或除 golang 之外的任何语言,其中所有
依赖项被复制和粘贴,抱歉,“版本化”到 Git 存储库中。

我只是无法理解人们怎么会如此愚蠢。 仅有的
我能想到的解释是产品管理团队不是
从业者从未使用过该产品。 我经常看到这个
特点在组织招聘时表现出来
jira/敏捷技能。

我会一直使用摇杆直到 2019 年或任何人认为有意义的时候
然后。

2017 年 1 月 22 日星期日,Shane StClair,23:47, notifications@ github.com
写道:

此外,docker secrets 只管理运行时的机密,而不管理构建时的机密。


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/docker/docker/issues/13490#issuecomment-274370450
或静音线程
https://github.com/notifications/unsubscribe-auth/AAZk5vJVJe4OeypWd1Cwqmh8Gzyn8P-mks5rU-qqgaJpZM4Eq021
.

@binarytemple现在每个人都想要所有功能。 如果东西还没有准备好,那么它只是没有准备好。 限制新功能的范围绝对不是坏事,因为即使范围有限,也总有改进的空间。

如果有人真的很热衷于获取功能,那么他们应该与维护者讨论他们如何为此贡献工作。

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

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

这些实现似乎分为两个阵营。
1) 通过“平台”提供的卷挂载或 (chef/docker secret/k8s) 传递秘密
2)传递凭据以与外部服务对话以在启动时获取内容(iam/credstash/etc)

我想我希望看到更多类似第二个选项的内容。 在第一个选项中,我认为没有足够的关注点分离(启动的事情也可以访问所有密钥),但这是偏好,就像系统构建中的其他所有事情一样,每个人都喜欢做不同的事情.

我很高兴 docker 已经采取了这第一步,并希望docker run的更通用机制由此产生(以支持营地 #2)——这意味着我不认为这个线程是初始任务已完成,不应关闭。

喜欢!
非常简单但非常有效的设计

@bacoboy , @mixja - 单节点群和单容器服务还不错
docker swarm init , docker service create replica=1

对我来说,从现在开始,docker swarm 将成为运行容器/服务的默认设置是合乎逻辑的。

我认为这个新的基于 swarm 的提议只会影响运行时的秘密是否正确? 我真的认为没有必要对运行时机密进行特殊处理,因为已经有很多方法可以将机密放入正在运行的容器中。

构建时的秘密很重要,据我所知,这个提议没有解决它们。

要注入构建时机密,我们现在可以使用docker build --squash安全地执行以下操作:

COPY ssh_private_key_rsa /root/.ssh/id_rsa
RUN git pull ...
RUN rm -rf /root/.ssh/id_rsa

--squash标志将为整个 Dockerfile 生成单个层:不会有秘密的痕迹。

--squash在 docker-1.13 中作为实验标志可用。

@hmalphettes这意味着您错过了构建之间共享较低层的好处。

这绝对不是壁球的本意。 我在添加这样的秘密时仍然非常小心。

@zoidbergwill下层仍然共享。

我 100% 同意@cpuguy83。 依靠构建时间标志来保密是非常冒险的。 有一个关于构建时间的提案 PR (https://github.com/docker/docker/pull/30637) 我将在 rebase 上工作以获得更多反馈。

@wpalmer如果您有自动镜像构建,您的工具应该知道如何获取构建时的秘密。

例如,您可能希望将构建时机密保存在烘焙到映像中的 Ansible 加密保管库中,并授予从该映像运行的容器访问保存保管库密码的运行时机密的权限。

WDYT?

为什么我们总是将构建时机密与运行时机密混淆? docker(或 kubernetes 等相关工具)已经有很多好方法来提供运行时机密。 唯一真正缺少的是构建时的秘密。 这些秘密在运行时不使用,它们在安装时使用,例如可以是内部存储库。 我在本主题和相关主题中看到的唯一工作方式(但也建议不要这样做)是在构建期间将 http 服务器暴露给容器。 http 服务器方法使实际获取这些秘密的事情变得非常复杂。

+1 构建时间秘密!= 运行时间秘密

正如保罗指出的那样。 不希望烘焙内部存储库
凭据到图像中。

为什么这很难理解?

2017 年 2 月 16 日星期四,14:42 Paul van der Linden, notifications@ github.com
写道:

为什么我们总是将构建时机密与运行时机密混淆? 那里
docker(或 kubernetes 等相关工具)已经有很多好方法
提供运行时机密。 唯一真正缺少的是构建时间
秘密。 这些秘密在运行时不使用,它们在运行期间使用
安装时间,例如,这可能是内部存储库。 唯一的
我在这个和相关主题中看到的工作方式(但也建议
反对它),在构建期间将 http 服务器暴露给容器。
http 服务器方法使实际访问变得安静复杂
那些秘密。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/docker/docker/issues/13490#issuecomment-280348116
或静音线程
https://github.com/notifications/unsubscribe-auth/AAZk5h0Z2OGwApVnLNEFWKRdOfGxLOmRks5rdGBagaJpZM4Eq021
.

@pvanderlinden您也可以通过两步构建来做到这一点。
这里有一个例子: https :

@timka如前所述,将凭据放入图像中是不可取的,因为这会带来安全风险。 这是构建时间秘密的建议: https :

@BenoitNorrin不确定在我(和其他人)的用例中会如何。
当我开始 docker 构建过程时,需要安装的包已经构建好了。 但是 docker build 需要安装这些包,它需要访问内部 anaconda 存储库和/或 pypi 服务器 (python)。 位置和密码当然是私人的。
看起来#30637 是另一个尝试,希望这会在 docker 中结束!

@timka你消息的前半部分似乎提到了构建时的秘密,但后半部分明确地谈到了运行时的秘密。 运行时的秘密很简单。 我目前针对构建时机密的“解决方案”是预先运行一个完全独立的步骤,该容器使用运行时机密获取私有数据。 在运行常规docker build命令之前,另一个步骤将其合并到树中。

如果构建时机密是标准功能,另一种方法是在 Dockerfile 中运行这些步骤。

我的工具确实知道如何自动运行这些步骤,但我需要自己烘焙这个,对于这样一个共同的愿望来说,这有点荒谬。

仅供参考,我写了https://github.com/abourget/secrets-bridge来解决构建时的秘密问题。

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

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

亚历山大,你所做的非常有创意和技巧。 它只是
让我感到难过的是有必要跳过所有这些步骤只是为了
如果“docker build”支持“mount”,则可以实现相同的效果
命令而不是盲目地坚持将所有东西都复制到
容器。

我是我的情况,我将放弃“docker build”,而是使用摇杆或
如果我自己创作的东西。

2017 年 7 月 13 日星期四,16:23 Alexandre Bourget,通知@ github.com
写道:

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

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

服务器支持 SSH 代理转发,通过 TLS 隧道传输
网络套接字通信。 它也适用于 Windows!


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/13490#issuecomment-315111388或静音
线程
https://github.com/notifications/unsubscribe-auth/AAZk5hZqTAgPBjS9cFP_IsYNa9wv-yoAks5sNjaBgaJpZM4Eq021
.

这是最新的秘密提案: https :

我认为上一个 Docker CE 版本中包含的新“多阶段构建”功能解决了我们的很大一部分问题。

https://docs.docker.com/engine/userguide/eng-image/multistage-build/

为执行Dockerfile命令而生成的容器带有熟/dev并且在那里所做的任何更改都不应记录到图层中。 docker 可以通过该挂载点传送用户机密吗? 它/dev/init类似的方式提供

这仍然非常重要,因为带有参数的多阶段构建不会泄漏到图像中,但仍将您的秘密作为正在运行的系统上的进程列表的一部分公开,因此它并没有真正解决。

现在是 2017 年 8 月。与此同时,原始问题中的“处理机密的旧建议”链接到 2014 年的问题。

对于构建时的秘密,仍然没有好的解决方案。 提供--build-time-secret标志的 PR 被关闭,没有任何解释。 “那么,需要什么?”中没有任何内容。 节实施。

同时

新上任的 CEO Steve Singh 专注于商业客户
最新一轮 7500 万美元用于帮助组建销售、营销团队


UPD。:正如@cpuguy83在下面正确且正确地指出的那样,提案的完整摘要在#33343

我知道它不是内置的,但secrets-bridge现在工作得很好。

@dmitriid我理解您对缺少此功能感到沮丧。 然而,这不是解决开源社区(或任何社区)的方法。

我在上面发布了一个提案的链接,除了我自己的之外,我看到了 0 条评论。

这是最新的秘密提议:#33343

@cpuguy83 太棒了! 我有点跳过了这个讨论的最后三分之一(和其他一些),因为它有很多东西要阅读(同时寻找解决方案),所以我真的很想念你的评论,抱歉:(

这个话题始于 2015 年。

现在是 2017 年。

为什么没有解决方案可以解决既不黑客又不可怕的构建时机密? 对于很多人来说,这显然是一个大问题,但仍然没有真正好的解决方案!

@mshappe

为什么没有解决方案可以解决既不黑客又不可怕的构建时机密?

因为这是一个很难正确解决的问题,而且会被数以百万计的人使用。

请看我在你上面的评论:

我在上面发布了一个提案的链接,除了我自己的之外,我看到了 0 条评论。
这是最新的秘密提议:#33343

如果你想看到某些东西被实现,那么你需要做的不仅仅是抱怨某些东西没有被实现。 请对提案发表评论!

这么容易解决。 它只是需要一些东西,任何不需要的东西
烘焙到图像中。 而且其实很容易解决,别用了
'docker build' 并使用 python API、rocker 或其他任何东西。

2017 年 8 月 23 日星期三晚上 9:42,Brian Goff通知@github.com
写道:

@mshappe https://github.com/mshappe

为什么没有针对非黑客的构建时机密的解决方案
可怕吗?

因为这是一个很难正确解决的问题
将被数以百万计的人使用。

请看我在你上面的评论:

我在上面发布了一个提案的链接,并且看到了 0 条评论
除了我自己的。
这是最新的秘密提议:#33343
https://github.com/moby/moby/issues/33343

如果你想看到一些实现,那么你需要做的不仅仅是
抱怨某些事情没有实施。 请对提案发表评论!


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/13490#issuecomment-324441280或静音
线程
https://github.com/notifications/unsubscribe-auth/AAZk5oEpcipmfCji1mXz6MOVt0p6-OA6ks5sbIC0gaJpZM4Eq021
.

@binarytemple我已经开始将 Rocker 视为替代方案,实际上……但只是因为这个奇怪的心理障碍 docker 似乎对构建时的秘密有所了解。

有点奇怪。 我和人们交谈,他们正在做各种愚蠢的黑客攻击
就像使用 HTTP 服务 - 扔掉所有东西(监控/粒度
权限/简单性)POSIX/SELinux 组合提供。 我只是不
理解。 拒绝对我来说似乎不合逻辑。

2017 年 8 月 23 日,星期三,23:03 Michael Scott Shappe通知@github.com
写道:

@binarytemple https://github.com/binarytemple我已经开始看
摇杆作为替代品,其实……但只是因为这个奇怪
心智块 docker 似乎有关于构建时的秘密。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/13490#issuecomment-324461257或静音
线程
https://github.com/notifications/unsubscribe-auth/AAZk5ppZYsOhdfvgotCUk5l41Truo_EEks5sbJOLgaJpZM4Eq021
.

多阶段 docker build 解决了很多这些问题。

以最简单的形式,您可以将秘密作为 build-args 注入,并且它们只会成为明确表明它们需要参数的图像的图像历史的一部分。 正如neclimdul 指出的那样,这些秘密将在构建期间的进程列表中可用。 IMO 不是大问题,但我们采取了另一种方法。

我们的构建服务器运行时将一些秘密安装为卷,因此我们在 f.ex 中的 CI 副本。 /mnt/secrets/.npmrc 进入当前工作目录。 然后我们使用一个类似于下面的 Dockerfile。

FROM node:latest
WORKDIR /usr/src/app
COPY .npmrc .
RUN echo '{ "dependencies": [ "lodash" ] }' > package.json
RUN npm install
RUN ls -lah

FROM alpine:latest
WORKDIR /usr/src/app
COPY --from=0 /usr/src/app/node_modules ./node_modules
RUN ls -lah
CMD ["ls", "./node_modules"]

生成的映像将具有已安装的依赖项,但没有 .npmrc 或其内容的任何痕迹。

使用多阶段构建可以让您完全控制如何向构建过程公开构建时间秘密。 您可以通过卷(我们从 Kubernetes 中的 Secrets 存储安装)从 Vault 等外部存储获取机密,在存储库中对它们进行 gpg 加密,Travis 机密等。

当为此用例使用多阶段构建时,请确保您意识到机密数据将保留在本地守护程序中的未标记图像中,直到该图像被删除,以便此数据可用于后续构建中的构建缓存。 但是在推送最终标记的图像时不会推送到注册表。

@androa我喜欢那个解决方案,但我不确定我对复制到工作目录的秘密的感受。 这在私有 CI 服务器上可能没问题,但对于本地构建来说并不是那么好,在那里您将复制不应超出受保护位置的文件(更不用说复制本身既烦人又危险,因为它们可能会意外结束在源代码管理中)。 另一种选择是使用更广泛的 Docker 构建上下文,但对于许多可能意味着整个根卷的常见秘密。 关于如何使本地和 CI 变得更好的任何建议?

这是骇人听闻的。 这个自称为“世界领先的软件容器平台”的公司在过去 3 年里都懒得将构建时的秘密安全地传递到容器中。

通过“我们知道得更好”和“不要让软件允许错误”的方法以及在设计阶段最多可以描述为不幸的遗漏,DevOps 软件所需的功能之一没有支持,也没有明显的进展。 由于担心有人滥用它们,所有社区建议甚至有时甚至发展到可以合并的改进都被关闭。 由于这个集群......失败,所有传递仅在 docker 容器的构建阶段所需的私钥的方法都需要将这些秘密保存在构建历史中,或者在进程列表中可见,并希望构建历史永远不会离开受信任的机器或不应该看到进程列表的人。 即使是最宽松的安全审计,这两者都会失败。

这个问题已经开放了 2 年多,以总结当时对该问题的了解以及如何处理。 仍然没有解决办法。 我的意思并不是说一个全面的解决方案将支持开箱即用的最复杂的秘密管理方案。 根本没有解决方案,没有主机环境变量,没有从构建上下文之外的文件路径加载机密。 即使在最不严格的条件下,也没有任何东西可以被认为是安全的。

@OJezu正如我在这个问题上说多次,有一个开放的建议与它基本上0条评论。
如果你想看到推进的秘密,那么请花时间对提案发表评论。

下一次尝试提出问题并至少阅读有关您正在评论的问题的最新评论,而不是突然袭击每天从事此工作的人。

当真的只有人在努力工作时,事情往往看起来停滞不前。
对于构建,请参阅 github.com/moby/buildkit,其中大部分工作都在今天进行。

谢谢。

我有点醉了,因为今天我花了 9 个小时试图找到一个不应该成为问题的解决方案,尤其是在一个正在全职工作并将自己定位为事实上的标准和解决方案的项目中. 在写这些评论时,我非常努力地不发誓并停止自我伤害。

我查看了那个问题,并看到了两个解决方案的参考,一个自 4 月以来停滞不前,另一个已经关闭。 我不禁注意到,0 评论提案有 4 个参与者,评论数量相同,并提到了一些明显的内部讨论,我猜是更熟悉 . 但是如果你想从一个甚至不会用 Go 编程的人那里得到更多的反馈,我可以提供更多关于我在之前的评论中提到的问题的想法。

@OJezu

至少有一个简单的解决方案:使用专用服务(例如在 Jenkins 上运行)来构建工件。
该服务将安全地提供访问您的图像所依赖的工件所需的所有密钥。
完成后,工件将被放置到一个安全的位置(例如 Jenkins)。 这些工件不会包含任何秘密,只是一个包含二进制文件/源/等的目录。
然后另一个服务(例如另一个 Jenkins 工作)将访问那些预构建的工件并将它们转换成一个图像,该图像可以安全地推送到一个图像注册表,而后者又使用 rbac/keys 从开发人员/生产机器访问它们而受到安全保护。

即 docker 镜像构建过程与任何其他构建系统没有什么不同:你必须有一个构建管道。

Build pipeline

@Vanuan并非所有语言的打包和安装都那么简单,只需使用工件进行安装。

例子?

Python 项目在安装时间而不是构建时间上提出了他们的要求。 在我们的例子中,来自私人 pypi/conda 存储库(受密码保护)

所以? 将安装作为构建过程的一部分,然后将安装的包复制到新映像。

您只需要确保您的构建映像和生产映像基于相同的 Python 基础映像。

您确实可以将所有内容复制到新图像中。 不过,这消除了 Dockerfile 的全部意义。 如果您唯一可以使用 Dockerfile 的目的只是复制一组目录,为什么要使用 Dockerfile?

所以,我不能有一个简单的流程,我只是在任何地方运行docker build . - 无论是在开发机器上还是在 CI 上,但我必须依赖 CI 来构建包。 为什么还要打扰 docker 呢? 我可以写一个travis文件,或者用bamboo配置流程。

您不能在第一阶段构建中仅pip install requirements.txt使用可从您的私有存储库中提取的机密。 然后下一阶段构建只是从第一阶段复制站点包。

如果您唯一可以使用 Dockerfile 的目的只是复制一组目录,为什么要使用 Dockerfile?

为什么不? 使用 Dockerfile 构建是一致的。

图像规范不仅仅是一堆压缩文件。 有环境变量、命令行参数、卷等

阅读 Dockerfile 参考:
https://docs.docker.com/engine/reference/builder/

看起来您一直主要关注RUN指令,认为 Dockerfile 是您 Makefile 的替代品。 它不是。 Dockerfile 仅用于一件事:从一些源材料中构建图像。 源材料是什么——通过 http 或 git 存储库下载的二进制文件——并不重要。 Docker 不需要成为您的 CI 系统,即使您可以在某些条件下将其用作 CI 系统。

我可以写一个travis文件,或者用bamboo配置流程。

如果您可以获得构建过程的结果,然后在没有图像和容器的情况下在另一个环境中运行它,那么您肯定不需要打扰 docker。 你为什么要?

单独的、严格控制的环境可以保证在构建之间重置,但前提是构建步骤发生了变化。 能够在任何地方运行它,不仅仅是在 CI 服务器上(如 Travis),将构建指令与代码联系起来,我认为如果为不同的代码分支构建更改(例如,仅在一个分支上更改运行环境的版本),这是很好的。 在开发人员机器上运行构建容器的可能性,允许将整个环境传送给不知道如何升级自己的系统的开发人员,但将能够在与其他人相同的环境下在本地构建应用程序。

如果我不想要所有这些,我会坚持使用 lxc + ansible,然后不需要 docker。

你不需要docker build

你不需要docker build

当然,您也可以为每个项目提供自定义的Makefilebuild_image.sh脚本,而不是单个自给自足的 Dockerfile,但这有多个缺点:

  • 跨平台兼容性:通过提供 Dockerfile,我知道任何可以运行docker build都可以构建映像。 通过提供自定义的Makefilebuild_image.sh ,我必须手动确保它们在我想要支持的所有平台上工作。
  • 用户的已知界面:如果您了解 docker,即使不查看 Dockerfile(例如,关于缓存等),您也知道docker build用于任何项目的一些行为。 如果我有一个自定义的Makefilebuild_image.sh ,对于每个项目,我需要首先找出要构建、清理的命令,结果的位置和形式,如果有是一些缓存,以什么形式,...

哦,Dockerfile 远不能自给自足。 特别是对于开发环境。
考虑一下:

  • 大多数开发人员不知道docker build所有不同选项,但几乎每个人都知道如何运行 bash 脚本
  • docker build取决于上下文目录。 因此,除非您愿意等待千兆字节的数据(您的带有依赖项的源代码)从一个位置传输到另一个位置以对每个源代码行进行更改,否则您不会将其用于开发。
  • 除非你从头开始构建一切,否则你依赖于docker 注册表
  • 您很可能会依赖操作系统存储库(无论您使用 Debian 还是基于 Alpine 的映像),除非您将容器直接启动到静态构建的二进制文件
  • 除非您将所有内容都提交给 git,否则您将拥有一些项目级别的依赖项,无论是 npm、python 包索引、rubygems 还是其他任何东西。 所以你将依赖于一些外部包注册表或其镜像
  • 正如大多数人在这里注意到的那样,您将依赖一些秘密包位置来获取您无法发布到公共存储库的私有依赖项,因此您将依赖于该位置
  • 访问该安全位置需要秘密配置,因此您将依赖某些系统将秘密分发给开发人员
  • 除了 Dockefile,您还需要 docker-compose.yml,而且它不是跨平台的:您仍然依赖于forward-/backslash 差异

跨平台兼容性:通过提供 Dockerfile,我知道任何可以运行 docker build 的系统都可以构建镜像。

Dockerfile 不能确保跨平台兼容性。 您仍然需要为多个平台提供多个 Dockerfile。 “可以运行 docker build”不再意味着“使用 Linux”。 Docker 还支持 Windows 本机映像。 如果你想在 Windows 主机上运行专门针对 Linux 机器的东西,你仍然必须使用 Cygwin + Linux VM。

哦,我什至没有提到 x86 vs ARM ......

用户的已知界面:如果您了解 docker,即使不查看 Dockerfile,您也知道 docker build 对任何项目的一些行为

除非你不这样做。 每个人都知道如何在没有参数或单个make命令的情况下运行 bash 脚本。 很少有人知道如何为docker builddocker rundocker-compose正确指定所有不同的命令行选项。 您不可避免地会有一些包装器 bash 或 cmd 脚本。


出于对 Docker 人员所做的一切应有的尊重,我认为您要求的太多了。 恐怕 Mobyproject 没有如此广泛的范围来支持所有可以想象的开发工作流程。

我不会单独反驳你的所有观点。 首先,您当然总能找到“单个 Dockerfile”方法根本不起作用的情况。 但是,我认为,对于您提出的几乎所有观点(所有观点都是有效且相关的),“自定义脚本或 makefile”方法要么同样糟糕,要么更糟。 举一个例子:

大多数开发人员不知道 docker build 的所有不同选项,但几乎每个人都知道如何运行 bash 脚本

如果我参与了 10 个项目,并且它们都使用 Dockerfile,那么我只需要学习一次 docker,但是根据您的建议,我需要学习 10 个完全不同的构建脚本。 如何擦除缓存并重新开始项目 Foo 的build_image.sh ? 不清楚。 如果构建图像是用docker build ,很明显(ofc 我需要知道 docker 是如何工作的,但我也需要这样做以使用来自build_image.sh )。

总的来说,我想我和其他人试图提出的观点是,对于 /many/ 场景,“单个 Dockerfile”方法似乎对人们非常有效(这是 docker 如此受欢迎的原因),特别是在开源世界,通常所有资源都可以在没有秘密的情况下访问。 但是,如果您尝试在部分资源需要凭据才能访问的上下文中应用您喜欢的相同模式,则该方法会失效。 已经有许多技术上不太复杂的方法来使其工作的建议(和实现),但在很长一段时间内没有任何结果(这已在上面多次放置)。 于是就有了挫败感。

我很欣赏人们为此付出的努力,例如 #33343 中的链接提案。 我的帖子是关于激励一些人什么以及为什么他们不断回来这里要求它。

出于对 Docker 人员所做的一切应有的尊重,我认为您要求的太多了。 恐怕 Mobyproject 没有如此广泛的范围来支持所有可以想象的开发工作流程。

在我看来,大多数人在这里要求的并不是那种东西,而只是一种在docker build中使用机密的简单方法,其安全性不低于在自定义build_image.sh使用机密的安全性

对不起,这张票中的每个人都有一个略有不同的用例。 这些都是极端情况,需要不同的解决方案。

  1. 我想在开发机器上运行生产映像。 使用 docker 注册表
  2. 我想要一个分布式 CI 系统,以便每个开发人员都有一个可重现的构建。 使用docker run构建您的项目,使用docker prune进行清理
  3. 我想构建 docker 镜像,以便我可以分发它们。 使用专用 CI 服务器,您可以在其中运行多阶段构建。

@Vanuan ,所以我猜你的方法基本上是:不要使用 docker build,除了基本环境之外的任何东西。 这是为了改变这一点而创建的问题。 “你必须以不同的方式去做”是问题,而不是解决方案。

推动这个问题的人希望对 docker 镜像有更简单、更直接的方法,而不必绕过 docker 的限制。

对于任何感兴趣的人:我曾尝试利用像 FTP_PROXY 这样的“默认屏蔽”构建参数来构建上下文。 docker-build 不会将这些屏蔽的 args 暴露给图像元数据或图像层这一事实是安全的。

36443 试图将其扩展为名为SECRET的构建参数,以便我们鼓励用户将其用作解决秘密管理问题的简单方法。

但是,这项工作已被合理拒绝,因为将来无法保证这些构建参数的掩蔽性质。

之后,我的最好的办法是遵循@AkihiroSuda建议,使用docker build --network或工具,如体质存储/通过临时TCP服务器唯一可见的构建上下文住单泊坞窗内的守护进程,在最广泛的传递秘密。

部分评论,所以我在 5 年后收到通知,当 Docker 最终决定在正确的凭据管理方向上向我们迈出一小步时......而且,还概述了我目前正在使用的 hack ,帮助他人,或在其中戳破我不知道的漏洞。

在关注@mumoshu问题后,我终于得到了使用预定义参数作为构建机密的提示。

所以,本质上,我可以使用 docker-compose 和这样的映射:

  myProject:
    build:
      context: ../myProject/
      args: 
        - HTTPS_PROXY=${NEXUS_USERNAME}
        - NO_PROXY=${NEXUS_PASSWORD}

然后,在 docker-compose.yml 文件所在的文件夹中,创建一个名为“.env”的文件,其中包含 NEXUS_USERNAME 和 NEXUS_PASSWORD 的键值对 - 以及那里的正确值。

最后,在 Dockerfile 本身中,我们像这样指定我们的运行命令:
运行 wget --user $HTTPS_PROXY --password $NO_PROXY

并且不要在 DockerFile 中将它们声明为 ARG。

我还没有在生成的构建中找到我的凭据...为它们创建具有正确值的 .env 文件。

@darmbrust我尝试了您的解决方案,但无法使其正常工作。
这是我的 compose yml:
版本:“3.3”
服务:

  buildToolsImage:
    image: vsbuildtools2017:web-v6

    build:
      context: .
      dockerfile: ./vsbuild-web-v6-optimized.dockerfile
      args:
        - CONTAINER_USER_PWD=${CONTAINER_USER_CREDS}

这是位于 yml 文件旁边的 .env 文件:

CONTAINER_USER_CREDS=secretpassword

而且,这是我的 dockerfile:

# escape=`
FROM microsoft/dotnet-framework:4.7.2-sdk
# Add non-root user
CMD ["sh", "-c", "echo ${CONTAINER_USER_PWD}"] 
RUN net user userone ${CONTAINER_USER_PWD} /add /Y

最后启动它的命令是这样的:

docker-compose -f docker-compose.buildImage.yml build

它构建映像但不使用存储在 .env 文件中的密码。

[警告] 未消耗一个或多个构建参数 [CONTAINER_USER_PWD]

我在这里错过了什么?
谢谢!

您必须在 docker 文件中使用https://docs.docker.com/engine/reference/builder/#predefined -args 之一。 您不能使用自己的参数名称,例如 CONTAINER_USER_PWD。

这就是技巧的工作原理,因为 docker 对预定义的参数有特殊的行为,因为您可以在不声明它们的情况下使用它们。 通过使用它们而不声明它们,它们似乎没有被记录在任何地方。

使用 docker-compose 文件,您可以将这些预定义的 args 映射到更合理命名的内容。

@darmbrust是的,这就是诀窍。
但是,你不觉得它很臭吗? 有什么更好的推荐吗?
谢谢!

这可能不像通过 tcp 暴露您的 ssh-agent 凭据那么臭
通过 socat 为任何本地进程窃取,但确实,与任何事情一样
与秘密有关,“docker build”确实很臭。

实际上,我忘记了 Mac 版 Docker 不能公开 Unix 域
osx 主机上的套接字到容器,这样就打开了更多的
一罐蠕虫。

我目前的解决方案,运行一个Centos VM,GitHub机器用户账号
凭据进入其中,使用“Rocker”(已弃用)工具构建。

2018 年 7 月 26 日星期四,Sameer Kumar, notifications @github.com 写道:

@darmbrust https://github.com/darmbrust是的,成功了。
但是,你不觉得它很臭吗? 有什么更好的推荐吗?
谢谢!


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/13490#issuecomment-408230125或静音
线程
https://github.com/notifications/unsubscribe-auth/AAZk5iz1kvCpZ0s65ng4TwL7LmHa9zZvks5uKitDgaJpZM4Eq021
.

整个虫子都很臭。 我还没有找到更好的方法……上面还有其他几种方法,但我认为所有其他安全方法都需要建立一个小的 http 服务器来将信息输入到图像中。 也许不那么臭,但更复杂,更多的工具,更多的活动部件。

不确定是否有人找到了“好的”解决方案……我们都在等待 docker 人员对此做些什么……不要屏住呼吸,因为这个 bug 是在 2015 年编写的,而且他们还没有甚至还没有提出路线图,更不用说解决方案了。

如此简单明了,允许挂载卷,(文件或
目录)在构建期间进入容器。

这不是技术限制,而是不允许机密信息进入的决定
为了保留以下行为 - 签出、运行构建、相同的输入、相同的
输出,如果要使缓存无效,请更改构建参数...

问题是,抽象变得越来越泄露
人们使用各种笨拙、不安全的黑客手段来获取“秘密”
放入容器中。

Newsflash,通过 TCP 公开您的 SSH 密钥环,即使在本地主机上也不是
安全,也不是通过环境变量传递凭据(提示,运行
ps,或查看 /proc 文件系统)、命令参数和环境变量都在那里,赤裸裸的,供全世界看到。

对于 golang 代码的开发人员来说,这在传统上不是问题,因为他们复制和粘贴
将他们的依赖项添加到他们的项目中,而不是使用依赖项管理工具,golang 开发人员将这种做法称为“供应商”。

对于在构建系统的其他生态系统中工作的任何人
从 Git 或需要身份验证的存储库获取依赖项,这是一个大问题。

我很确定在某处有一些启动规则,
“不要假设您知道,您的用户如何或为什么使用该产品”。

2018 年 7 月 26 日星期四,Dan Armbrust, notifications@ github.com 写道:

整个虫子都很臭。 我还没有找到更好的方法......有
上面的其他几种方法,但我认为所有其他安全的方法
需要建立一个小的 http 服务器来将信息输入到
图片。 也许不那么臭,但更复杂,更多工具,更动人
部分。

不确定是否有人找到了“好的”解决方案……我们都被困住了
等待码头工人做点什么......不要拿着你的
喘口气,因为这个bug是2015年写的,他们甚至没有提出
路线图,更不用说解决方案了。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/moby/moby/issues/13490#issuecomment-408233258或静音
线程
https://github.com/notifications/unsubscribe-auth/AAZk5nvbBTj4BAv5TtELNIHhJN8mU0Ctks5uKi38gaJpZM4Eq021
.

@binarytemple曾经在 Docker/moby 上工作过的每个人(就像它背后的工程师一样)都确切地知道问题是什么,甚至遇到过它。

Volumes 是一个本身就非常容易泄漏的解决方案。
有一个提议,在评论流中提到了一点,试图以合理的方式解决这个问题(https://github.com/moby/moby/issues/33343)

这里的主要事情是提供“正确”的抽象,而不是“任何碰巧有效的抽象”……我们当然知道这对许多人来说不仅仅是这种情况下的痛苦。

最近在构建器上完成了很多工作,但目前还不一定可见,但这项工作的成果将在未来几个月内开始显现。
首先,Docker 18.06 附带了一个由https://github.com/moby/buildkit支持的替代构建器实现
您可能会想“这对我有什么帮助?”。 Buildkit 提供了许多低级原语,使我们能够在 Docker 构建器中更加灵活。 甚至能够提供您自己的构建解析器(它可以是从增强的 Dockerfile 解析器到完全不同的任何东西)。 解析器在“Dockerfile”的顶部指定,只是您想用来解析文件的任何图像。

如果您现在真的想看到一些东西,您可以立即使用 buildkit 本身并运行它,它位于 containerd 之上,您可以非常快速地构建自定义集成。

https://github.com/moby/buildkit/pull/522 中为 buildkit 添加了秘密安装支持。 它们严格出现在 tmpfs 上,从构建缓存中排除,并且可以使用可配置的数据源。 还没有 PR 以 dockerfile 语法公开它,但应该是一个简单的补充。

有 2 种解决方案来构建带有机密的图像。

多阶段构建:

FROM ubuntu as intermediate
ARG USERNAME
ARG PASSWORD
RUN git clone https://${USERNAME}:${PASSWORD}@github.com/username/repository.git

FROM ubuntu
# copy the repository form the previous image
COPY --from=intermediate /your-repo /srv/your-repo

然后: docker build --build-arg USERNAME=username --build-arg PASSWORD=password my-image .

使用图像生成器: docker-build-with-secrets

@BenoitNorrin抱歉,您已将该密码暴露给主机系统上的每个进程。 Unix 安全 101 - 不要将机密作为命令参数。

是的,但有一些用法安全性不那么重要:

  • 您想在自己的计算机上构建
  • 你建立在你的企业 CI 服务器上(比如 jenkins)。 大多数情况下,它是关于访问私有存储库(nexus、git、npm 等),因此您的 CI 可能有她自己的凭据。
  • 您可以使用从 docker-machine 创建的 VM,然后将其删除。

如果这是唯一的问题@binarytemple ,那么简单地添加标志docker image build --args-file ./my-secret-file应该可以很容易地解决整个问题,不是吗? :思维:

@yajo可能是,是的,它至少是一种解决方法,直到 buildkit 随附秘密安装。 好建议。 谢谢。 乙

不幸的是,这些和许多其他票证中提到的大多数解决方法仍然将秘密暴露给生成的图像,或者仅适用于您只在编译期间而不是在安装期间需要依赖项的特定语言。

@binarytemple永远不会发生,

最大的痛点是我的秘密轮换

您必须维护服务依赖项的秘密图,并为每个服务更新两次(以恢复原始秘密名称)

列出来自服务的秘密似乎并不容易(我在docker service inspect --format='{{.Spec.TaskTemplate.ContainerSpec.Secrets}}' <some_service>附近尝试了几次后放弃了),列出来自docker secret inspect <secret_name>服务依赖项也很有用。 所以我现在只是手动维护那个(近似)图。

您还必须指定秘密目的地,当它不是 docker service update 命令中的默认/run/secrets/<secret_name>

我只是希望有一种更简单的方式来轮换秘密

@caub这里有一些 CLI 帮助:

用于格式化的 Docker 文档帮助提出了其余的检查格式:

docker service inspect --format='{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{println .SecretName}}{{end}}'

这将列出服务中的所有秘密名称。 如果您想要姓名和 ID,您可以:

docker service inspect --format='{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{println .SecretName .SecretID}}{{end}}' nginx

我总是让我的 CI/CD(服务更新命令)或堆栈文件对路径进行硬编码,因此您在轮换时不会遇到这个问题。

如果您不使用堆栈文件,您可以使用标签让 CI/CD 自动化识别正确的秘密(不需要秘密名称,每次都会不同)。

docker build --secret终于在 Docker 18.09 中可用https://medium.com/@tonistiigi/build -secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

@thaJeztah我们准备好关闭这个问题了吗?

对于旧版本的 docker,在构建命令之前使用多阶段构建并复制机密是可行的选择,对吗?

``
从 debian 作为构建
复制 ./secret.conf /path/on/image/
运行构建.sh
...

从 debian
复制 --from=build ...

@andriy-f 是的,只要你就行;

  • (显然)不要将秘密复制到最后阶段😉,或者:
  • 使用build阶段/存在秘密的阶段作为最终图像的“父”
  • 从不_push_构建阶段到注册表
  • 信任运行守护进程的主机; 即考虑到您的“构建”阶段被保留为图像; 有权访问该图像的人将能够访问您的秘密。

当使用 buildkit 作为构建器时,构建时间的秘密现在是可能的; 请参阅此处的博客文章https://medium.com/@tonistiigi/build -secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

和文件; https://docs.docker.com/develop/develop-images/build_enhancements/

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

谢谢@thaJeztah我只是做了一点挖掘,并在发布后不久发现了那篇文章(上一篇文章现已删除)。 再次感谢!

凉爽的。 这就结束了构建时间秘密问题。 任何用于运行时/开发时间的东西(OS X 中的 ssh)?

此页面是否有帮助?
0 / 5 - 0 等级