Docker Secrets: 不注意な ‘inspect’ コマンドでパスワードを漏洩させないために

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

Docker Secrets でパスワードを「不可視化」する5分間ガイド

データベースのパスワードがシステムログに丸見えになっているのは避けたいですよね? docker-compose.yml ファイルの environment セクションに API キーを直接記述するのは絶対にやめましょう。代わりに、ローカル環境から適切に保護するために Docker Secrets を使用します。

ステップ1: パスワードを含むファイルを作成します(例:db_password.txt)。公開サーバーにプッシュされないよう、忘れずに .gitignore にこのファイルを追加してください。

echo "my-super-secret-password" > db_password.txt

ステップ2: docker-compose.yml での secrets の定義は非常に簡単です:

services:
  db:
    image: postgres
    secrets:
      - db_password
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password

secrets:
  db_password:
    file: ./db_password.txt

ステップ3: docker compose up -d コマンドを実行すれば完了です。パスワードは /run/secrets/db_password に安全に格納されます。誰かが興味本位で docker inspect を実行しても、実際のパスワードの代わりに空欄が表示されるだけです。

環境変数:思っている以上に大きな「落とし穴」

実のところ、docker inspect <container_id> コマンドを一つ実行するだけで、サーバーへのアクセス権を持つ同僚や誰にでも、あなたの秘密情報は筒抜けになってしまいます。集中監視ツールのログにこれらの環境変数が書き込まれ、機密情報がすべて漏洩してしまったシステムを私は目にしたことがあります。

Docker Secrets は以下のメカニズムによって、この問題を根本的に解決します:

  • RAM 上での保存: Docker Swarm では、シークレットは暗号化された Raft ログに保存され、必要な時にのみコンテナの RAM(tmpfs)にマウントされます。データが物理ディスクに書き込まれることはありません。
  • アクセス制御: 明示的に指定されたサービスのみが、そのシークレットを「見る」権限を持ちます。
  • 一元管理: 開発環境と本番環境でデータが混ざることを心配せずに、同じ設定を複数の環境に簡単にデプロイできます。

実際の動作メカニズム

シークレットをサービスにアタッチすると、Docker はそれをコンテナ内の /run/secrets/ ディレクトリにファイルとしてマウントします。MariaDB、Postgres、WordPress などの主要なイメージの多くは、_FILE 接尾辞オプションを標準で備えています。これにより、アプリケーションは通常の環境変数からではなく、ファイルから直接データを読み取ることができます。

Docker Swarm でセキュリティを向上させる

Docker Swarm でクラスターを運用している場合、シークレットの管理はよりプロフェッショナルなものになります。すべての機密データは、管理ノード(Manager nodes)間で暗号化された mTLS チャネルを介して同期され、極めて高いセキュリティが確保されます。

CLI から直接シークレットをプッシュする

サーバー上に物理ファイルを作成する必要はありません。コマンド一行で Swarm のデータベースに値を直接プッシュできます:

echo "serect_key_2024" | docker secret create api_key -

Stack Deploy による展開

stack.yml ファイルでは、external キーワードを使用して、システムに既に存在するシークレットを活用します:

version: '3.8'
services:
  app:
    image: my-app:latest
    secrets:
      - api_key

secrets:
  api_key:
    external: true

最後に、おなじみのコマンドでシステムをデプロイします: docker stack deploy -c stack.yml my_web_app

「失敗」から得た経験

docker-compose v1 から v2 への移行は非常にスムーズです。v2(ハイフンのない docker compose コマンドを使用)では、Swarm を実行していない場合でも、secrets 機能が標準となりました。以前のような複雑なエミュレーション手法を使う必要はもうありません。

より柔軟なコードを書く

アプリケーションをローカルと本番環境の両方で適切に動作させるために、私はよく Python で、環境変数の前に Docker のシークレットファイルから優先的に読み取る小さな関数を書きます:

import os

def get_config(key, default=None):
    # Docker のシークレットパスからの読み取りを優先
    secret_path = f"/run/secrets/{key}"
    if os.path.exists(secret_path):
        with open(secret_path, 'r') as f:
            return f.read().strip()
    # ファイルが見つからない場合は環境変数にフォールバック
    return os.getenv(key, default)

シークレットを「期限切れ」にしない(シークレットのローテーション)

多くの人は、同じパスワードを2〜3年も変えずに使い続ける習慣があります。Docker Swarm では、シークレットは不変(immutable)であるため、更新が必要な場合は新しいバージョンを作成する必要があります。標準的な手順は次の通りです: api_key_v2 を作成し、compose ファイルを更新して再デプロイし、Docker が自動的にコンテナを置き換えるのを待ち、最後にすべてが安定したら api_key_v1 を削除します。

安心して眠るためのチェックリスト

  • シークレットファイルのコミット禁止: .gitignore を常にチェックし、.txt.key ファイルが Git に紛れ込んでいないか確認してください。
  • Docker Configs の適切な使い分け: nginx.conf のような通常の構成ファイルには、最高のパフォーマンスを得るために secrets ではなく configs を使用してください。
  • 最小権限の原則: フロントエンドを実行するコンテナが、データベースマスターのシークレットにアクセスすることは絶対に許可しないでください。
  • RAM の活用: Swarm では、シークレットは RAM 上にのみ存在することを忘れないでください。これにより、サーバーの物理ディスクの制御が奪われた場合でもデータを保護できます。

セキュリティ管理は決して難しくありません。大切なのは、それを日々の習慣にすることです。強力かつ安全なシステムを構築できることを願っています!

Share: