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


102

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


2
如果我在笔记本电脑上运行一个Docker容器,当将其推入该容器时,它应该也可以在ECS中正常运行吗?我想我会使用--volume标志...肯定有人已经回答了……
兰迪·L

Answers:


105

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


35
在本地开发/测试过程中是否有不损害生产安全性的好方法?我很乐意确保映像能够正常运行而不会完全部署。
honktronic '16

3
我发布的带有环境变量的替代方法在开发人员/本地环境中效果很好。
2016年

5
我想知道这是否是拼写错误,但是我需要输入AWS_SECRET_ACCESS_KEY,而不是AWS_SECRET_KEY,无论如何,您的回答很有帮助。谢谢。
Akavall '02

14
简单地说(对于那些以与我相同的方式获得此答案的人);在EC2上运行的Docker容器将继承与主机实例相同的角色。(当我的容器中没有传递任何凭据时,当我的容器中的AWS CLI命令神秘地起作用时,我需要这样的“ ELI5”!)
Adam Westbrook,

8
从本地配置文件获取键值并分配给环境变量以进行开发的简单方法(如cameroneckelberry.co/words/…所示):“ aws --profile default configure get aws_access_key_id”
Altair7852

89

自从提出此问题以来,Docker发生了很多变化,因此,我们尝试获取更新的答案。

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


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

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

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


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

选项A:如果仅在映像构建期间需要此秘密,无法在构建开始之前使用该秘密,并且还没有访问BuildKit的权限,那么最好选择多阶段构建。您可以将机密添加到构建的初始阶段,在其中使用它,然后将没有机密的该阶段的输出复制到您的发布阶段,然后仅将该发布阶段推送到注册表服务器。这个秘密仍然在构建服务器的图像缓存中,因此我倾向于仅将其用作最后的手段。

选项B:同样,在构建期间,如果可以使用18.09中发布的BuildKit,则当前具有实验性功能,允许将秘密作为单个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 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

我经常使用以下脚本来发布我的秘密:https//github.com/sudo-bmitch/docker-config-update

选项E:存在其他用于管理机密的工具,我最喜欢的是保管库,因为它提供了创建会自动失效的限时机密的功能。然后,每个应用程序都有自己的一组令牌来请求机密,并且这些令牌使它们能够请求那些有时间限制的机密,只要它们可以到达Vault服务器即可。如果机密不起作用或很快就会过期,那么这将降低从机密中删除机密的风险。https://www.vaultproject.io/docs/secrets/aws/index.html记录了适用于Vault的AWS的特定功能


20

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

3
正确的区域环境变量是AWS_REGION。见stackoverflow.com/questions/44151982/...
约翰卡梅林

3
请查看提及AWS_DEFAULT_REGION docs.aws.amazon.com/cli/latest/userguide/…
-prafi

7
当我使用AWS_DEFAULT_REGION时,出现了一个例外,即找不到默认区域。我的搜索导致了docs.aws.amazon.com/sdk-for-java/v1/developer-guide/…,它指定了AWS_REGION环境变量,并且对我有用。
约翰·卡梅林,

如果您使用的是临时凭据,那么您可能还需要AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}
达沃斯

13

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


在Windows上,可以找到.aws目录"%UserProfile%\.aws"。所以,我认为你必须改变: - ~/.aws/:/root/.aws:ro- %UserProfile%\.aws:/root/.aws:ro
阿图尔Siepietowski

1
这仅适用于单个构建过程,而不适用于多阶段。
wlarcheveque

@wlarcheveque关心详细吗?
ErikE

使用- host:container语法非常小心,如果文件/文件夹在创建它的主机上不存在(作为根用户),并且awscli不会感谢您将其提供给零字节文件。您应该使用“长格式”来指定绑定的类型,主机路径和容器路径,如果文件不存在,则失败,这是您在docker-compose.dev中想要的。 yml,但不在您的docker-compose.yml中(产品/ AWS部署)。
dragon788

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.