envsubstコマンド
認証情報をソースコードに載せるのは情報漏洩に繋がるため、必ず回避すべき脆弱性です。envsubst
コマンドを使うとDocker Imageやコンテナを作成するタイミングで、ソースコードの一部分をホスト側の環境変数で置換することが出来ます。
つまりバージョン管理しない外部ファイルに環境変数に認証情報を記述し、スクリプト内でenvsubst
コマンドで置換することでソースコードに認証情報を残さずにアプリケーションを起動することが可能になります。認証情報はバージョン管理するソースコードには含まれないので情報漏洩に繋がることは無いということです。
やってみる
以前作成したS3の画像をSlackに送信するLambdaのコードを参考にします。コードの意味を全て理解する必要はありません。.templateファイルが置換される様子に注目して下さい。
最初にホスト側の環境変数をexportしておきます。面倒なので.zshrcに追記しています。
$ vi ~/.zshrc
export MY_LAMBDA_SLACK_TOKEN='xoxb-1051071700934-1606419213746-xvrL86GnDQBKWDG4pEWDdv8j'
export MY_LAMBDA_SLACK_CHANNELL_ID='C011CP2UVCP'
export MY_LAMBDA_SLACK_MEMBER_ID='U011H23LM0W'
$ source ~/.zshrc
前回のソースコードの手入力していた認証情報の部分を環境変数を参照するかのようなコードに変更します。
import requests
import boto3
import base64
def lambda_handler(event, context):
s3 = boto3.client('s3')
bucket = 'weather-capture'
file_path = 'weather.png'
response = s3.get_object(Bucket=bucket, Key=file_path)
image_data = response['Body'].read()
files = {'file': image_data}
param = {'token': ${MY_LAMBDA_SLACK_TOKEN}, 'channels': '${MY_LAMBDA_SLACK_CHANNELL_ID}', 'initial_comment': '<@${MY_LAMBDA_SLACK_MEMBER_ID}>'}
res = requests.post(url="https://slack.com/api/files.upload",params=param, files=files)
return res.text
Dockerfileはこれをenvsubst
コマンドでホスト側の環境変数で置き換えてから、lambda_function.pyにリダイレクションするコマンドを8行目に追記しています。
FROM lambci/lambda:build-python3.6
ENV AWS_DEFAULT_REGION ap-northeast-1
ENV APP_DIR /var/task
ADD . .
CMD envsubst < lambda_function.py.template > lambda_function.py && \
pip install -r requirements.txt -t $APP_DIR && \
zip -9 deploy_package.zip lambda_function.py && \
zip -r9 deploy_package.zip *
このDockerfileでビルドを行います。
$ docker build -t lambda_headless_chrome .
コンテナを起動する際にホスト側の環境変数をコンテナ側でも使うように引数に渡します。
$ docker run --rm -e "MY_LAMBDA_SLACK_TOKEN=${MY_LAMBDA_SLACK_TOKEN}" \
-e "MY_LAMBDA_SLACK_CHANNELL_ID=${MY_LAMBDA_SLACK_CHANNELL_ID}" \
-e "MY_LAMBDA_SLACK_MEMBER_ID=${MY_LAMBDA_SLACK_MEMBER_ID}" \
-v "${PWD}":/var/task lambda_headless_chrome
するとホスト側の環境変数が埋め込まれたlambda_function.pyが作成されています。この通りenvsubst
コマンドを使うとソースコードに認証情報を残さずにバージョン管理することが容易に可能です。
終わりに
ちなみに引数で指定しない方法は探したものの見つかりませんでした。docker-composeの場合だとymlからホスト側の環境変数を参照出来るようでしたが、Dockerfileのみだと引数で渡す以外には方法は無いかと思われます。恐らく……