¿Cuál es la mejor manera de pasar las credenciales de AWS al contenedor Docker?

104

Estoy ejecutando docker-container en Amazon EC2. Actualmente he agregado credenciales de AWS a Dockerfile. ¿Podría decirme cuál es la mejor manera de hacer esto?

suraj chopade
fuente
2
¿Qué tal si estoy ejecutando un contenedor Docker en mi computadora portátil que se supone que también funciona mágicamente en ECS cuando lo empujo allí? Supongo que uso la bandera de volumen ... alguien ya debe haber respondido ...
Randy L

Respuestas:

107

La mejor forma es utilizar el rol de IAM y no ocuparse en absoluto de las credenciales. (ver http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html )

Las credenciales se pueden recuperar de http://169.254.169.254..... Dado que se trata de una dirección IP privada, solo se puede acceder a ella desde instancias EC2.

Todas las bibliotecas de cliente de AWS modernas "saben" cómo obtener, actualizar y usar credenciales desde allí. Entonces, en la mayoría de los casos, ni siquiera necesita saberlo. Simplemente ejecute ec2 con el rol de IAM correcto y listo.

Como opción, puede pasarlos en el tiempo de ejecución como variables de entorno (es decir docker run -e AWS_ACCESS_KEY_ID=xyz -e AWS_SECRET_ACCESS_KEY=aaa myimage)

Puede acceder a estas variables de entorno ejecutando printenv en la terminal.

Vor
fuente
35
¿Existe una buena manera de hacer esto durante el desarrollo / prueba local que no comprometa la seguridad en la producción? Me encantaría asegurarme de que una imagen funcione sin implementarla por completo.
honktronic
3
una alternativa que publiqué con variables de entorno funciona bien en el entorno dev / local.
Vor
5
Me pregunto si esto es un error tipográfico, pero necesito ingresar AWS_SECRET_ACCESS_KEY, no AWS_SECRET_KEY, de todos modos tu respuesta fue muy útil. Gracias.
Akavall
14
En pocas palabras (para aquellos que llegan a esta respuesta de la misma manera que yo); Un contenedor de Docker que se ejecuta en EC2 heredará el mismo rol que la instancia de host. (¡Necesitaba un "ELI5" como este cuando los comandos de la AWS CLI en mis contenedores funcionaban misteriosamente a pesar de que no se les transfirieron credenciales!)
Adam Westbrook
8
Una forma sencilla de obtener los valores clave de su perfil local para asignarlos a la variable de entorno con fines de desarrollo (como se sugiere en cameroneckelberry.co/words/… ): "aws --profile default configure get aws_access_key_id"
Altair7852
92

Mucho ha cambiado en Docker desde que se hizo esta pregunta, así que aquí hay un intento de obtener una respuesta actualizada.

Primero, específicamente con las credenciales de AWS en contenedores que ya se ejecutan dentro de la nube, usar roles de IAM como sugiere Vor es una muy buena opción. Si puede hacer eso, agregue uno más más uno a su respuesta y omita el resto de esto.


Una vez que empiezas a ejecutar cosas fuera de la nube, o tienes un tipo diferente de secreto, hay dos lugares clave que recomiendo no almacenar secretos:

  1. Variables de entorno: cuando se definen en un contenedor, todos los procesos dentro del contenedor tienen acceso a ellas, son visibles a través de / proc, las aplicaciones pueden volcar su entorno a stdout donde se almacena en los registros y, lo más importante, aparecen en texto claro cuando inspecciona el contenedor.

  2. En la propia imagen: las imágenes a menudo se envían a registros donde muchos usuarios tienen acceso de extracción, a veces sin que se requieran credenciales para extraer la imagen. Incluso si elimina el secreto de una capa, la imagen se puede desmontar con utilidades comunes de Linux como tary el secreto se puede encontrar desde el paso donde se agregó por primera vez a la imagen.


Entonces, ¿qué otras opciones existen para los secretos en los contenedores de Docker?

Opción A: si necesita este secreto solo durante la compilación de su imagen, no puede usar el secreto antes de que comience la compilación y aún no tiene acceso a BuildKit, entonces una compilación de varias etapas es la mejor de las malas opciones. Agregaría el secreto a las etapas iniciales de la compilación, lo usaría allí y luego copiaría la salida de esa etapa sin el secreto a su etapa de lanzamiento, y solo enviaría esa etapa de lanzamiento a los servidores de registro. Este secreto todavía está en la memoria caché de imágenes en el servidor de compilación, por lo que tiendo a usarlo solo como último recurso.

Opción B: también durante el tiempo de compilación, si puede usar BuildKit que se lanzó en 18.09, actualmente hay características experimentales para permitir la inyección de secretos como un montaje de volumen para una sola línea RUN. Ese montaje no se escribe en las capas de imagen, por lo que puede acceder al secreto durante la compilación sin preocuparse de que se envíe a un servidor de registro público. El Dockerfile resultante se ve así:

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

Y lo construyes con un comando en 18.09 o más reciente como:

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

Opción C:En tiempo de ejecución en un solo nodo, sin el modo Swarm u otra orquestación, puede montar las credenciales como un volumen de solo lectura. El acceso a esta credencial requiere el mismo acceso que tendría fuera de la ventana acoplable al mismo archivo de credenciales, por lo que no es mejor ni peor que el escenario sin la ventana acoplable. Lo más importante es que el contenido de este archivo no debe ser visible cuando inspecciona el contenedor, ve los registros o envía la imagen a un servidor de registro, ya que el volumen está fuera de ese en todos los escenarios. Esto requiere que copie sus credenciales en el host de la ventana acoplable, aparte de la implementación del contenedor. (Tenga en cuenta que cualquier persona con la capacidad de ejecutar contenedores en ese host puede ver su credencial, ya que el acceso a la API de Docker es root en el host y root puede ver los archivos de cualquier usuario. Si no confía en los usuarios con root en el host ,

Para a docker run, esto se ve así:

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

O para un archivo de redacción, tendría:

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

Opción D:Con herramientas de orquestación como Swarm Mode y Kubernetes, ahora tenemos compatibilidad con secretos que es mejor que un volumen. Con el modo Swarm, el archivo se cifra en el sistema de archivos del administrador (aunque la clave de descifrado a menudo también está allí, lo que permite que el administrador se reinicie sin que un administrador ingrese una clave de descifrado). Más importante aún, el secreto solo se envía a los trabajadores que necesitan el secreto (ejecutando un contenedor con ese secreto), solo se almacena en la memoria del trabajador, nunca en el disco, y se inyecta como un archivo en el contenedor con un tmpfs montar. Los usuarios en el host fuera del enjambre no pueden montar ese secreto directamente en su propio contenedor, sin embargo, con acceso abierto a la API de la ventana acoplable, podrían extraer el secreto de un contenedor en ejecución en el nodo, por lo que nuevamente, limite quién tiene este acceso al API. De componer, esta inyección secreta se ve así:

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

Activa el modo de enjambre con docker swarm initpara un solo nodo, luego sigue las instrucciones para agregar nodos adicionales. Puede crear el secreto externamente con docker secret create aws_creds $HOME/.aws/credentials. E implementas el archivo de redacción con docker stack deploy -c docker-compose.yml stack_name.

A menudo versiono mis secretos usando un script de: https://github.com/sudo-bmitch/docker-config-update

Opción E: existen otras herramientas para administrar secretos, y mi favorita es Vault porque brinda la capacidad de crear secretos por tiempo limitado que expiran automáticamente. Luego, cada aplicación obtiene su propio conjunto de tokens para solicitar secretos, y esos tokens les dan la capacidad de solicitar esos secretos por tiempo limitado mientras puedan llegar al servidor de la bóveda. Eso reduce el riesgo si alguna vez se saca un secreto de su red, ya que no funcionará o caducará rápidamente. La funcionalidad específica de AWS for Vault está documentada en https://www.vaultproject.io/docs/secrets/aws/index.html

BMitch
fuente
22

Otro enfoque consiste en pasar las claves de la máquina host al contenedor de la ventana acoplable. Puede agregar las siguientes líneas al docker-composearchivo.

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
fuente
3
La variable de entorno de región correcta es AWS_REGION. Ver stackoverflow.com/questions/44151982/…
John Camerin
3
Consulte el documento oficial que menciona AWS_DEFAULT_REGION docs.aws.amazon.com/cli/latest/userguide/…
prafi
7
Cuando usé AWS_DEFAULT_REGION, obtuve una excepción de que no se pudo encontrar una región predeterminada. Mi búsqueda me llevó a docs.aws.amazon.com/sdk-for-java/v1/developer-guide/… que especifica la variable de entorno AWS_REGION, y eso funcionó para mí.
John Camerin
Si está utilizando credenciales temporales, es posible que también necesite AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}
Davos
14

Otro enfoque más es crear un volumen temporal de solo lectura en docker-compose.yaml. AWS CLI y SDK (como boto3 o AWS SDK para Java, etc.) están buscando un defaultperfil en el ~/.aws/credentialsarchivo.

Si desea utilizar otros perfiles, solo necesita exportar la variable AWS_PROFILE antes de ejecutar el 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

En este ejemplo utilicé el usuario root en la ventana acoplable. Si está utilizando otro usuario, simplemente cambie /root/.awsal directorio de inicio del usuario

:ro - significa volumen de la ventana acoplable de solo lectura

Es muy útil cuando tiene varios perfiles en ~/.aws/credentials archivo y también está utilizando MFA. También es útil cuando desea probar localmente docker-container antes de implementarlo en ECS en el que tiene roles de IAM, pero localmente no los tiene.

Artur Siepietowski
fuente
En windows se encuentra el catálogo .aws` "%UserProfile%\.aws". Así que supongo que tienes que cambiar: - ~/.aws/:/root/.aws:roa- %UserProfile%\.aws:/root/.aws:ro
Artur Siepietowski
1
Esto solo funcionará con procesos de compilación únicos y no con varias etapas.
wlarcheveque
@wlarcheveque ¿Te importaría elaborar?
ErikE
Sea MUY cuidadoso al usar la - host:containersintaxis, si el archivo / carpeta no existe en el host que se crea (como raíz) y el awscli no le agradecerá que le proporcione un archivo de cero bytes. Debe usar el "formulario largo" que especifica el tipo de enlace, la ruta del host y la ruta del contenedor en líneas separadas, esto falla si el archivo no existe, que es lo que desea en su docker-compose.dev. yml pero no en su docker-compose.yml (prod / AWS deploy).
dragon788
0

Podrías crear ~/aws_env_credsconteniendo

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

agregue el valor inferior (reemplace la clave suya)

AWS_ACCESS_KEY_ID=AK_FAKE_KEY_88RD3PNY
AWS_SECRET_ACCESS_KEY=BividQsWW_FAKE_KEY_MuB5VAAsQNJtSxQQyDY2C

"esc" para guardar el archivo.

Ejecuta y prueba el contenedor

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