Dockerコンテナーで実行されるアプリに必要な秘密の値を渡したいのですが。この特定のコンテナは短命です-起動してコマンドを実行し、その後終了します。
方法1:コンテナーを開始するときに、コマンドラインを介して値を環境変数として渡します(Dockerは、コンテナーを開始するためのコマンドライン引数としてこれをサポートしています)。 dockerコンテナーを起動したホストマシンのプロセスリスト(キーとすべて)にコマンドが表示されるため、これは悪い感じです。
方法2:env変数ファイルを介して、env変数として値を渡します。これはプロセスリストの問題を解決しますが、docker info
ホストから実行中のコンテナで、そのコンテナに設定されているすべての環境変数のリストを表示します。これにより、Dockerは安全ではないホスト上のディスクのどこかにこれらを格納していると思います(実行中のコンテナーに新しい環境変数を追加してもこのリストは更新されないため、リアルタイムで直接読み取ってはなりません)。
一般的に、環境変数は秘密データを安全に(一時的にでも)保管するのに十分ではないと思いますが、この考えを裏付ける十分な知識がありません。
秘密のデータをコンテナに渡す安全な方法は何ですか?
これを行うには、環境変数、特に方法2が最善の方法です。デフォルトでは、Dockerはroot以外のユーザーによる実行を許可していません。ソケットへのアクセスは禁止されています。方法2は、攻撃者がrootアクセス権を持っている(そしてDockerコンテナーを覗き見できる)場合、箱から出してすぐに状態が悪くなるので、かなり安全です。
一般的に2つのDockerセキュリティノート。デフォルトでは暗号化や認証は行われないため、APIの有効化には十分注意してください。文書化した証明書とTLSを使用する方法がありますが、注意して進めてください。
また、可能であれば、サーバーでSELinuxを有効にします。新しいバージョンでは、実際にDockerコンテナーを確認して、コンテナーごとにセキュリティコンテキストを自動的に構築できます。これにより、コンテナーの侵害がホストに簡単に戻らないようにします。デフォルトでは、Dockerはrootユーザーとして実行され、USERディレクティブを使用しても、VMとは異なり、カーネルと直接インターフェイスします。これにより、Dockerコンテナーが侵害されるとすぐに、ホストがローカル権限の悪用にさらされます。
Dockerの人たちは最近、このためのネイティブソリューションを導入しました: https://blog.docker.com/2017/02/docker-secrets-management/
使用パターンは次のとおりです。
$ echo "This is a secret" | docker secret create my_secret_data -
$ docker service create --name="redis" --secret="my_secret_data" redis:Alpine
暗号化されていないシークレットは、/run/secrets/<secret_name>
にあるメモリ内ファイルシステムのコンテナーにマウントされます。
これはswarm
内でのみアクセス可能ですが
ここで完全なドキュメントを見つけることができます: https://docs.docker.com/engine/swarm/secrets/
docker build
には --secret
APIバージョン1.39+のオプション があります。
リリースノートの 18.09. の「Docker Engine EEおよびCEの新機能」セクションで、次のように述べています。
新しいDockerビルドの秘密情報 で--secret
オプションを見つけましたが、ここの説明は古くなっています。それは言う
このDockerfileは、シークレットにアクセスできることを示すためだけのものです。ご覧のとおり、ビルドの出力に出力された秘密が表示されます。ビルドされた最終イメージには秘密ファイルがありません
しかし、実際には秘密はビルド出力に出力されません。安全のために守られていると思います。
そして次のページを見つけました。
docker build --secret
の使い方以下の手順に従います。
$ docker version
Client: Docker Engine - Community
Version: 19.03.2
API version: 1.40
Go version: go1.12.8
Git commit: 6a30dfc
Built: Thu Aug 29 05:29:11 2019
OS/Arch: linux/AMD64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.2
API version: 1.40 (minimum version 1.12)
Go version: go1.12.8
Git commit: 6a30dfc
Built: Thu Aug 29 05:27:45 2019
OS/Arch: linux/AMD64
Experimental: false
containerd:
Version: 1.2.6
GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
runc:
Version: 1.0.0-rc8
GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f
docker-init:
Version: 0.18.0
GitCommit: fec3683
DOCKER_BUILDKIT
環境変数を1
に設定します$ export DOCKER_BUILDKIT=1
$ echo "It's a secret" > mysecret.txt
$ cat <<EOF > Dockerfile
# syntax = docker/dockerfile:experimental
FROM Alpine
RUN --mount=type=secret,id=mysecret,target=/foobar cat /foobar | tee /output
EOF
Dockerfile
の最初の行に# syntax = docker/dockerfile:experimental
があることを確認してください。上記の例はデモ用です。秘密の内容は実際の使用では保存しないでください。
docker build
を--secret
オプション付きで実行します。$ docker build -t secret-example --secret id=mysecret,src=mysecret.txt .
[+] Building 2.3s (8/8) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 176B
=> [internal] load .dockerignore
=> => transferring context: 2B
=> resolve image config for docker.io/docker/dockerfile:experimental
=> CACHED docker-image://docker.io/docker/dockerfile:experimental@sha256:888f21826273409b5ef5ff9ceb90c64a8f8ec7760da30d1ffbe6c3e2d323a7bd
=> [internal] load metadata for docker.io/library/Alpine:latest
=> CACHED [1/2] FROM docker.io/library/Alpine
=> [2/2] RUN --mount=type=secret,id=mysecret,target=/foobar cat /foobar | tee /output
=> exporting to image
=> => exporting layers
=> => writing image sha256:22c44473107b6d1f92095c6400613a7e82c9835f5baaa85853a114e4bb5d8744
=> => naming to docker.io/library/secret-example
mysecret.txt
の内容は、ビルド出力でも出力されないことに注意してください。
シークレットが正しく使用されていることを確認します。これもデモ用です。
$ docker run -t secret-example cat /output
It's a secret
/foobar
の内容は保存されていませんが、ビルドされたイメージに空のファイルが残っています。
$ docker run -t secret-example ls -l /foobar
-rwxr-xr-x 1 root root 0 Sep 16 19:16 /foobar
docker secret
はswarm
モードでのみ機能します。ローカルモードの場合、パスワードなどの単純な秘密を渡すために、stdinから変数にパスワードを読み取ることができます。問題は、コンテナ内のパイプを読み取るときにハングするdetach
モードにあります。回避策は次のとおりです。
cid=$(docker run -d -i Alpine sh -c 'read A; echo "[$A]"; exec some-server')
docker exec -i $cid sh -c 'cat > /proc/1/fd/0' <<< _a_secret_
まず、-i
オプションを指定してdockerデーモンを作成します。コマンドread A
は、/proc/1/fd/0
からの入力を待機してハングします。次に、2番目のdockerコマンドを実行して、stdinからシークレットを読み取り、最後のハングしているプロセスにリダイレクトします。シークレットは1回だけ読み取られ、検査されません。