Docker Engine 18.09 から使える Build-time secrets を試してみた
Posted on
Docker Engine 18.09 から Build-time secrets という機能が使えるようになりました。この機能を使えば docker build
するときに secrets (API key, credentials, etc) を安全に取り扱えるようになります。
Integrate secrets in your Dockerfile and pass them along in a safe way. These secrets do not end up stored in the final image nor are they included in the build cache calculations to avoid anyone from using the cache metadata to reconstruct the secret.
docker build
の --build-arg
オプションを使えば引数で ARG
を渡せますが、この方法で渡した ARG
は docker history
コマンドで簡単に見えてしまいます。公式ドキュメントにも secrets を渡す用途には使わないように警告されています。
Warning: It is not recommended to use build-time variables for passing secrets like github keys, user credentials etc. Build-time variable values are visible to any user of the image with the
docker history
command.
これまではワークアラウンドで回避するしかありませんでしたが、やっと secrets を安全に渡すオフィシャルな方法が提供されました。
Build-time secrets を試してみる
試した Docker 環境は次のとおりです。
$ docker version
Client: Docker Engine - Community
Version: 18.09.0
API version: 1.39
Go version: go1.10.4
Git commit: 4d60db4
Built: Wed Nov 7 00:47:43 2018
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.0
API version: 1.39 (minimum version 1.12)
Go version: go1.10.4
Git commit: 4d60db4
Built: Wed Nov 7 00:55:00 2018
OS/Arch: linux/amd64
Experimental: false
今回は AWS credentials を使って S3 にアクセスしてみます。 S3 にあるプライベートなファイルをビルド時にダウンロードしてくるイメージです。
Dockerfile はこんな感じです。
# syntax = docker/dockerfile:1.0.0-experimental
FROM python:3.7-alpine
RUN pip install --quiet awscli
RUN --mount=type=secret,id=credentials,dst=/root/.aws/credentials \
aws s3 cp --region ap-northeast-1 s3://docker-build-secret/hello_world.txt .
まだ stable チャンネルの Dockerfile では有効になっていないので、1 行目のコメントで experimental チャンネルの syntax であることを宣言しています。詳しい説明は New Docker Build secret information を参照してください。
docker build
するときは --secret
オプションで id
と src
を指定します。 BuildKit はまだオプトインの機能なので DOCKER_BUILDKIT=1
を指定する必要があります。
$ DOCKER_BUILDKIT=1 docker build -t docker-build-secret --progress=plain \
--secret id=credentials,src=$HOME/.aws/credentials .
実行すると S3 にアクセスできていることが確認できました。
#8 [3/3] RUN --mount=type=secret,id=credentials,dst=/root/.aws/credentials ...
#8 digest: sha256:389724b447a83d008ea7d2a8ab88f3ceb9a4fe58dc58af68b3a62996c7f74251
#8 name: "[3/3] RUN --mount=type=secret,id=credentials,dst=/root/.aws/credentials aws s3 cp --region ap-northeast-1 s3://docker-build-secret/hello_world.txt ."
#8 started: 2018-12-28 07:50:57.1181584 +0000 UTC
download: s3://docker-build-secret/hello_world.txt to ./hello_world.txt
#8 completed: 2018-12-28 07:51:00.7738157 +0000 UTC
#8 duration: 3.6556573s
Build-time secrets の仕組みを知る
Build-time secrets の仕組みを知るために、ビルドされた Docker イメージを調べてみます。
docker history
でイメージの履歴を見ても credentials の情報はもちろん残っていません。
$ docker history docker-build-secret
IMAGE CREATED CREATED BY SIZE COMMENT
8f70e4d781aa About a minute ago RUN /bin/sh -c aws s3 cp --region ap-northea… 206kB buildkit.dockerfile.v0
<missing> About a minute ago RUN /bin/sh -c pip install --quiet awscli # … 60.9MB buildkit.dockerfile.v0
<missing> 47 hours ago /bin/sh -c #(nop) CMD ["python3"] 0B
...
Dockerfile の中で /root/.aws/credentials
のパスにマウントしましたが、Docker イメージの中には空のファイルだけが残っていました。
$ docker run -ti --rm docker-build-secret /bin/sh
/ # ls -l /root/.aws/credentials
-rwxr-xr-x 1 root root 0 Dec 28 07:50 /root/.aws/credentials
/ # cat /root/.aws/credentials
/ #
また、同じ Dockerfile の中でも他の RUN
コマンドからは参照できませんでした。たとえば、次の Dockerfile の最後の RUN
コマンドは空のファイルを参照するだけです。
# syntax = docker/dockerfile:1.0.0-experimental
FROM python:3.7-alpine
RUN pip install --quiet awscli
RUN --mount=type=secret,id=credentials,dst=/root/.aws/credentials \
aws s3 cp --region ap-northeast-1 s3://docker-build-secret/hello_world.txt .
RUN cat /root/.aws/credentials
公式ドキュメントには詳しい仕組みが載っていませんが、BuildKit のソースコードを読んでみると tmpfs
をマウントして実現していました。
まとめ
これまで secrets を安全に扱うには multi-stage build を使ったり、イメージの履歴に残らない特別な build-args を使っていましたが、Build-time secrets はそれらのワークアラウンドをすべて解決してくれます!
BuildKit について詳しく知りたい方は、こちらのスライドがよくまとまっていました。