Answers:
绝对是一个问题。Dockerfile通常被检入存储库并与其他人共享。一种替代方法是在运行时提供任何凭据(用户名,密码,令牌,任何敏感内容)作为环境变量。可以通过使用-e
参数(对于CLI上的各个var)或--env-file
参数(对于文件中的多个变量)来实现docker run
。阅读本文,了解如何将环境与docker-compose结合使用。
使用--env-file
绝对是一个更安全的选择,因为这样做可以防止出现秘密(ps
如果使用的话)set -x
。
但是,env var也不是特别安全。通过可以看到它们docker inspect
,因此,任何可以运行docker
命令的用户都可以使用它们。(当然,任何有权访问docker
主机的用户也都具有root用户。)
我的首选模式是使用包装脚本作为ENTRYPOINT
or CMD
。包装脚本可以在运行时首先从外部将机密导入容器中,然后执行应用程序以提供机密。具体的运行机制取决于您的运行时环境。在AWS中,您可以结合使用IAM角色,密钥管理服务和S3将加密的机密存储在S3存储桶中。像HashiCorp Vault或credstash之类的东西是另一种选择。
AFAIK没有将敏感数据用作构建过程一部分的最佳模式。实际上,我有一个对此主题问题。您可以使用docker-squash从图像中删除图层。但是Docker中没有用于此目的的本机功能。
您可能会发现容器中有关config的摇晃注释很有用。
.config
文件的2层(在ADD之后和第一次RUN之后)。
docker inspect
。
docker inspect
。如果攻击者已经可以进行sudo攻击,那么从docker inspect中抢夺密码可能就在您现在可能会出错的事情列表中了。这个细节对我来说似乎是可以接受的风险。
我们的团队避免将凭证放入存储库中,因此这意味着不允许使用它们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
.gitignore
这样,.env
包含敏感信息的文件就不会签到GitHub。我敢肯定,如果您添加它,它将无法正常工作.dockerignore
.env
文件并且在内部部署到服务器时,您是否建议.env
手动在服务器上再次创建文件?
Docker现在(1.13或17.06及更高版本)已支持管理机密信息。这是概述和更详细的文档
Kubernetes和DCOS中存在类似的功能
docker secret create
::创建机密 docker secret inspect
:显示有关机密的详细信息 docker secret ls
:查看所有机密 docker secret rm
:删除特定的机密 --secret
标志,以用于docker service create
:创建服务期间创建机密, --secret-add
以及--secret-rm
标志docker service update
:更新机密的值或删除机密在服务更新任务期间。在容器启动期间,Docker机密在管理员节点上处于静态状态,并被提供给工作节点。
除非可以将证书传播给可以下载该图像的任何人,否则切勿将凭据添加到容器中。特别地,执行and ADD creds
和更高版本RUN rm creds
并不安全,因为creds文件保留在中间文件系统层的最终映像中。任何有权访问图像的人都可以轻松提取它。
当您需要使用凭据来检查依赖项时,我所见的典型解决方案是使用一个容器来构建另一个容器。即,通常,您的基本容器中有一些构建环境,您需要调用该环境来构建应用程序容器。因此,简单的解决方案是添加您的应用程序源,然后添加RUN
构建命令。如果您需要信用证,这是不安全的RUN
。相反,您要做的是将源放置在本地目录中,运行docker run
容器(如中所示)以将本地源目录安装为卷,并将凭据插入或安装为另一个卷来执行构建步骤。构建步骤完成后,您只需通过简单地访问ADD
现在包含已构建工件的本地源目录来构建最终容器。
我希望Docker添加一些功能来简化所有这些工作!
更新:看起来前进的方法将是具有嵌套构建。简而言之,dockerfile将描述第一个用于构建运行时环境的容器,然后是第二个可将所有组件组装到最终容器中的嵌套容器。这样,构建时的东西就不在第二个容器中。这是一个Java应用程序,您需要JDK来构建应用程序,而只需要JRE来运行它。目前正在讨论许多建议,最好从https://github.com/docker/docker/issues/7115开始,并遵循一些替代建议的链接。
使用环境变量的一种替代方法是使用卷以使容器中的主机可访问目录,而如果您使用的环境变量很多,则可能会造成混乱。
如果将所有凭据作为文件放在该文件夹中,则容器可以读取文件并根据需要使用它们。
例如:
$ 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
许多程序可以从一个单独的文件中读取其凭据,因此您可以将程序指向其中一个文件。
仅运行时解决方案
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
进一步阅读:
在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
希望能帮助到你!再见
--build-arg var=secret
用于将SSH私钥传递到映像中,没有任何文献记载。有人可以解释吗?
docker history
暴露build-arg
/ ARG
变量。可以拉出任何图像,对其进行检查,并查看在构建过程中作为build-arg
/ ARG
参数传递的所有秘密。
我的方法似乎可行,但可能很幼稚。告诉我为什么这是错误的。
在docker构建期间设置的ARGs由history子命令公开,因此不要去那里。但是,在运行容器时,运行命令中给出的环境变量可用于该容器,但不是映像的一部分。
因此,在Dockerfile中,进行不涉及秘密数据的设置。设置CMD之类的/root/finish.sh
。在run命令中,使用环境变量将秘密数据发送到容器中。finish.sh
本质上使用变量来完成构建任务。
为了简化秘密数据的管理,请将其放入由docker run并由该--env-file
开关运行的文件中。当然,请将文件保密。.gitignore
等等。
对我来说,finish.sh
运行一个Python程序。它检查以确保它从未运行过,然后完成设置(例如,将数据库名称复制到Django的settings.py
)。
有一个新的docker 命令用于“秘密”管理。但这仅适用于群集集群。
docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver
在12因子的应用程序的方法告诉,任何配置应储存在环境变量。
Docker compose可以在配置中进行变量替换,因此可以用来将密码从主机传递到docker。
我完全同意,没有简单的解决方案。仍然存在单点故障。要么是dockerfile,要么是etcd,依此类推。Apcera的计划看起来像伙伴-双重身份验证。换句话说,除非有Apcera配置规则,否则两个容器无法通话。在他们的演示中,uid / pwd明确无误,除非管理员配置了链接,否则无法重复使用。但是,要使其正常工作,可能就意味着要修补Docker或至少修补网络插件(如果有的话)。