Dockerと安全なパスワード


162

私は最近Dockerを試してみて、いじくり回るいくつかのサービスを構築しています。そして、私を悩ませ続けている1つのことは、Dockerfileにパスワードを入力することです。私は開発者なので、パスワードをソースに保存することは、まるでパンチのように感じられます。これも懸念すべきでしょうか?Dockerfilesでパスワードを処理する方法に関する良い規則はありますか?


7
Githubのはドッカーと秘密に関するベストプラクティスのための要求に未解決の問題があり、問題はここにある:github.com/docker/docker/issues/13490
ルイス・Bianchin

回答:


92

確かにそれは懸念事項です。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 Vaultcredstashのようなものは別のオプションです。

AFAIKには、ビルドプロセスの一部として機密データを使用するための最適なパターンはありません。実際、私はこのトピックについてSOの質問をしています。docker-squashを使用して、画像からレイヤーを削除できます。しかし、この目的のためのDockerにはネイティブ機能はありません。

コンテナー内の構成に関する shykes コメントが役立つ場合があります。


他のコメントで述べたように、.configファイルを含む2つのレイヤー(追加後と最初の実行後)があります。
Petr Gladkikh 2014年

1
ええ、env変数が最善の方法です。私はこれをTDDing Dockerfile開発のコンテキストで見てきました。
gnoll110 2015年

5
パスワードがenv変数の場合、に表示されるのではないかと心配ですdocker inspect
スリム

docker(Linux)のデフォルトのインストールでは、sudoer特権を実行する必要がありますdocker inspect。攻撃者がすでにsudoを実行できる場合、Docker Inspectからパスワードを奪うことはおそらく、今や失敗する可能性のあるもののリストではかなり低いです。この特定の詳細は、私にとって許容できるリスクのようです。
GrandOpener 2017年

7
@GrandOpenerこれは、システムを使用している攻撃者がいる状況にのみ適用されます。dockerイメージをリポジトリーにプッシュし、それが他の誰かによってプルされた場合、彼らが自分のシステムにsudoを持っているかどうかは気にしませんが、envに存在しないはずのシークレットが表示されるかどうかは気にしません。
vee_ess 2017年

74

私たちのチームは、資格情報をリポジトリに置くことを避けているため、で許可されていません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


15
必要に応じて、.envファイルなしでこれを行うこともできます。docker-compose.ymlファイルで環境プロパティを使用するだけです。「キーのみの環境変数は、Composeが実行されているマシンの値に解決されます。これは、秘密の値またはホスト固有の値に役立ちます。」
D.フィッサー、2016

1
この男にクッキーを与えなさい!:)うん、これは本当に良い習慣ですdocs.docker.com/compose/env-fileを追加したいだけです。 これは自動的に機能するはずですが、Docker Composeバージョン2では、この回答で説明されているように宣言する必要があるようです。
equivalent8

5
env varは/ proc / <pid> / environおよびdocker inspectを介して確認できるため、Dockerチーム自体が環境変数を使用することはお勧めしません。ルートアクセスを取得した攻撃者の資格情報を取得する方法を難読化するだけです。もちろん、資格情報はCVSによって追跡されるべきではありません。rootユーザーがクレデンシャルを取得するのを防ぐ唯一の方法は、暗号化されたファイルからWebアプリ内から(そのproc環境ファイルを更新しないことを期待して)クレデンシャルを読み取ることであり、復号化プロセスはパスワードを安全に要求します。墓で試してみるつもりです:github.com/dyne/Tomb
pawamoy

.gitignoreそのよう.envな機密情報を含むファイルがチェックインされませんGitHubのに。これを追加しても機能しないと確信しています.dockerignore
theUtherSide

こんにちは@theUtherSide、回答ありがとうございます。質問がありました。.envファイルをチェックインせず、オンプレミスのサーバーにデプロイする場合、サーバーで.envファイルを手動で再度作成することをお勧めしますか?
opensource-developer

37

Docker(バージョン1.13または17.06以降)は、秘密情報の管理をサポートしています。ここに概要と詳細なドキュメントがあります

同様の機能がkubernetesDCOSに存在します


上記のリンクからのいくつかの便利なコマンド::docker secret createシークレットを作成するdocker secret inspect:シークレット に関する詳細情報を表示する docker secret ls:すべてのシークレットを表示する docker secret rm:の特定のシークレット--secretフラグを削除する docker service create:サービスの作成中にシークレットを作成し --secret-add--secret-rmフラグを設定するdocker service update:シークレットの値を更新するか、シークレットを削除するサービス更新タスク中。Dockerシークレットは、マネージャーノード上で保存され、コンテナーの起動時にワーカーノードにプロビジョニングされます。
PJ

7
はい、Dockerシークレットを使用するには、スウォームをセットアップする必要があります
Heather QC

11
これは回答の良い出発点ですが、回答自体に表示されるようにリンクされている情報からさらに多くの情報が必要です。
ジェフランバート

7
群れでのみ機能する場合、これが受け入れられる答えになるかどうかはわかりません。多くの人々は群れを使用していませんが、それでも秘密を渡す必要があります。
John Y

9

画像をダウンロードできる人に認証情報をブロードキャストしても問題がない場合を除き、認証情報をコンテナに追加しないでください。特に、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から始めて、代替提案のリンクのいくつかをたどるのが最善です。


7

環境変数を使用する代わりに、環境変数がたくさんある場合に厄介になる可能性があります。これは、ボリュームを使用して、コンテナ内のホスト上のディレクトリにアクセスできるようにすることです。

すべての資格情報をファイルとしてそのフォルダーに配置すると、コンテナーはファイルを読み取り、必要に応じてそれらを使用できます。

例えば:

$ 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つを指定するだけで済みます。


5

ランタイムのみのソリューション

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

参考文献:


2

ドッカー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

それが役に立てば幸い!さようなら。


26
DockerのARGドキュメントによると、「githubキー、ユーザー資格情報などのシークレットを渡すためにビルド時変数を使用することはお勧めしません」
Lie Ryan

3
なぜDocker --build-arg var=secretがSSH秘密鍵をイメージに渡すために使用することを推奨しないのかと疑問に思っているだけで、文書化された根拠はありません。誰かがそれを説明できますか?
Henk Wiersema 2016年

2
@HenkWiersemaプロセス情報、ログ、コマンド履歴は安全ではありません。プロセス情報は公開されており、すべてのコマンドラインパラメータが含まれています。多くの場合、これらの呼び出しは、公開することもできるログに記録されます。攻撃者が実行中のプロセスに関する情報を検査し、シークレットがないか公開ログファイルをトロールすることは珍しいことではありません。公開されていない場合でも、コマンド履歴に保存される可能性があるため、管理者以外のアカウントを介して簡単にシークレットを取得できます。
tu-Reinstate Monica-dor duh 2016

2
ビルド時に必要な資格情報を提供するための推奨される方法は何ですか?たとえば、画像内に存在する大きなデータセットをフェッチするためにaws s3アクセスが必要な画像は?
-e

3
推奨されない理由は、/ 変数がdocker history公開されるためだと思います。イメージをプルして検査し、ビルド中に/ パラメータとして渡されたシークレットを確認できます。build-argARGbuild-argARG
vee_ess

2

私のアプローチはうまくいくようですが、おそらく素朴です。それが間違っている理由を教えてください。

docker build中に設定されたARGは、historyサブコマンドによって公開されるため、そこに行く必要はありません。ただし、コンテナーを実行する場合、runコマンドで指定された環境変数はコンテナーで使用できますが、イメージの一部ではありません。

したがって、Dockerfileで、秘密データを含まない設定を行います。のようなもののCMDを設定し/root/finish.shます。runコマンドで、環境変数を使用してシークレットデータをコンテナーに送信します。finish.sh基本的に変数を使用して、ビルドタスクを完了します。

秘密データの管理を容易にするために、--env-fileスイッチで実行されるdockerによってロードされるファイルにそれを入れます。もちろん、ファイルは秘密にしてください。.gitignoreなど。

私にとってfinish.shは、Pythonプログラムを実行します。それが以前に実行されたことがないことを確認してから、セットアップを終了します(たとえば、データベース名をDjangoにコピーしますsettings.py)。


2

「シークレット」管理用の新しいdocker コマンドがあります。しかし、それは群れクラスターでのみ機能します。

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 


-2

私は完全に同意しますが、簡単な解決策はありません。単一障害点が引き続き存在します。dockerfile、etcdなどのいずれかです。Apceraには、サイドキック-デュアル認証のような計画があります。つまり、Apcera構成ルールがない限り、2つのコンテナーは通信できません。彼らのデモでは、uid / pwdは明確であり、管理者がリンケージを構成するまで再利用できませんでした。ただし、これが機能するためには、おそらくDockerまたは少なくともネットワークプラグインにパッチを当てることを意味します(そのようなものがある場合)。


2
質問のどこかに答えはありますか?
Abhijit Sarkar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.