私は最近Dockerを試してみて、いじくり回るいくつかのサービスを構築しています。そして、私を悩ませ続けている1つのことは、Dockerfileにパスワードを入力することです。私は開発者なので、パスワードをソースに保存することは、まるでパンチのように感じられます。これも懸念すべきでしょうか?Dockerfilesでパスワードを処理する方法に関する良い規則はありますか?
私は最近Dockerを試してみて、いじくり回るいくつかのサービスを構築しています。そして、私を悩ませ続けている1つのことは、Dockerfileにパスワードを入力することです。私は開発者なので、パスワードをソースに保存することは、まるでパンチのように感じられます。これも懸念すべきでしょうか?Dockerfilesでパスワードを処理する方法に関する良い規則はありますか?
回答:
確かにそれは懸念事項です。Dockerfileは通常、リポジトリにチェックインされ、他の人と共有されます。代わりに、実行時に環境変数として資格情報(ユーザー名、パスワード、トークン、その他の機密情報)を提供します。これは、-e
引数(CLIの個々の変数の場合)または--env-file
引数(ファイル内の複数の変数の場合)からを介して可能docker run
です。docker-composeで環境を使用する場合は、こちらをお読みください。
使用--env-file
すると、ps
ログまたはログに表示されるシークレットから保護されるため、使用することは間違いなく安全なオプションset -x
です。
ただし、環境変数も特に安全ではありません。これらはを介して表示されるdocker inspect
ため、docker
コマンドを実行できるすべてのユーザーが使用できます。(もちろん、docker
ホスト上でアクセス権を持つすべてのユーザーもルートを持っています。)
私が好むパターンは、ラッパースクリプトをENTRYPOINT
またはとして使用することCMD
です。ラッパースクリプトは、実行時に最初にシークレットを外部の場所からコンテナーにインポートし、次にアプリケーションを実行してシークレットを提供します。これの正確なメカニズムは、ランタイム環境によって異なります。AWSでは、IAMロール、キー管理サービス、S3の組み合わせを使用して、暗号化されたシークレットをS3バケットに保存できます。HashiCorp Vaultやcredstashのようなものは別のオプションです。
AFAIKには、ビルドプロセスの一部として機密データを使用するための最適なパターンはありません。実際、私はこのトピックについてSOの質問をしています。docker-squashを使用して、画像からレイヤーを削除できます。しかし、この目的のためのDockerにはネイティブ機能はありません。
コンテナー内の構成に関する shykes コメントが役立つ場合があります。
.config
ファイルを含む2つのレイヤー(追加後と最初の実行後)があります。
docker inspect
。
docker inspect
。攻撃者がすでにsudoを実行できる場合、Docker Inspectからパスワードを奪うことはおそらく、今や失敗する可能性のあるもののリストではかなり低いです。この特定の詳細は、私にとって許容できるリスクのようです。
私たちのチームは、資格情報をリポジトリに置くことを避けているため、で許可されていませんDockerfile
。アプリケーション内でのベストプラクティスは、環境変数からの信用情報を使用することです。
これを解決するには、を使用しdocker-compose
ます。
内docker-compose.yml
で、コンテナの環境変数を含むファイルを指定できます。
env_file:
- .env
必ずに追加して.env
から.gitignore
、次の.env
ようにファイル内に認証情報を設定します。
SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd
保管.env
ローカルまたはチームの残りの部分はそれをつかむことができ、安全な場所にファイルを。
参照:https : //docs.docker.com/compose/environment-variables/#/the-env-file
.gitignore
そのよう.env
な機密情報を含むファイルがチェックインされませんGitHubのに。これを追加しても機能しないと確信しています.dockerignore
.env
ファイルをチェックインせず、オンプレミスのサーバーにデプロイする場合、サーバーで.env
ファイルを手動で再度作成することをお勧めしますか?
Docker(バージョン1.13または17.06以降)は、秘密情報の管理をサポートしています。ここに概要と詳細なドキュメントがあります
同様の機能がkubernetesとDCOSに存在します
docker secret create
シークレットを作成するdocker secret inspect
:シークレット に関する詳細情報を表示する docker secret ls
:すべてのシークレットを表示する docker secret rm
:の特定のシークレット--secret
フラグを削除する docker service create
:サービスの作成中にシークレットを作成し --secret-add
、--secret-rm
フラグを設定するdocker service update
:シークレットの値を更新するか、シークレットを削除するサービス更新タスク中。Dockerシークレットは、マネージャーノード上で保存され、コンテナーの起動時にワーカーノードにプロビジョニングされます。
画像をダウンロードできる人に認証情報をブロードキャストしても問題がない場合を除き、認証情報をコンテナに追加しないでください。特に、credsファイルが中間ファイルシステムレイヤーの最終イメージに残っているため、ADD creds
それ以降RUN rm creds
は安全ではありません。画像にアクセスできる人なら誰でも簡単に抽出できます。
依存関係をチェックアウトするためにクレデンシャルが必要なときに私が見た典型的な解決策は、あるコンテナを使用して別のコンテナを構築することです。つまり、通常はベースコンテナーにビルド環境があり、それを呼び出してアプリコンテナーをビルドする必要があります。したがって、簡単な解決策は、アプリのソースを追加してからRUN
、ビルドコマンドを追加することです。これに信用が必要な場合、これは安全ではありませんRUN
。代わりに、ソースをローカルディレクトリに配置する代わりにdocker run
、コンテナを実行して(のように)、ローカルソースディレクトリをボリュームとしてマウントし、クレデンシャルを別のボリュームとして挿入またはマウントしてビルドステップを実行します。ビルドステップが完了したら、ビルドADD
されたアーティファクトが含まれているローカルソースディレクトリを使用するだけで、最終的なコンテナーをビルドします。
Dockerがこれをすべて簡略化するいくつかの機能を追加することを望んでいます!
更新:今後のメソッドはネストされたビルドを持つようになります。つまり、dockerfileは、ランタイム環境を構築するために使用される最初のコンテナーを記述し、次に、すべてのピースを最終的なコンテナーにアセンブルできる2番目のネストされたコンテナービルドを記述します。このように、ビルド時のものは2番目のコンテナーにありません。アプリのビルドにはJDKが必要ですが、実行にはJREのみが必要なJavaアプリです。議論されている多くの提案があります。https://github.com/docker/docker/issues/7115から始めて、代替提案のリンクのいくつかをたどるのが最善です。
環境変数を使用する代わりに、環境変数がたくさんある場合に厄介になる可能性があります。これは、ボリュームを使用して、コンテナ内のホスト上のディレクトリにアクセスできるようにすることです。
すべての資格情報をファイルとしてそのフォルダーに配置すると、コンテナーはファイルを読み取り、必要に応じてそれらを使用できます。
例えば:
$ echo "secret" > /root/configs/password.txt
$ docker run -v /root/configs:/cfg ...
In the Docker container:
# echo Password is `cat /cfg/password.txt`
Password is secret
多くのプログラムは資格情報を別のファイルから読み取ることができるので、この方法でプログラムにファイルの1つを指定するだけで済みます。
ランタイムのみのソリューション
docker-composeは非スウォームモードソリューションも提供します(v1.11:以降、 バインドマウントを使用したシークレット)。
シークレットは/run/secrets/
docker-composeによって以下のファイルとしてマウントされます。これは、実行時(コンテナーの実行時)の問題を解決しますが、ビルド時(イメージのビルド時)では解決し/run/secrets/
ません。これは、ビルド時にマウントされないためです。さらに、この動作はdocker-composeでのコンテナーの実行に依存します。
例:
Dockerfile
FROM alpine
RUN cat /run/secrets/password
CMD sleep inifinity
docker-compose.yml
version: '3.1'
services:
app:
build: .
secrets:
- password
secrets:
password:
file: password.txt
ビルドするには、次を実行:
docker-compose up -d
参考文献:
ドッカーV1.9は、使用できるARG命令を上の画像に、コマンドラインで渡される引数フェッチするために、ビルドアクションを。単に--build-argフラグを使用します。そのため、Dockerfileに明示的なパスワード(またはその他の賢明な情報)を保持して、その場で渡すことを回避できます。
ソース:https : //docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg
例:
Dockerfile
FROM busybox
ARG user
RUN echo "user is $user"
イメージ作成コマンド
docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .
ビルド中に印刷します
$ docker build --build-arg user=capuccino -t test_arguments -f ./test_args.Dockerfile .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM busybox
---> c51f86c28340
Step 2 : ARG user
---> Running in 43a4aa0e421d
---> f0359070fc8f
Removing intermediate container 43a4aa0e421d
Step 3 : RUN echo "user is $user"
---> Running in 4360fb10d46a
**user is capuccino**
---> 1408147c1cb9
Removing intermediate container 4360fb10d46a
Successfully built 1408147c1cb9
それが役に立てば幸い!さようなら。
--build-arg var=secret
がSSH秘密鍵をイメージに渡すために使用することを推奨しないのかと疑問に思っているだけで、文書化された根拠はありません。誰かがそれを説明できますか?
docker history
公開されるためだと思います。イメージをプルして検査し、ビルド中に/ パラメータとして渡されたシークレットを確認できます。build-arg
ARG
build-arg
ARG
私のアプローチはうまくいくようですが、おそらく素朴です。それが間違っている理由を教えてください。
docker build中に設定されたARGは、historyサブコマンドによって公開されるため、そこに行く必要はありません。ただし、コンテナーを実行する場合、runコマンドで指定された環境変数はコンテナーで使用できますが、イメージの一部ではありません。
したがって、Dockerfileで、秘密データを含まない設定を行います。のようなもののCMDを設定し/root/finish.sh
ます。runコマンドで、環境変数を使用してシークレットデータをコンテナーに送信します。finish.sh
基本的に変数を使用して、ビルドタスクを完了します。
秘密データの管理を容易にするために、--env-file
スイッチで実行されるdockerによってロードされるファイルにそれを入れます。もちろん、ファイルは秘密にしてください。.gitignore
など。
私にとってfinish.sh
は、Pythonプログラムを実行します。それが以前に実行されたことがないことを確認してから、セットアップを終了します(たとえば、データベース名をDjangoにコピーしますsettings.py
)。
12ファクターアプリの方法論は、任意の構成は、環境変数に格納する必要があることを、伝えます。
Docker composeは構成で変数の置換を行うことができるため、ホストからdockerにパスワードを渡すために使用できます。
私は完全に同意しますが、簡単な解決策はありません。単一障害点が引き続き存在します。dockerfile、etcdなどのいずれかです。Apceraには、サイドキック-デュアル認証のような計画があります。つまり、Apcera構成ルールがない限り、2つのコンテナーは通信できません。彼らのデモでは、uid / pwdは明確であり、管理者がリンケージを構成するまで再利用できませんでした。ただし、これが機能するためには、おそらくDockerまたは少なくともネットワークプラグインにパッチを当てることを意味します(そのようなものがある場合)。