Skip to main content

Dockerのシークレットを安全に管理する方法(Kubernetesを使っていない場合も)

著者

Marcelo Oliveira

hero docker secrets

2022年8月24日

0 分で読めます

分散コンテナシステムは、アプリケーション、リソース、サービス、データベースなどのコンポーネントで構成されます。これらのコンポーネントが適切に機能するには、ユーザーキー、パスワード、APIキー、証明書などの機密情報が必要になることがよくあります。

シークレット管理は、機密情報を適切に扱ううえで欠かせません。Kubernetes環境では、組み込みのSecretsリソースタイプと関連するRBAC制御がよく利用されます。しかし、Kubernetesにデプロイしない場合はどうでしょうか?Kubernetesの強力な機能が不要な組織や、その複雑さを引き受けたくない組織も少なくありません。それでも、データ漏えいやパスワード紛失のリスクを避ける必要があります。幸い、Dockerに組み込まれたSwarmオーケストレーターがその解決策を提供します。

この記事では、Dockerでシークレットを管理する方法を取り上げ、ベストプラクティスと使用に伴う潜在的なリスクを解説します。また、Dockerシークレットの作成と一覧表示、サービスへの追加と削除を行う簡単な演習も紹介します。読者は、DockerコンテナランタイムとそのSwarmオーケストレーターについて基本的な知識があることを前提としています。

Dockerシークレットを安全に管理する

組織内でシークレットや機密データをやり取りする際には、データ漏えいやパスワード紛失のリスクがあります。パスワード、秘密鍵、トークン、APIキーなどの機密情報を扱うDockerプロジェクトでは、シークレットを安全に保管し、コンテナに渡す方法を定める必要があります。

最も避けるべき方法のひとつは、機密データをソースコードに残すことです。セキュリティ上の懸念に加えて、コードにシークレットをハードコードすると、シークレットを変更するたびにイメージを再ビルドしなければなりません。

もうひとつのよくない方法は、パスワードやSSHキーなどの重要な情報を「手作業」で扱い、ローカルディスクに残しておくことです。権限のないユーザーや悪意のあるプログラムもファイルを読み取る可能性があることを忘れてはいけません。

開発者は機密データの保存に環境変数をよく使います。状況によっては問題ありませんが、Dockerコンテナでは推奨されません。環境変数はファイルよりも安全性が低く、次のようなさまざまな経路から漏れる可能性があります。

たとえば、アプリケーションの例外処理コードがログにcontextを出力すると、環境変数に含まれる機密値までログに記録されるおそれがあります。

シークレットマネージャーを使うと、Docker Swarmでシークレットを一元管理できるため、先ほどの方法よりはるかに優れています。シークレットマネージャーは、シークレットの保存、管理、取得を便利に行えるサービスを提供し、アプリケーション、サービス、ITリソースへのアクセスを保護します。対象となるのは、APIやデータベースの認証情報、キー、パスワード、SSH秘密鍵、SSL証明書など、アプリケーションの実行時に必要な機密データです。

Dockerでのシークレット管理の仕組み

マネージャー、ロックされたワーカー、内部ドキュメント、キー、外部アプリを含むRaftコンセンサスグループに、Web UIが接続する様子を示す図。

上の図は、Dockerが分散システム内の複製ログを管理するためにRaftという合意アルゴリズムを使用し、Swarm全体とその上で稼働するすべてのサービスでデータの一貫性を保っていることを示しています。Raftアルゴリズムは、シークレットを暗号化してすべてのマネージャーノードに一貫して送信します。

図には、ワーカーノードも示されています。これらは、コンテナの実行に特化したDocker Engineのインスタンスです。マネージャーノードは、キーが割り当てられたサービスに属するコンテナへシークレットを配布します。

Dockerシークレットは、機密データを保管できる金庫のようなものです。金庫の鍵を持っている場合にのみ利用できます。鍵は、その鍵を割り当てたサービスノードから取得する必要があります。

Dockerのシークレット管理サービスは、コンテナオーケストレーションスタックの一部であり、データを安全に保つプロセスを自動化します。

Docker Swarmサービスでは、シークレットは保存時も転送時も暗号化されています。

Dockerシークレットは一元管理でき、アクセスが必要なコンテナに安全に送信できます。各シークレットにアクセスできるのは、明示的に権限を付与されたサービスだけであり、サービスの稼働中に限られます。

サービスがシークレットへのアクセス権を得ると、シークレットを復号して、メモリ内ファイルシステムを介してコンテナと共有します。コンテナタスクが停止すると、利用可能だった復号済みシークレットは直ちに切り離され、ノードのメモリから消去されます。

Docker CLIでシークレットを管理する

Dockerの組み込み機能を使うと、シークレットを登録し、どのサービスがシークレットにアクセスできるか、またどのような状況で使用できるかを細かく制御できます。

この簡単な演習では、rootパスワードを設定したMySQLサービスを作成し、その認証情報をシークレットとして追加します。

DockerシークレットはSwarmサービスでのみ利用できるため、動作を確認するにはDocker Swarmをセットアップする必要があります。まず、Dockerコマンドライン(Docker CLI)がインストールされていることを確認してください。まだの場合は、Swarmを初期化するか、参加します。

docker swarm init

Swarm initialized: current node (wv4c3hvdwqlssjpaxzvvhy3vj) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-3qizt7vyw8cbpii3nosl8ws7zr1npikrepr0qqh9ad7esucwon-bfxct86tefphzo8xiz8ue0tx6 192.168.65.3:2377

次に、Dockerにシークレットを追加します。

シークレットを保存する場所にテキストファイルを作成します。次のコマンドは、this-is-a-mysql-passwordという文字列を含むpassword.txtファイルを作成します。

$ echo "this-is-a-mysql-password" > $HOME/password.txt

次に、docker secret createコマンドを使い、前の手順で作成したファイルから新しいシークレットを作成します。

$ docker secret create mysql-password-secret $HOME/password.txt

l1m5jvgcox1l96i6bjbz4dvnt

上記のl1m5jvgcox1l96i6bjbz4dvntという文字列はシークレットそのものではなく、シークレットIDです。そのため、実際の環境では異なる値になります。

次に、docker secret createコマンドの別の使い方を見てみましょう。最後の引数(ファイルを表す引数)にマイナス記号(-)を指定して、ファイル名を省略します。

$ echo "another-mysql-password" | docker secret create another-mysql-secret -

このコマンドを実行すると、次のような出力が表示されます。

q3bjo7wx4xqr45ma20lk5j2g7

この方法ではシークレットを読み取るファイルを指定せず、docker secret createコマンドが標準入力からanother-mysql-passwordを読み取ります。

Dockerシークレットの一覧表示

Docker Swarmで利用可能なシークレットを一覧表示するには、docker secret lsコマンドを実行します。

$ docker secret ls

Docker Swarmで作成したシークレットの一覧が出力されます。

ID                          NAME                    DRIVER    CREATED              UPDATED
q3bjo7wx4xqr45ma20lk5j2g7   another-mysql-secret              46 seconds ago       46 seconds ago
l1m5jvgcox1l96i6bjbz4dvnt   mysql-password-secret             About a minute ago   About a minute ago

シークレットを使ってサービスを作成する

上で作成したシークレットを使ってサービスを作成できます。

mysql-serviceサービスを作成し、--secretフラグを使って、コンテナにanother-mysql-secretへのアクセス権を付与します。

$ docker service create --name mysql-service --secret another-mysql-secret mysql:5.7

既存のサービスへのシークレットの追加・削除

既存のサービスからシークレットを削除できます。

$ docker service update --secret-rm another-mysql-secret mysql-service

または、稼働中のサービスにシークレットを追加できます。

$ docker service update --secret-add mysql-password-secret mysql-service

シークレットをサービスに紐付けると、Dockerはシークレットと同じ名前のテキストファイルを作成します。このファイルにはシークレットを表す文字列が含まれ、デフォルトでは、コンテナ内にマウントされた/run/secretsディレクトリにある一時ファイルシステム(TMPFS)に配置されます。この例では、ファイルのパスは/run/secrets/mysql-password-secretです。作成すると、そのサービスのすべてのコンテナでシークレットを利用できます。

外部シークレット管理の選択肢

Dockerシークレットは優れたソリューションですが、このタスクを外部のサードパーティ製シークレットストレージに委ねることも検討しましょう。特定のプラットフォームに関する知見や投資がすでにある組織では、特に有効です。

たとえば、すでにHashicorp Vaultを利用していて、アプリケーションが統合されているなら、プラットフォームに組み込まれているという理由だけでDockerシークレット(またはKubernetesシークレット)に切り替える必要はほとんどありません。そのソリューションに関する既存のプロセス、ライブラリ、知見をサービスで活用しましょう。

シークレット管理の代表的な選択肢には、次のようなものがあります。

シークレットを安全に保つ

この記事では、Docker Swarmにおけるシークレットとシークレット管理の概念を紹介し、Dockerがシークレットを管理する仕組みを解説しました。また、機密データをハードコードしたり、環境変数を使ったり、手作業で管理したりするより、シークレットマネージャーを利用するほうがはるかに優れていることを示しました。

データセキュリティは、効果的な企業統治を支える柱のひとつです。CLIコマンドと、シークレットデータを細かく制御してデプロイできるインメモリーアーキテクチャにより、Dockerは堅牢なシークレット管理ツールを提供し、組織の情報セキュリティの適切な実装を支援します。

シークレットをのぞき見から守ることは、安全なコンテナを構築するための第一歩です。Snyk Codeはハードコードされたシークレットの検出を支援し、Snyk ContainerとSnyk Open Sourceは、コンテナに最適な安全性の高いベースイメージやパッケージを見つける手助けをします。本番環境への移行準備が整ったら、Snyk IaCでデプロイ前後のリスクを低減できます。今すぐ無料で始めて、コード、オープンソース依存関係、コンテナ、クラウドインフラストラクチャの脆弱性を検出し、自動的に修正しましょう。

開発者ファーストのコンテナセキュリティ

Snykは、コンテナイメージとKubernetesワークロードの脆弱性を検出し、自動的に修正します。

続きを読む

Blog

フロンティアモデルは脆弱性を発見した。攻撃者だけがエクスプロイトチェーンを見つけた。

静的解析で欠陥は見つかりましたが、ライブ攻撃テストで侵害につながる連鎖を実証できたのは唯一でした。Evo COS、Claude Security、Claude Code Securityを比較します。

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。

Blog

AIコーディングエージェントが不適切なアクセス制御を繰り返し実装する理由

AIコーディングエージェントは、コンパイルが通りレビューも通過する一方で、あるテナントのデータを別のテナントに公開してしまう認可ロジックを生成することがあります。不適切なアクセス制御が検出しにくい理由と、その防止策をご紹介します。