Docker和保护密码
我最近一直在尝试与Docker一起构build一些服务来玩玩,而一件让我烦恼的事情是把密码放在一个Dockerfile中。 我是一名开发人员,因此在源代码中存储密码就像是一个重大的冲击。 如果这甚至是一个问题? 有没有什么好的约定如何处理Dockerfiles中的密码?
这肯定是一个问题。 Dockerfiles通常检入到存储库并与其他人共享。 另一种方法是在运行时提供任何凭据(用户名,密码,令牌,任何敏感的东西) 作为环境variables 。 这可以通过-e
参数(对于CLI上的单个variables)或--env-file
参数(对于--env-file
中的多个variables)来docker run
。
然而,环境variables也不是特别安全。 它们通过docker inspect
可见,因此它们可供任何可以运行docker
命令的用户使用。 (当然,任何有权访问主机上的docker
用户也都有root权限 。)
我的首选模式是使用包装脚本作为ENTRYPOINT
或CMD
。 包装脚本可以首先将外部位置的秘密在运行时导入容器,然后执行应用程序,提供秘密。 其确切的机制取决于您的运行时环境。 在AWS中,可以使用IAMangular色, 密钥pipe理服务和S3的组合将encryption的秘密存储在S3存储桶中。 像HashiCorp Vault或credstash是另一种select。
AFAIK没有使用敏感数据作为构build过程的一部分的最佳模式。 事实上,我对这个话题有个疑问 。 您可以使用docker-squash从图像中移除图层。 但是为此,Docker中没有本地function。
你可能会发现shykes 对容器中的configuration有用的评论 。
我们的团队避免将证书放在存储库中,这意味着它们不被允许在Dockerfile
。 我们在应用程序中的最佳实践是使用来自环境variables的声明。
我们使用docker-compose
来解决这个问题。
在docker-compose.yml
,你可以指定一个包含容器环境variables的文件:
env_file: - .env
确保将.env
添加到.gitignore
,然后在.env
文件中设置凭据,如:
SOME_USERNAME=myUser SOME_PWD_VAR=myPwd
将.env
文件存储在本地或安全的地方,其余的团队可以抓住它。
请参阅: https : //docs.docker.com/compose/environment-variables/#/the-env-file
你不应该添加证书到一个容器,除非你可以向任何可以下载图像的人传播信任。 尤其是,执行和ADD creds
和后来的RUN rm creds
是不安全的,因为信用文件保留在中间文件系统层的最终映像中。 任何有权访问该映像的人都可以很容易地将其提取出来。
我看到的典型的解决scheme,当你需要信任结帐依赖关系,这是使用一个容器来build立另一个。 也就是说,通常在基本容器中有一些构build环境,并且需要调用它来构build应用程序容器。 所以简单的解决scheme是添加你的应用程序源,然后RUN
生成命令。 这是不安全的,如果你需要在该RUN
信用。 相反,你所做的是把你的源代码放到一个本地目录中,运行(如在docker run
)容器来执行构build步骤,将本地源代码目录挂载为卷,并将注入或挂载为另一个卷。 构build步骤完成后,只需ADD
现在包含构build工件的本地源目录即可构build最终容器。
我希望Docker增加了一些function来简化这一切!
更新:看起来像前进的方法将是嵌套的构build。 简而言之,dockerfile将描述用于构build运行时环境的第一个容器,然后描述第二个嵌套容器构build,可以将所有构件组装到最终容器中。 这样的构build时间的东西是不是在第二个容器。 这是一个Java应用程序,您需要JDK来构build应用程序,但只有JRE才能运行它。 有许多build议正在讨论中,最好从https://github.com/docker/docker/issues/7115开始,并按照其他build议的一些链接进行。;
现在Docker(版本1.13或17.06和更高版本)支持pipe理机密信息。 这是一个概述和更详细的文档
类似的function存在于kubernetes和DCOS中
使用Docker v1.9,您可以使用ARG指令将命令行传递的参数提取到构build操作中的图像上。 只需使用–build-arg标志。 所以你可以避免在Dockerfile上保留明确的密码(或其他合理的信息),并且可以直接传递它们。
来源: https : //docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg
例:
Dockerfile
FROM busybox ARG user RUN echo "user is $user"
build立图像命令
docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .
在构build期间打印
$ 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
希望能帮助到你! 再见。
虽然我完全同意没有简单的解决scheme。 仍然有一个单一的失败点。 dockerfile,etcd等等。 Apcera有一个计划,看起来像伙伴 – 双authentication。 换句话说,除非有Apceraconfiguration规则,否则两个容器不能通话。 在他们的演示中,uid / pwd是清晰的,在pipe理员configuration链接之前不能重复使用。 然而,为了这个工作,这可能意味着修补Docker或至lessnetworking插件(如果有这样的事情)。
作为使用环境variables的一个替代方法,如果你有很多环境variables,可以使用它们,那就是使用卷在容器中访问主机上的一个目录。
如果你把所有的凭证作为文件放在那个文件夹中,那么容器就可以读取这些文件,并且可以随意使用它们。
例如:
$ 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 build期间设置的ARGs被history子命令公开,所以不要去那里。 但是,运行容器时,运行命令中给出的环境variables对容器可用,但不是图像的一部分。
所以,在Dockerfile中,请设置不涉及秘密数据的设置。 设置一个类似/root/finish.sh
的CMD。 在运行命令中,使用环境variables将秘密数据发送到容器中。 finish.sh
基本上使用variables来完成构build任务。
为了更方便地pipe理秘密数据,把它放到一个由--env-file
运行加载--env-file
开关--env-file
。 当然,保持文件的秘密。 .gitignore
等。
对我来说, finish.sh
运行一个Python程序。 它检查以确保它以前没有运行,然后完成设置(例如,将数据库名称复制到Django的settings.py
)。