Qual é a melhor maneira de passar credenciais AWS para o contêiner Docker?

102

Estou executando o docker-container no Amazon EC2. Atualmente, adicionei as credenciais da AWS ao Dockerfile. Você poderia me informar a melhor maneira de fazer isso?

Suraj Chopade
fonte
2
E se eu estiver executando um contêiner Docker em meu laptop que também funcionará magicamente no ECS quando for colocado lá? Acho que vou usar o sinalizador --volume ... alguém já deve ter respondido ...
Randy L

Respostas:

105

A melhor maneira é usar a função IAM e não lidar com credenciais. (consulte http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html )

As credenciais podem ser recuperadas http://169.254.169.254..... por ser um endereço IP privado, ele só pode ser acessado por instâncias EC2.

Todas as bibliotecas cliente modernas da AWS "sabem" como buscar, atualizar e usar credenciais a partir daí. Portanto, na maioria dos casos, você nem precisa saber sobre isso. Basta executar o ec2 com a função IAM correta e pronto.

Como opção, você pode passá-los no tempo de execução como variáveis ​​de ambiente (ou seja docker run -e AWS_ACCESS_KEY_ID=xyz -e AWS_SECRET_ACCESS_KEY=aaa myimage)

Você pode acessar essas variáveis ​​de ambiente executando printenv no terminal.

Vor
fonte
35
Existe uma boa maneira de fazer isso durante o desenvolvimento / teste local que não comprometa a segurança na produção? Adoraria ter certeza de que uma imagem funciona sem implantá-la totalmente.
honktronic
3
uma alternativa que postei com variáveis ​​de ambiente funciona bem no ambiente dev / local.
Vor
5
Eu me pergunto se isso é um erro de digitação, mas eu preciso digitar AWS_SECRET_ACCESS_KEY, não AWS_SECRET_KEY, de qualquer maneira sua resposta foi muito útil. Obrigado.
Akavall
14
Simplificando (para aqueles que chegaram a esta resposta da mesma forma que eu); Um contêiner docker em execução no EC2 herdará a mesma função da instância do host. (Eu precisava de um "ELI5" como este quando os comandos AWS CLI em meus contêineres funcionavam misteriosamente, apesar de não haver credenciais passadas para eles!)
Adam Westbrook
8
Uma maneira fácil de obter os valores-chave do seu perfil local para atribuir à variável de ambiente para fins de desenvolvimento (como sugerido em cameroneckelberry.co/words/… ): "aws --profile default configure get aws_access_key_id"
Altair7852
89

Muita coisa mudou no Docker desde que essa pergunta foi feita, então aqui está uma tentativa de uma resposta atualizada.

Primeiro, especificamente com as credenciais da AWS em contêineres já em execução dentro da nuvem, usar funções de IAM, como sugere Vor, é uma opção realmente boa. Se você puder fazer isso, adicione mais um mais um à sua resposta e pule o resto.


Depois que você começa a executar coisas fora da nuvem ou tem um tipo diferente de segredo, há dois pontos-chave que eu recomendo contra o armazenamento de segredos:

  1. Variáveis ​​de ambiente: quando são definidas em um contêiner, todos os processos dentro do contêiner têm acesso a elas, são visíveis por meio de / proc, os aplicativos podem despejar seu ambiente para o stdout, onde fica armazenado nos logs e, o mais importante, eles aparecem em texto claro ao inspecionar o contêiner.

  2. Na própria imagem: as imagens muitas vezes são enviadas para registros onde muitos usuários têm acesso de pull, às vezes sem nenhuma credencial necessária para puxar a imagem. Mesmo se você excluir o segredo de uma camada, a imagem pode ser desmontada com utilitários comuns do Linux, como tare o segredo pode ser encontrado a partir da etapa em que foi adicionado pela primeira vez à imagem.


Então, quais outras opções existem para segredos em contêineres do Docker?

Opção A: Se você precisar desse segredo apenas durante a construção de sua imagem, não puder usar o segredo antes do início da construção e ainda não tiver acesso ao BuildKit, uma construção de vários estágios é a melhor das opções ruins. Você adicionaria o segredo aos estágios iniciais da compilação, usaria lá e, em seguida, copiaria a saída desse estágio sem o segredo para o estágio de lançamento e apenas enviaria esse estágio de lançamento para os servidores de registro. Esse segredo ainda está no cache de imagem no servidor de compilação, então costumo usar isso apenas como último recurso.

Opção B: também durante o tempo de construção, se você pode usar o BuildKit que foi lançado em 18.09, existem atualmente recursos experimentais para permitir a injeção de segredos como uma montagem de volume para uma única linha RUN. Essa montagem não é gravada nas camadas da imagem, então você pode acessar o segredo durante a construção sem se preocupar se ele será enviado a um servidor de registro público. O Dockerfile resultante se parece com:

# 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://... ...

E você o constrói com um comando em 18.09 ou mais recente, como:

DOCKER_BUILDKIT=1 docker build -t your_image --secret id=aws,src=$HOME/.aws/credentials .

Opção C:No tempo de execução em um único nó, sem o modo Swarm ou outra orquestração, você pode montar as credenciais como um volume somente leitura. O acesso a essa credencial requer o mesmo acesso que você teria fora do docker para o mesmo arquivo de credenciais, portanto, não é melhor nem pior do que o cenário sem docker. Mais importante ainda, o conteúdo desse arquivo não deve ser visível quando você inspeciona o contêiner, visualiza os logs ou envia a imagem para um servidor de registro, uma vez que o volume está fora disso em todos os cenários. Isso exige que você copie suas credenciais no host docker, separado da implantação do contêiner. (Observe, qualquer pessoa com a capacidade de executar contêineres nesse host pode visualizar sua credencial, já que o acesso à API docker é root no host e root pode visualizar os arquivos de qualquer usuário. Se você não confiar em usuários com root no host ,

Para um docker run, isso se parece com:

docker run -v $HOME/.aws/credentials:/home/app/.aws/credentials:ro your_image

Ou para um arquivo de composição, você teria:

version: '3'
services:
  app:
    image: your_image
    volumes:
    - $HOME/.aws/credentials:/home/app/.aws/credentials:ro

Opção D:Com ferramentas de orquestração como o Modo Swarm e Kubernetes, agora temos suporte a segredos que é melhor do que um volume. Com o Modo Swarm, o arquivo é criptografado no sistema de arquivos do gerenciador (embora a chave de descriptografia frequentemente também esteja lá, permitindo que o gerenciador seja reiniciado sem que um administrador insira uma chave de descriptografia). Mais importante ainda, o segredo é enviado apenas para os trabalhadores que precisam do segredo (executando um contêiner com esse segredo), é armazenado apenas na memória do trabalhador, nunca no disco, e é injetado como um arquivo no contêiner com um tmpfs montar. Os usuários no host fora do swarm não podem montar esse segredo diretamente em seu próprio contêiner, no entanto, com acesso aberto à API docker, eles podem extrair o segredo de um contêiner em execução no nó, portanto, novamente, limite quem tem esse acesso ao API. Na composição, essa injeção secreta se parece com:

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

Você ativa o modo de enxame com docker swarm initpara um único nó e, a seguir, segue as instruções para adicionar nós adicionais. Você pode criar o segredo externamente com docker secret create aws_creds $HOME/.aws/credentials. E você implanta o arquivo de composição com docker stack deploy -c docker-compose.yml stack_name.

Costumo criar versões de meus segredos usando um script de: https://github.com/sudo-bmitch/docker-config-update

Opção E: Existem outras ferramentas para gerenciar segredos, e minha favorita é o Vault porque oferece a capacidade de criar segredos com limite de tempo que expiram automaticamente. Cada aplicativo obtém seu próprio conjunto de tokens para solicitar segredos, e esses tokens dão a eles a capacidade de solicitar esses segredos de tempo limitado, desde que possam acessar o servidor do vault. Isso reduz o risco de um segredo ser retirado de sua rede, já que ele não funcionará ou expirará rapidamente. A funcionalidade específica do AWS para Vault está documentada em https://www.vaultproject.io/docs/secrets/aws/index.html

BMitch
fonte
20

Outra abordagem é passar as chaves da máquina host para o contêiner do docker. Você pode adicionar as seguintes linhas ao docker-composearquivo.

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}
prafi
fonte
3
A variável de ambiente da região correta é AWS_REGION. Consulte stackoverflow.com/questions/44151982/…
John Camerin
3
Verifique o documento oficial que menciona AWS_DEFAULT_REGION docs.aws.amazon.com/cli/latest/userguide/…
prafi
7
Quando usei AWS_DEFAULT_REGION, recebi uma exceção de que não foi possível encontrar uma região padrão. Minha pesquisa levou a docs.aws.amazon.com/sdk-for-java/v1/developer-guide/… que especifica a variável de ambiente AWS_REGION, e funcionou para mim.
John Camerin,
Se você estiver usando credenciais temporárias, também pode precisarAWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}
Davos,
13

Outra abordagem é criar um volume somente leitura temporário em docker-compose.yaml. AWS CLI e SDK (como boto3 ou AWS SDK para Java etc.) estão procurando por um defaultperfil no ~/.aws/credentialsarquivo.

Se você quiser usar outros perfis, você só precisa exportar a variável AWS_PROFILE antes de executar o docker-composecomando

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

Neste exemplo, usei o usuário root no docker. Se você estiver usando outro usuário, basta mudar /root/.awspara o diretório inicial do usuário

:ro - significa volume docker somente leitura

É muito útil quando você tem vários perfis no ~/.aws/credentialsarquivo e também está usando o MFA. Também é útil quando você deseja testar localmente o docker-container antes de implantá-lo no ECS no qual você tem funções de IAM, mas não localmente.

Artur Siepietowski
fonte
No Windows, o catálogo .aws` está localizado "%UserProfile%\.aws". Então eu suponho que você tenha que mudar: - ~/.aws/:/root/.aws:ropara- %UserProfile%\.aws:/root/.aws:ro
Artur Siepietowski
1
Isso funcionará apenas com processos de construção única e não em vários estágios.
wlarcheveque
@wlarcheveque Quer elaborar?
ErikE
Tenha MUITO cuidado ao usar a - host:containersintaxe, se o arquivo / pasta não existir no host, ele foi criado (como root) e o awscli não agradecerá por alimentá-lo com um arquivo de zero bytes. Você deve usar o "formato longo" que especifica o tipo é bind, o caminho do host e o caminho do contêiner em linhas separadas; isso falhará se o arquivo não existir, que é o que você deseja em seu docker-compose.dev. yml, mas não em docker-compose.yml (prod / AWS deploy).
dragon788
0

Você pode criar ~/aws_env_credscontendo

touch ~/aws_env_creds
chmod 777 ~/aws_env_creds
vi ~/aws_env_creds

adicione o valor abaixo (substitua a sua chave)

AWS_ACCESS_KEY_ID=AK_FAKE_KEY_88RD3PNY
AWS_SECRET_ACCESS_KEY=BividQsWW_FAKE_KEY_MuB5VAAsQNJtSxQQyDY2C

"esc" para salvar o arquivo.

Execute e teste o contêiner

 my_service:
      build: .
      image: my_image
      env_file:
        - ~/aws_env_creds
Manimaran Samuthirapandi
fonte