我在 Amazon EC2 上运行 docker-container。目前我已将 AWS 凭证添加到 Dockerfile。你能告诉我最好的方法吗?
自从提出这个问题以来,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
最好的方法是使用 IAM 角色并且根本不处理凭证。 (见http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)
可以从 http://169.254.169.254.....
检索凭证,因为这是一个私有 IP 地址,它只能从 EC2 实例访问。
所有现代 AWS 客户端库都“知道”如何从那里获取、刷新和使用凭证。所以在大多数情况下,你甚至不需要知道它。只需使用正确的 IAM 角色运行 ec2 即可。
作为一个选项,您可以在运行时将它们作为环境变量传递(即 docker run -e AWS_ACCESS_KEY_ID=xyz -e AWS_SECRET_ACCESS_KEY=aaa myimage
)
您可以通过在终端运行 printenv 来访问这些环境变量。
AWS_SECRET_ACCESS_KEY
,而不是 AWS_SECRET_KEY
,反正你的回答很有帮助。谢谢你。
另一种方法是在 docker-compose.yaml 中创建临时只读卷。 AWS CLI 和 SDK(如 boto3 或 AWS SDK for Java 等)正在 ~/.aws/credentials
文件中寻找 default
配置文件。
如果您想使用其他配置文件,您还需要在运行 docker-compose
命令之前导出 AWS_PROFILE 变量。
export AWS_PROFILE=some_other_profile_name
version: '3'
services:
service-name:
image: docker-image-name:latest
environment:
- AWS_PROFILE=${AWS_PROFILE}
volumes:
- ~/.aws/:/root/.aws:ro
在这个例子中,我在 docker 上使用了 root 用户。如果您正在使用其他用户,只需将 /root/.aws
更改为用户主目录。
:ro
- 代表只读 docker 卷
当您在 ~/.aws/credentials
文件中有多个配置文件并且您也在使用 MFA 时,这非常有用。当您想在将 docker-container 部署到您拥有 IAM 角色但在本地没有的 ECS 上之前对其进行本地测试时也很有帮助。
"%UserProfile%\.aws"
。所以我假设你必须改变: - ~/.aws/:/root/.aws:ro
到 - %UserProfile%\.aws:/root/.aws:ro
- host:container
语法时要非常小心,如果文件/文件夹在它创建的主机上不存在(以 root 身份),并且 awscli 不会感谢您为其提供零字节文件。您应该使用“长格式”来指定类型是绑定,主机路径和容器路径在单独的行上,如果文件不存在,这将失败,这是您在 docker-compose.dev 中想要的。 yml 但不在您的 docker-compose.yml (产品/AWS 部署)中。
另一种方法是将密钥从主机传递到 docker 容器。您可以将以下行添加到 docker-compose
文件中。
services:
web:
build: .
environment:
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
AWS_DEFAULT_REGION
docs.aws.amazon.com/cli/latest/userguide/… 的官方文档
AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}
即使我的凭据是由 aws-okta 或 saml2aws 设置的,以下单行代码也适用于我:
$ docker run -v$HOME/.aws:/root/.aws:ro \
-e AWS_ACCESS_KEY_ID \
-e AWS_CA_BUNDLE \
-e AWS_CLI_FILE_ENCODING \
-e AWS_CONFIG_FILE \
-e AWS_DEFAULT_OUTPUT \
-e AWS_DEFAULT_REGION \
-e AWS_PAGER \
-e AWS_PROFILE \
-e AWS_ROLE_SESSION_NAME \
-e AWS_SECRET_ACCESS_KEY \
-e AWS_SESSION_TOKEN \
-e AWS_SHARED_CREDENTIALS_FILE \
-e AWS_STS_REGIONAL_ENDPOINTS \
amazon/aws-cli s3 ls
请注意,对于高级用例,您可能需要允许 rw
(读写)权限,因此在 -v$HOME/.aws:/root/.aws:ro
中安装 .aws
卷时忽略 ro
(只读)限制
此线程中记录了卷安装,但从 docker-compose v3.2 +
开始,您可以绑定安装。
例如,如果您的项目根目录中有一个名为 .aws_creds
的文件:
在您的撰写文件服务中,为卷执行此操作:
volumes:
# normal volume mount, already shown in thread
- ./.aws_creds:/root/.aws/credentials
# way 2, note this requires docker-compose v 3.2+
- type: bind
source: .aws_creds # from local
target: /root/.aws/credentials # to the container location
使用这个想法,您可以在 docker-hub 上公开存储您的 docker 图像,因为您的 aws credentials
不会物理地在图像中...要使它们关联,您必须在容器启动的本地具有正确的目录结构(即从 Git 中提取)
您可以创建包含以下内容的 ~/aws_env_creds
:
touch ~/aws_env_creds
chmod 777 ~/aws_env_creds
vi ~/aws_env_creds
添加这些值(替换您的密钥):
AWS_ACCESS_KEY_ID=AK_FAKE_KEY_88RD3PNY
AWS_SECRET_ACCESS_KEY=BividQsWW_FAKE_KEY_MuB5VAAsQNJtSxQQyDY2C
按“esc”保存文件。
运行并测试容器:
my_service:
build: .
image: my_image
env_file:
- ~/aws_env_creds
777
权限设置文件,因为任何其他有权访问主机的用户都可以读取凭据文件......不是很好,因为使用 env 变量的要点是使凭证远离任何人/任何不是需要它们的 aws 服务的东西!也许744 is more appropriate
如果有人在按照接受的答案中提到的说明进行操作后仍然面临同样的问题,请确保您没有从两个不同的来源传递环境变量。在我的情况下,我通过文件将环境变量传递给 docker run
,并作为导致作为参数传递的变量显示无效的参数。
所以以下命令对我不起作用:
docker run --env-file ./env.list -e AWS_ACCESS_KEY_ID=ABCD -e AWS_SECRET_ACCESS_KEY=PQRST IMAGE_NAME:v1.0.1
将 aws 凭证移动到提到的 env.list
文件中会有所帮助。
根据之前的一些答案,我构建了自己的如下。我的项目结构:
├── Dockerfile
├── code
│ └── main.py
├── credentials
├── docker-compose.yml
└── requirements.txt
我的 docker-compose.yml
文件:
version: "3"
services:
app:
build:
context: .
volumes:
- ./credentials:/root/.aws/credentials
- ./code:/home/app
我的 Docker
文件:
FROM python:3.8-alpine
RUN pip3 --no-cache-dir install --upgrade awscli
RUN mkdir /app
WORKDIR /home/app
CMD python main.py
不定期副业成功案例分享
/home/app/
并且它有效。docker run -v $HOME/.aws/credentials:/root/.aws/credentials:ro -it -p 8080:8080 imageName:tagName
你知道我如何访问那个根目录吗?我使用了docker exec imageId ls -la
,但在那里找不到我的 aws 凭据文件docker run -d -e ASPNETCORE_ENVIRONMENT=development -v "%UserProfile%\.aws\credentials":/root/.aws/credentials:ro --name containerName imageName