実行時の設定ファイル内のシークレット

アプリケーションの構造上、config.yaml、application.yml、settings.json などの設定ファイルを維持する必要がある場合があります。その場合も、シークレットの実際の値をリポジトリにコミットしないでください。実ファイルは安全な供給元から実行時に生成またはマウントしてください。

このガイドが役立つ場合

  • 環境変数だけでは設定構造を変更しにくい場合
  • アプリケーションが特定のパスの設定ファイルを必要とする場合
  • config.yaml.example に加え、運用に実際の config.yaml も必要な場合
  • Kubernetes、Vault Agent、CSIドライバー、デプロイシステムの安全なファイル配信を利用できる場合

基本となる推奨パターン

  • リポジトリには config.yaml.example だけを置いてください。
  • 実際の config.yaml はGitにコミットしないでください。
  • 実ファイルはKubernetes Secretボリューム、CSI/Vault Agent、安全なファイル配信によって、実行時に生成またはマウントしてください。
  • アプリケーションは指定パスから設定を読み、ファイルがない場合や必須のシークレットが空の場合は処理を続けず終了するようにしてください。

このパターンを選ぶ場合

  • アプリケーションが特定のパスから設定ファイルを読む必要がある場合
  • 環境変数だけでは階層的な設定を表現しにくい場合
  • デプロイプラットフォームがシークレットファイルのマウントや安全なファイル配信を標準で提供する場合

避けるべきパターン

  • 本番用の config.yaml をリポジトリにコミットする
  • シークレットを含む config.yaml をConfigMapに保存する
  • Dockerイメージに config.yaml を埋め込む
  • Dockerfile の COPY で本番用の config.yaml を含める
  • 手動でのファイル配布を標準の運用方法にする

推奨構成

text
config.yaml.example         # サンプル設定のみ。Gitへのコミット可
config.yaml                 # 実際の本番設定。Gitへのコミット禁止
.gitignore                  # config.yamlを含める
/etc/app/config.yaml        # 実行時にマウントまたは生成する実ファイルのパス例

例

変更前

yaml
database:
  host: prod-db.internal
  user: app_user
  password: super-secret-password

jwt:
  secret: hardcoded-jwt-secret

このようなファイルがリポジトリに含まれる場合は、シークレットが露出したものとして扱ってください。

変更後

リポジトリに置くファイル:config.yaml.example

yaml
database:
  host: prod-db.internal
  user: app_user
  password: "<runtime-provided>"

jwt:
  secret: "<runtime-provided>"

実行時のファイルパス例

text
/etc/app/config.yaml

このファイルは、Kubernetes Secretボリューム、Vault Agent/CSI、またはデプロイシステムの安全なファイル配信によって、実行時に生成またはマウントされます。

ファイル権限

  • アプリケーションの実行ユーザーだけが設定ファイルを読めるよう、権限を最小限にしてください。
  • 全ユーザーに読み取りを許可しないでください。
  • 所有者とグループを運用標準に合わせて制限してください。

次のコマンドは、通常の書き込み可能なファイルを対象としています。Kubernetes Secretボリュームのような読み取り専用マウントでは、ボリュームの設定で権限と所有権を構成してください。

bash
chmod 600 /etc/app/config.yaml
chown appuser:appgroup /etc/app/config.yaml

Kubernetesでの例

  • 設定ファイルの内容を Secret または外部シークレット連携リソースに保存してください。
  • Secretボリュームを使い、Podの /etc/app/config.yaml にマウントしてください。
  • ConfigMap で代用しないでください。

開発者が行うこと

  • リポジトリにある実際の設定ファイルから、シークレットの値を削除してください。
  • 実行時のファイルパスを読む構造を維持しつつ、ファイルや必須値がない場合は直ちに失敗するようにしてください。
  • 設定オブジェクト全体をログ、panic、デバッグダンプに出力しないでください。
  • シークレットのローテーション時に再読み込みや再起動が必要かを文書化してください。

インフラ・プラットフォーム担当者が行うこと

  • 実ファイルはKubernetes Secretボリューム、CSI/Vault Agent、または安全なファイル配信で供給してください。
  • シークレットを含むファイルには、ConfigMap、Dockerイメージへの埋め込み、Dockerfile COPY を使わない運用標準を定めてください。
  • ファイルの所有者、グループ、権限を必要最小限にしてください。
  • ローテーション時のファイル更新と再起動・再読み込みの手順を運用文書に含めてください。

確認方法

  • リポジトリに本番用の設定ファイルがないことを確認してください。
  • コンテナーやホスト上のファイル権限が最小限になっていることを確認してください。
  • ファイルがない場合にアプリケーションが失敗することを確認してください。
  • 設定値がログ、actuator、例外メッセージに露出していないことを確認してください。

よくある間違い

  • 本番用の config.yaml をGitにコミットする
  • シークレットを含む設定ファイルをConfigMapに保存する
  • Dockerイメージに設定ファイルを埋め込む
  • 権限を広く許可し、誰でも読める状態でデプロイする
  • シークレットをローテーションしても、再読み込みや再起動の手順を定めない

担当者の対処手順

露出した認証情報は、以下のファイル整理やデプロイ変更を待たず、まず失効または無効化して新しい値に置き換えてください。

  1. リポジトリにコミットされた実際の config.yaml からシークレットの値を削除してください。
  2. リポジトリには config.yaml.example だけを残し、実際の config.yaml を .gitignore に追加してください。
  3. 実際の config.yaml はKubernetes Secretボリューム、CSI/Vault Agent、または安全なファイル配信によって実行時に供給してください。
  4. 指定パスを読む構造は維持し、ファイルや必須シークレットがない場合は直ちに終了するようにしてください。
  5. ファイル権限を最小限にし、全ユーザーへの読み取り許可を取り除いてください。
  6. デバッグログ、panic、設定ダンプにシークレットが出ないようマスキングしてください。
  7. ローテーションでファイルを更新した後の再読み込みまたは再起動手順を文書化してください。
  8. 古い値がリポジトリに露出していた場合は、失効して再発行してください。

担当者への案内例

  • 「config.yaml 形式を維持する場合も、本番の実ファイルはGitにコミットせず、実行時に安全にマウントしてください。」
  • 「リポジトリには config.yaml.example だけを残し、実際の config.yaml はKubernetes Secretボリュームまたはデプロイシステムの安全なファイル配信で供給してください。」
  • 「設定ファイルがない場合や必須のシークレットが空の場合は、アプリケーションを直ちに失敗させてください。」
  • 「シークレットを含む config.yaml をDockerイメージやConfigMapに含めないでください。」

運用チェックリスト

  • 実際の設定ファイルが .gitignore の対象になっているか。
  • config.yaml.example と実際の config.yaml の役割が分かれているか。
  • ファイル権限は最小限になっているか。
  • ログ、panic、デバッグダンプに設定オブジェクト全体を出力していないか。
  • ローテーション時の再読み込みや再起動の手順が定められているか。
  • 例外的に手動配置する場合も、標準の推奨方法ではなく代替手段として管理しているか。

関連文書