簡體   English   中英

將 AWS 憑證傳遞給 Docker 容器的最佳方式是什么?

[英]What is the best way to pass AWS credentials to a Docker container?

我在 Amazon EC2 上運行 docker-container。 目前我已經將 AWS 憑證添加到 Dockerfile。你能告訴我最好的方法嗎?

自從提出這個問題以來,Docker 發生了很多變化,所以這里嘗試更新答案。

首先,特別是對於已經在雲內部運行的容器上的 AWS 憑證,使用Vor 建議的IAM 角色是一個非常好的選擇。 如果你能做到這一點,那么在他的答案中再加一加一,跳過剩下的部分。


一旦您開始在雲之外運行事物,或者擁有不同類型的機密,我建議您不要在兩個關鍵位置存儲機密:

  1. 環境變量:當這些在容器上定義時,容器內的每個進程都可以訪問它們,它們可以通過 /proc 看到,應用程序可以將它們的環境轉儲到標准輸出,並存儲在日志中,最重要的是,它們出現在檢查容器時清除文本。

  2. 在鏡像本身:鏡像經常被推送到許多用戶具有拉取訪問權限的注冊表,有時不需要任何憑據來拉取鏡像。 即使您從一層中刪除了機密,也可以使用常見的 Linux 實用程序(如tar反匯編映像,並且可以從第一次將機密添加到映像的步驟中找到機密。


那么 Docker 容器中的秘密還有哪些其他選擇呢?

選項 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 模式或其他編排,您可以將憑據掛載為只讀卷。 訪問此憑據需要的訪問權限與您在 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 的開放訪問,他們可以從節點上正在運行的容器中提取秘密,因此再次限制誰有權訪問應用程序接口。 從 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為單個節點打開 swarm 模式,然后按照說明添加其他節點。 您可以使用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

最好的方法是使用 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 來訪問這些環境變量。

另一種方法是在 docker-compose.yaml 中創建臨時只讀卷。 AWS CLI 和 SDK(如 boto3 或 AWS SDK for Java 等)正在~/.aws/credentials文件中尋找default配置文件。

如果你想使用其他配置文件,你只需要在運行 docker 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 上時也很有幫助,但在本地您沒有。

另一種方法是將密鑰從主機傳遞到 docker 容器。 您可以docker-compose添加到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}

您可以創建~/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

即使我的憑據是由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 (只讀)限制-v$HOME/.aws:/root/.aws:ro

如果有人在按照接受的答案中提到的說明操作后仍然面臨同樣的問題,請確保您沒有傳遞來自兩個不同來源的環境變量。 在我的情況下,我通過文件將環境變量傳遞給docker run並將其作為參數傳遞給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文件中有所幫助。

此線程中記錄了卷安裝,但從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 鏡像公開存儲在 docker-hub 上,因為您的aws credentials實際上不會在鏡像中, aws credentials它們關聯,您必須在啟動容器的本地擁有正確的目錄結構。

根據之前的一些答案,我按如下方式構建了自己的答案。 我的項目結構:

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

對於 php apache docker 以下命令有效

docker run --rm -d -p 80:80 --name my-apache-php-app -v "$PWD":/var/www/html -v ~/.aws:/.aws --env AWS_PROFILE=mfa php:7.2-apache

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM