将AWS凭据传递给Docker容器的最佳方法是哪种?

时间:2016-04-01 10:50:51

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

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

7 个答案:

答案 0 :(得分:54)

最好的方法是使用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来访问这些环境变量。

答案 1 :(得分:5)

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

答案 2 :(得分:3)

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

首先,特别是对于已经在云内部运行的容器使用AWS凭据,将IAM角色用作Vor suggests是一个很好的选择。如果可以的话,请在他的答案中再加上一个加一个,然后跳过其余的内容。


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

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

  2. 在映像本身中:映像通常被推送到许多用户具有访问权限的注册表中,有时甚至不需要任何凭据即可提取映像。即使您从一个层中删除密钥,也可以使用tar之类的常见Linux实用程序来分解该映像,并且可以从将密钥首次添加到映像的步骤中找到该密钥。


那么Doc​​ker容器中的秘密还有哪些其他选择呢?

选项A::如果仅在映像构建过程中需要此机密,无法在构建开始前使用此机密,并且还无法访问BuildKit,则{{3} }是最糟糕的选择。您可以将机密添加到构建的初始阶段,在其中使用它,然后将不包含机密的该阶段的输出复制到发布阶段,然后仅将该发布阶段推送到注册表服务器。这个秘密仍然在构建服务器的图像缓存中,因此我倾向于仅将其用作最后的选择。

选项B:另外,在构建期间,如果您可以使用18.09版发布的BuildKit,则当前有multi-stage build允许将秘密作为单个卷的卷装入使用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 Mode或其他编排的单个节点上运行时,可以将凭据安装为只读卷。访问此凭据需要与在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。从撰写的内容来看,这种秘密注入看起来像:

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部署撰写文件。

我经常使用以下脚本编写版本的秘密:experimental features

选项E:还有其他用于管理机密的工具,我最喜欢的是https://github.com/sudo-bmitch/docker-config-update,因为它可以创建自动失效的限时机密。然后,每个应用程序都有自己的一组令牌来请求机密,并且这些令牌使它们能够请求那些有时间限制的机密,只要它们可以到达Vault服务器即可。如果机密从机密中删除了,那将降低风险,因为它要么不起作用,要么很快过期。 Vault

记录了适用于Vault的AWS的特定功能

答案 3 :(得分:0)

另一种方法是在docker-compose.yaml中创建临时只读卷。 AWS CLI和SDK(例如boto3或Java的AWS开发工具包等)正在default文件中寻找~/.aws/credentials配置文件。

如果您想使用其他配置文件,则只需要在运行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时,这将非常有用。如果要在将其部署到具有IAM角色的ECS上但在本地没有该实例的ECS上进行本地测试之前,也很有用。

答案 4 :(得分:0)

您可以创建包含以下内容的~/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

答案 5 :(得分:0)

即使我的凭据是由 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(读写)权限,因此在挂载 ro 卷时省略 .aws(只读)限制在-v$HOME/.aws:/root/.aws:ro

答案 6 :(得分:0)

如果有人在按照已接受的答案中提到的说明操作后仍然面临同样的问题,请确保您没有传递来自两个不同来源的环境变量。在我的例子中,我通过文件和参数将环境变量传递给 docker run,这导致作为参数传递的变量没有效果。

所以以下命令对我不起作用:

docker run --env-file ./env.list -e AWS_ACCESS_KEY_ID=ABCD -e AWS_SECRET_ACCES_KEY=PQRST IMAGE_NAME:v1.0.1

将 aws 凭据移动到提到的 env.list 文件中有所帮助。