【问题标题】:What is the best way to pass AWS credentials to a Docker container?将 AWS 凭证传递给 Docker 容器的最佳方式是什么?
【发布时间】:2016-07-21 03:32:45
【问题描述】:

我在 Amazon EC2 上运行 docker-container。目前我已将 AWS 凭证添加到 Dockerfile。你能告诉我最好的方法吗?

【问题讨论】:

  • 如果我在我的笔记本电脑上运行一个 Docker 容器,当我将它推到那里时,它应该也能在 ECS 中神奇地工作?我猜我使用了 --volume 标志……一定有人已经回答了……

标签: amazon-web-services docker docker-compose


【解决方案1】:

自从提出这个问题以来,Docker 发生了很多变化,所以这里尝试更新答案。

首先,特别是对于已经在云中运行的容器上的 AWS 凭证,使用 IAM 角色作为Vor suggests 是一个非常好的选择。如果你能做到,那么在他的答案中再加一加一,然后跳过其余部分。


一旦您开始在云之外运行东西,或者拥有不同类型的机密,我不建议在两个关键位置存储机密:

  1. 环境变量:当这些在容器上定义时,容器内的每个进程都可以访问它们,它们可以通过 /proc 看到,应用程序可以将它们的环境转储到存储在日志中的标准输出,最重要的是,当您检查容器时,它们会以明文形式显示。

  2. 在镜像本身:镜像经常被推送到许多用户拥有拉取访问权限的注册表,有时不需要任何凭据来拉取镜像。即使您从一层中删除秘密,也可以使用常见的 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

【讨论】:

  • 不使用docker compose怎么办?
  • @Jun711 上一行的 docker run 没有覆盖?
  • 它似乎不起作用。这是我使用的命令docker run -v $HOME/.aws/credentials:/home/app/.aws/credentials:ro -it -p 8080:8080 imageName:tagName。 boto3 错误消息是Unable to locate credentials。我不确定这是否重要,但凭据文件的权限是ls -la $HOME/.aws/credentials -rw-------
  • @Jun711 如果您使用的是 linux,则主机上文件的 uid 需要与容器用户的 uid 匹配。否则,我建议使用 minimal reproducible example 发布一个新问题,以获得有关您的问题的帮助。
  • 我在 Mac 上,我将容器路径更改为 root 而不是 /home/app/ 并且它有效。 docker run -v $HOME/.aws/credentials:/root/.aws/credentials:ro -it -p 8080:8080 imageName:tagName你知道我如何访问那个根目录吗?我使用了docker exec imageId ls -la,但在那里找不到我的 aws 凭据文件
【解决方案2】:

最好的方法是使用 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,反正你的回答很有帮助。谢谢。
  • 简单地说(对于那些和我一样得到这个答案的人);在 EC2 上运行的 docker 容器将继承与主机实例相同的角色。 (当我的容器中的 AWS CLI 命令神秘地工作时,尽管没有传递给它们的凭据,我需要这样的“ELI5”!)
  • 从本地配置文件中获取键值以分配给环境变量以用于开发目的的简单方法(如cameroneckelberry.co/words/… 中所建议):“aws --profile default configure get aws_access_key_id”
【解决方案3】:

另一种方法是在 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 上之前对其进行本地测试时也很有帮助。

【讨论】:

  • 在 windows 上的 .aws` 目录位于 "%UserProfile%\.aws"。所以我假设你必须改变:- ~/.aws/:/root/.aws:ro- %UserProfile%\.aws:/root/.aws:ro
  • 这仅适用于单个构建过程,而不适用于多阶段。
  • @wlarcheveque 需要详细说明吗?
  • 使用- host:container 语法时要非常小心,如果文件/文件夹在主机上不存在,它会被创建(以root 身份)并且awscli 不会感谢你给它一个零字节文件。您应该使用“长格式”来指定类型是绑定,主机路径和容器路径在单独的行上,如果文件不存在,这将失败,这是您在 docker-compose.dev 中想要的。 yml 但不在您的 docker-compose.yml 中(产品/AWS 部署)。
【解决方案4】:

另一种方法是将密钥从主机传递到 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}

【讨论】:

【解决方案5】:

您可以创建 ~/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
【解决方案6】:

即使我的凭据是由aws-oktasaml2aws 设置的,以下单行代码也适用于我:

$ 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(只读)限制

【讨论】:

    【解决方案7】:

    如果有人在按照接受的答案中提到的说明进行操作后仍然面临同样的问题,请确保您没有从两个不同的来源传递环境变量。在我的情况下,我通过文件将环境变量传递给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 文件中有所帮助。

    【讨论】:

    • 嗨 Abhay - 您在 AWS_SECRET_ACCES_KEY 上缺少一个“S”
    • 感谢@lukass77 指出这一点。已更新。
    【解决方案8】:

    卷安装已在此线程中注明,但从 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 中提取)

    【讨论】:

      【解决方案9】:

      根据之前的一些答案,我构建了自己的如下。 我的项目结构:

      ├── 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
      

      【讨论】:

        猜你喜欢
        • 2010-10-13
        • 2014-11-12
        • 2021-08-03
        • 1970-01-01
        • 2014-02-12
        • 2021-12-16
        • 1970-01-01
        • 2011-11-01
        相关资源
        最近更新 更多