秘密情報の管理

OWASP の Secrets Management Cheat Sheet を取得して読み、 理解した内容を自分の言葉で書いたもの。

原則

一元化して標準化する
  複数の仕組み(クラウド、サードパーティ、パスワードマネージャ)が必要になることはある
  それでも、扱い方は組織で統一する

最小権限を徹底する
  エンジニアが全部の秘密情報にアクセスできる状態にしない
  各主体が必要なものだけに触れるよう、細かい粒度で制御する

ローテーションを自動化する
  手作業での維持は、漏洩と人為ミスの温床
  CI/CD、起動時の動的発行、定期処理のいずれかで回す

生存期間を最小にする
  短命な資格情報を使う
  動的な秘密情報なら、アプリの再起動で自動的に失効する

ハードコードしない
  平文でソースに埋め込むのが最大のアンチパターン

暗号化する
  AES-256-GCM か ChaCha20-Poly1305
  転送時(TLS)も保存時も暗号化する
  鍵は暗号化されたデータとは別の場所に保管する

ソースコードと CI/CD

置き場所には3通りあり、下にいくほど分離が強い

方式注意点
CI/CD ツールの秘密情報機能(GitHub Actions, GitLab, Jenkins)大きな権限の秘密を置かない。短命に保ち、影響範囲を限定する。定期的にローテーションし、アクセスを監査する。fork で秘密がコピーされないようにする。何の秘密をなぜ置いているかを文書化する
外部の秘密情報管理システム(AWS Secrets Manager, HashiCorp Vault, Azure Key Vault)取得に使う CI/CD の資格情報自体を一時的かつ最小権限にする。呼び出しの帰属を追えるようにする。ジョブ終了で失効させる
CI/CD が秘密情報に触れない利用側が管理システムから直接取得する。CI/CD はサービスアカウントでデプロイを指揮するだけ。関心の分離が最も強い

パイプライン自体を守る

CI/CD は本番インフラとして扱う。 堅牢化し、パッチを当て、監視する。

最小権限。開発者がパイプラインを管理者として触れないようにする
パイプラインの出力から秘密が漏れないようにする
ランナーへの exec を禁止する
すべての操作を監査し、不審な改変にアラートを出す

検出とスキャン

開発者の手元(IDE、pre-commit フック)で検出できるようにする
脅威モデリングに秘密情報の検出を含める
組織共通のテスト用ダミー秘密を用意して、誤検知を減らす
API キー、資格情報、SSHキー、トークン、接続文字列など、よくある20種類程度を追跡する

仕掛ける場所は3つ。

  • pre-commit フック — 誤ってコミットするのを防ぐ
  • CI/CD パイプライン — リポジトリをスキャンする
  • 定期スキャン — 既存のコードベースとログを対象にする

複数のツールの結果を突き合わせると漏れが減る。

そしてランブックを作って維持する。誰がどの秘密を管理し、 どうローテーションし、何に依存し、誰に連絡するか。

漏れたとき

順序が決まっている。失効 → ローテーション → 削除。

  1. 失効(Revoke) — 露出した資格情報を即座に無効化する。 失効済みかどうかを、システムが即座に判定できる状態にしておく
  2. ローテーション(Rotate) — 自動化された手順で回す。 一貫性が保たれ、人が読める形で露出することも防げる
  3. 削除(Delete) — ソース、ログ、キャッシュから消す。 git の履歴をどう扱うかは慎重に検討する

対応に必要なもの

インシデント対応チームが、その秘密のライフサイクルを追える状態になっていること。 誰がいつアクセスしたか、過去のローテーション履歴はどうか。 ログは1箇所に集約して、対応チームがアクセスできるようにしておく。

対応中は、アクセスのパターンを見る。 見慣れない IP、想定外のユーザーエージェント、通常の稼働時間外のタイムスタンプは、 アラートを出して侵害を前提に動く。

そのほかの実務ルール

バックアップとリストアの手順を定期的にテストする
非常用の break-glass 資格情報は別建てで用意する
秘密を平文で送信しない
秘密のライフサイクルのイベントすべてを監視してアラートを出す

関連