自从提出这个问题以来,Docker 发生了很多变化,所以这里尝试更新答案。
首先,特别是对于已经在云中运行的容器上的 AWS 凭证,使用 IAM 角色作为Vor suggests 是一个非常好的选择。如果你能做到,那么在他的答案中再加一加一,然后跳过其余部分。
一旦您开始在云之外运行东西,或者拥有不同类型的机密,我不建议在两个关键位置存储机密:
-
环境变量:当这些在容器上定义时,容器内的每个进程都可以访问它们,它们可以通过 /proc 看到,应用程序可以将它们的环境转储到存储在日志中的标准输出,最重要的是,当您检查容器时,它们会以明文形式显示。
-
在镜像本身:镜像经常被推送到许多用户拥有拉取访问权限的注册表,有时不需要任何凭据来拉取镜像。即使您从一层中删除秘密,也可以使用常见的 Linux 实用程序(如tar)对图像进行反汇编,并且可以从首次将其添加到图像的步骤中找到该秘密。
那么 Docker 容器中的机密还有哪些其他选项?
选项 A: 如果您仅在构建映像期间需要此密钥,在构建开始之前无法使用该密钥,并且还没有访问 BuildKit 的权限,那么 multi-stage build 是最好的坏选择。您可以将秘密添加到构建的初始阶段,在那里使用它,然后将没有秘密的该阶段的输出复制到您的发布阶段,并且只将该发布阶段推送到注册表服务器。这个秘密仍然在构建服务器上的图像缓存中,所以我倾向于仅将其用作最后的手段。
选项 B: 同样在构建期间,如果您可以使用 18.09 发布的 BuildKit,目前有 experimental features 允许将秘密注入作为单个 RUN 行的卷挂载.该挂载不会写入映像层,因此您可以在构建期间访问该密钥,而不必担心它将被推送到公共注册表服务器。生成的 Dockerfile 如下所示:
# syntax = docker/dockerfile:experimental
FROM python:3
RUN pip install awscli
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials aws s3 cp s3://... ...
您使用 18.09 或更高版本中的命令构建它,例如:
DOCKER_BUILDKIT=1 docker build -t your_image --secret id=aws,src=$HOME/.aws/credentials .
选项 C: 在单个节点上运行时,无需 Swarm 模式或其他编排,您可以将凭据挂载为只读卷。访问此凭据需要与您在 docker 之外对同一凭据文件具有相同的访问权限,因此与没有 docker 的情况相比,它没有更好或更差。最重要的是,当您检查容器、查看日志或将映像推送到注册表服务器时,该文件的内容不应该是可见的,因为在每种情况下该卷都在该卷之外。这确实需要您在 docker 主机上复制您的凭据,与容器的部署分开。 (请注意,任何能够在该主机上运行容器的人都可以查看您的凭据,因为对 docker API 的访问权限是主机上的 root 并且 root 可以查看任何用户的文件。如果您不信任主机上具有 root 的用户,那么不要给他们 docker API 访问权限。)
对于docker run,如下所示:
docker run -v $HOME/.aws/credentials:/home/app/.aws/credentials:ro your_image
或者对于撰写文件,您将拥有:
version: '3'
services:
app:
image: your_image
volumes:
- $HOME/.aws/credentials:/home/app/.aws/credentials:ro
选项 D: 借助 Swarm Mode 和 Kubernetes 等编排工具,我们现在拥有比卷更好的秘密支持。使用 Swarm 模式,文件在管理器文件系统上被加密(尽管解密密钥通常也在那里,允许管理员在没有管理员输入解密密钥的情况下重新启动管理器)。更重要的是,秘密只发送给需要秘密的工作人员(运行具有该秘密的容器),它只存储在工作人员的内存中,而不是磁盘中,并且它作为一个文件注入到具有 tmpfs 的容器中山。 swarm 之外的主机上的用户不能直接将该秘密挂载到他们自己的容器中,但是,通过对 docker API 的开放访问,他们可以从节点上正在运行的容器中提取秘密,因此再次限制谁可以访问API。从 compose 来看,这个秘密注入看起来像:
version: '3.7'
secrets:
aws_creds:
external: true
services:
app:
image: your_image
secrets:
- source: aws_creds
target: /home/user/.aws/credentials
uid: '1000'
gid: '1000'
mode: 0700
您使用docker swarm init 为单个节点打开集群模式,然后按照说明添加其他节点。您可以使用docker secret create aws_creds $HOME/.aws/credentials 在外部创建密钥。然后使用docker stack deploy -c docker-compose.yml stack_name 部署撰写文件。
我经常使用来自https://github.com/sudo-bmitch/docker-config-update的脚本来修改我的秘密
选项 E: 存在其他管理机密的工具,我最喜欢的是 Vault,因为它能够创建自动过期的限时机密。然后,每个应用程序都会获得自己的一组令牌来请求机密,这些令牌使他们能够在可以访问保险库服务器的情况下请求这些时间有限的机密。如果秘密从您的网络中取出,这会降低风险,因为它要么不起作用,要么很快就会过期。特定于 AWS for Vault 的功能记录在 https://www.vaultproject.io/docs/secrets/aws/index.html