Docker和保护密码


162

我最近一直在试验Docker,以构建一些可玩的服务,而一直困扰着我的一件事就是将密码放入Dockerfile中。我是一名开发人员,因此将密码存储在源代码中感觉像是一拳。这是否值得关注?关于如何处理Dockerfile中的密码是否有任何好的约定?


7
目前在Github上请求关于泊坞窗和秘密最佳做法的悬而未决的问题,这个问题是在这里:github.com/docker/docker/issues/13490
路易斯Bianchin的

Answers:


92

绝对是一个问题。Dockerfile通常被检入存储库并与其他人共享。一种替代方法是在运行时提供任何凭据(用户名,密码,令牌,任何敏感内容)作为环境变量。可以通过使用-e参数(对于CLI上的各个var)或--env-file参数(对于文件中的多个变量)来实现docker run。阅读本文,了解如何将环境与docker-compose结合使用。

使用--env-file绝对是一个更安全的选择,因为这样做可以防止出现秘密(ps如果使用的话)set -x

但是,env var也不是特别安全。通过可以看到它们docker inspect,因此,任何可以运行docker命令的用户都可以使用它们。(当然,任何有权访问docker主机的用户也都具有root用户。)

我的首选模式是使用包装脚本作为ENTRYPOINTor CMD。包装脚本可以在运行时首先从外部将机密导入容器中,然后执行应用程序以提供机密。具体的运行机制取决于您的运行时环境。在AWS中,您可以结合使用IAM角色,密钥管理服务和S3将加密的机密存储在S3存储桶中。像HashiCorp Vaultcredstash之类的东西是另一种选择。

AFAIK没有将敏感数据用作构建过程一部分的最佳模式。实际上,我有一个对此主题问题。您可以使用docker-squash从图像中删除图层。但是Docker中没有用于此目的的本机功能。

您可能会发现容器中有关config的摇晃注释很有用。


如其他注释所述,将包含.config文件的2层(在ADD之后和第一次RUN之后)。
Petr Gladkikh 2014年

1
是的,env变量似乎是最好的方法。我一直在TDDing Dockerfile开发的背景下进行研究。
gnoll110 2015年

5
我担心如果您的密码是一个env变量,它将显示在中docker inspect
2016年

docker的默认安装(在Linux上)需要sudoer特权才能运行docker inspect。如果攻击者已经可以进行sudo攻击,那么从docker inspect中抢夺密码可能就在您现在可能会出错的事情列表中了。这个细节对我来说似乎是可以接受的风险。
GrandOpener

7
@GrandOpener仅适用于存在攻击者使用您的系统的情况。如果我将docker映像推送到存储库,并且由其他人将其拉出,则我不在乎他们在自己的系统上是否有sudo,但我绝对在乎他们是否看到env中不再应该存在的秘密。
vee_ess

74

我们的团队避免将凭证放入存储库中,因此这意味着不允许使用它们Dockerfile。在应用程序中,我们的最佳实践是使用来自环境变量的凭据。

我们使用解决此问题docker-compose

在中docker-compose.yml,您可以指定一个包含容器环境变量的文件:

 env_file:
- .env

确保添加.env.gitignore,然后在.env文件中设置凭据,例如:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

.env文件存储在本地或其他团队可以抓取的安全位置。

参见:https : //docs.docker.com/compose/environment-variables/#/the-env-file


15
如果需要,您也可以不使用.env文件。只需在docker-compose.yml文件中使用environment属性“只有键的环境变量在运行Compose的计算机上解析为它们的值,这对于秘密或特定于主机的值很有帮助。”
D. Visser

1
给这个男人一个饼干!:)是的,这真的是一个很好的做法,我只想添加docs.docker.com/compose/env-file, 它应该会自动运行,但是在docker compose版本2中,您似乎需要按照此答案中的说明进行声明。
相当于

5
Docker团队本身不建议使用环境变量,因为可以通过/ proc / <pid> / environ和docker inspect看到env var。它只会使获得根访问权限的攻击者无法获得凭证。当然,CVS绝不应该跟踪凭据。我猜想防止root用户获得信任的唯一方法是从加密的文件中读取Web应用程序中的凭据(希望它不会更新其proc环境文件),解密过程会安全地要求输入密码。我想我要去尝试一个墓:github.com/dyne/Tomb
pawamoy

.gitignore这样,.env包含敏感信息的文件就不会签到GitHub。我敢肯定,如果您添加它,它将无法正常工作.dockerignore
-theUtherSide

@theUtherSide,您好:感谢您的回答,我有一个问题,当我不签入.env文件并且在内部部署到服务器时,您是否建议.env手动在服务器上再次创建文件?
开源开发人员

37

Docker现在(1.13或17.06及更高版本)已支持管理机密信息。这是概述和更详细的文档

KubernetesDCOS中存在类似的功能


上面的链接提供了一些有用的命令docker secret create::创建机密 docker secret inspect:显示有关机密的详细信息 docker secret ls:查看所有机密 docker secret rm:删除特定的机密 --secret标志,以用于docker service create:创建服务期间创建机密, --secret-add以及--secret-rm标志docker service update:更新机密的值或删除机密在服务更新任务期间。在容器启动期间,Docker机密在管理员节点上处于静态状态,并被提供给工作节点。
PJ

7
是的,你需要建立一个群使用泊坞窗的秘密
希瑟QC

11
这是一个很好的答案开始,但是需要更多的信息,这些信息链接到答案本身中。
杰夫·兰伯特

7
如果仅适用于群体,则不确定是否可以接受此答案。许多人没有使用大量信息,但仍然需要传递秘密。
约翰Y

9

除非可以将证书传播给可以下载该图像的任何人,否则切勿将凭据添加到容器中。特别地,执行and ADD creds和更高版本RUN rm creds并不安全,因为creds文件保留在中间文件系统层的最终映像中。任何有权访问图像的人都可以轻松提取它。

当您需要使用凭据来检查依赖项时,我所见的典型解决方案是使用一个容器来构建另一个容器。即,通常,您的基本容器中有一些构建环境,您需要调用该环境来构建应用程序容器。因此,简单的解决方案是添加您的应用程序源,然后添加RUN构建命令。如果您需要信用证,这是不安全的RUN。相反,您要做的是将源放置在本地目录中,运行docker run容器(如中所示)以将本地源目录安装为卷,并将凭据插入或安装为另一个卷来执行构建步骤。构建步骤完成后,您只需通过简单地访问ADD现在包含已构建工件的本地源目录来构建最终容器。

我希望Docker添加一些功能来简化所有这些工作!

更新:看起来前进的方法将是具有嵌套构建。简而言之,dockerfile将描述第一个用于构建运行时环境的容器,然后是第二个可将所有组件组装到最终容器中的嵌套容器。这样,构建时的东西就不在第二个容器中。这是一个Java应用程序,您需要JDK来构建应用程序,而只需要JRE来运行它。目前正在讨论许多建议,最好从https://github.com/docker/docker/issues/7115开始,并遵循一些替代建议的链接。


7

使用环境变量的一种替代方法是使用卷以使容器中的主机可访问目录,而如果您使用的环境变量很多,则可能会造成混乱。

如果将所有凭据作为文件放在该文件夹中,则容器可以读取文件并根据需要使用它们。

例如:

$ echo "secret" > /root/configs/password.txt
$ docker run -v /root/configs:/cfg ...

In the Docker container:

# echo Password is `cat /cfg/password.txt`
Password is secret

许多程序可以从一个单独的文件中读取其凭据,因此您可以将程序指向其中一个文件。


5

仅运行时解决方案

docker-compose还提供了非群模式解决方案(自v1.11开始: 使用绑定安装的机密)。

秘密/run/secrets/由docker-compose 作为文件挂载。这在运行时(运行容器)解决了问题,但是在构建时(构建映像)解决了问题,因为/run/secrets/它不是在构建时挂载的。此外,此行为取决于使用docker-compose运行容器。


例:

Docker文件

FROM alpine
RUN cat /run/secrets/password
CMD sleep inifinity

docker-compose.yml

version: '3.1'
services:
  app:
    build: .
    secrets:
      - password

secrets:
  password:
    file: password.txt

要构建,执行:

docker-compose up -d

进一步阅读:


2

Docker v1.9中,您可以使用ARG指令构建操作中获取通过命令行传递给映像的参数。只需使用--build-arg标志。因此,您可以避免在Dockerfile上保留明确的密码(或其他敏感信息),并即时传递它们。

来源:https : //docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg

例:

Docker文件

FROM busybox
ARG user
RUN echo "user is $user"

建立映像命令

docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .

在构建过程中打印

$ docker build --build-arg user=capuccino -t test_arguments -f ./test_args.Dockerfile .

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM busybox
 ---> c51f86c28340
Step 2 : ARG user
 ---> Running in 43a4aa0e421d
 ---> f0359070fc8f
Removing intermediate container 43a4aa0e421d
Step 3 : RUN echo "user is $user"
 ---> Running in 4360fb10d46a
**user is capuccino**
 ---> 1408147c1cb9
Removing intermediate container 4360fb10d46a
Successfully built 1408147c1cb9

希望能帮助到你!再见


26
根据Docker的ARG文档:“不建议使用构建时变量来传递诸如github密钥,用户凭据等秘密信息”
Lie Ryan

3
只是想知道为什么Docker不推荐--build-arg var=secret用于将SSH私钥传递到映像中,没有任何文献记载。有人可以解释吗?
Henk Wiersema

2
@HenkWiersema进程信息,日志和命令历史记录不安全。进程信息是公开可用的,其中包括所有命令行参数。通常,这些调用最终会存储在可以公开的日志中。攻击者通常会检查正在运行的进程的信息并拖曳公共日志文件中的机密信息,这种情况并不罕见。即使它不是公开的,它也可以存储在您的命令历史记录中,这将使某人很容易通过非管理帐户获取机密。
tu-Restate Monica-dor duh 2016年

2
建议在构建时提供所需凭据的方法是什么?例如,需要aws s3访问以获取将驻留在图像内部的大数据集的图像?
伊利

3
我想不建议使用的原因是因为docker history暴露build-arg/ ARG变量。可以拉出任何图像,对其进行检查,并查看在构建过程中作为build-arg/ ARG参数传递的所有秘密。
vee_ess

2

我的方法似乎可行,但可能很幼稚。告诉我为什么这是错误的。

在docker构建期间设置的ARGs由history子命令公开,因此不要去那里。但是,在运行容器时,运行命令中给出的环境变量可用于该容器,但不是映像的一部分。

因此,在Dockerfile中,进行不涉及秘密数据的设置。设置CMD之类的/root/finish.sh。在run命令中,使用环境变量将秘密数据发送到容器中。finish.sh本质上使用变量来完成构建任务。

为了简化秘密数据的管理,请将其放入由docker run并由该--env-file开关运行的文件中。当然,请将文件保密。.gitignore等等。

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


2

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

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


-2

我完全同意,没有简单的解决方案。仍然存在单点故障。要么是dockerfile,要么是etcd,依此类推。Apcera的计划看起来像伙伴-双重身份验证。换句话说,除非有Apcera配置规则,否则两个容器无法通话。在他们的演示中,uid / pwd明确无误,除非管理员配置了链接,否则无法重复使用。但是,要使其正常工作,可能就意味着要修补Docker或至少修补网络插件(如果有的话)。


2
所问问题的某处是否有答案?
Abhijit Sarkar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.