秘密情報の扱い — 鍵やパスワードを隠す

上級の解説は準備中のため、上級の内容を表示しています。

概要 — まず全体をつかむ

中級では「隔離の選択肢」(環境変数・シークレットマネージャ・KMS)まで見ました。上級では発想を一段進めます——そもそも長期の秘密を配らない。エンベロープ暗号化・動的シークレット・ワークロードIDで、「漏れても被害が小さい」設計に踏み込みます。

アニメーション『秘密情報の扱い(隔離)』を開く
NG:コードに直書きapp.js(ソースコード)const dbPass =  "P@ssw0rd-秘密";apiKey = "sk-live-9f8a...";🔑そのまま残るリポジトリ履歴に秘密が残る(消しても既に読まれた前提)ビルド成果物配布物に秘密が同梱(フロントなら全部読まれる)漏洩 → 悪用・課金・侵入被害が直接的OK:外に隔離して実行時に読み込むapp.js(ソースコード)const dbPass =  process.env.DB_PASS;参照だけ(中身は持たない)実行時に読み込む🔐 環境変数/シークレットマネージャコードの外・サーバ側だけに保管🔑 APIキー🔑 パスワード🔑 署名鍵↻ ローテーション(定期更新)定期的に、また漏れたら即、鍵を無効化して新しくする→ 漏れても被害を最小化リポジトリにもビルドにも秘密が残らないブラウザに配るコードは全部読まれる前提。秘密はサーバ側だけに置く

詳細 — 1段階ずつ追う

環境変数だけでは守り切れない

中級では「秘密は置き場所だけでなく経路でも漏れる」と押さえました。上級では、もっとも手軽な環境変数すら「隔離」としては弱いことを直視します。

  • プロセスから覗ける — 環境変数はプロセス一覧やメモリダンプ、/proc 経由で読まれうる。同じホストの別プロセスや、クラッシュダンプにそのまま載る
  • 子プロセスへ継承される — 起動した外部コマンドに丸ごと引き継がれ、意図せぬ範囲へ広がる
  • イメージや設定に焼き付く — コンテナイメージやCIの設定へ平文で埋め込まれやすい

つまり環境変数は「コードから分離する最低ライン」であって、上限ではありません。上級の目標は、実行時にだけ・必要な範囲にだけ・短命に秘密を渡すことです。

シークレットマネージャとVault

中級の「隔離の選択肢」を、運用の仕組みとして深掘りします。専用基盤に集約する狙いは、単なる保管ではなく 集中管理・アクセス制御・監査 です。

  • 一元管理Vault ※1 のような基盤に秘密を集め、誰がどの秘密をいつ読んだかを監査ログに残す
  • 実行時取得 — アプリは起動時や実行時にAPIで取得し、ディスクに書かない。設定ファイルに平文を置かない
  • リースとTTL — 貸し出しに期限を付け、「借りっぱなし」を防ぐ。失効すれば自動で無効になる

登場人物メモ(※の説明):

  • ※1 Vault — 秘密の保管・払い出し・監査・動的発行を担う専用基盤の代表格。アクセスは細かいポリシーで制御する

KMSとエンベロープ暗号化

大量のデータをすべてマスタ鍵で直接暗号化すると、マスタ鍵を使う回数が増え、外に晒す機会も増えます。そこで 二段構えにします。これがエンベロープ暗号化です。

  • DEK(データ鍵) ※1 でデータ本体を暗号化する(速い共通鍵暗号
  • その DEKを KEK(マスタ鍵) ※2 で暗号化し、暗号化済みDEKをデータのそばに保管する
  • 復号時だけ、暗号化済みDEKを KMS に渡して「DEKだけ復号して」と頼む。KEKはKMSの外へ一度も出ない

こうすると、保管場所ごと漏れても中身はDEKで守られ、そのDEKもKEKなしでは開けません。KMSとの往復は小さなDEKだけで済むので、大量データでも軽い、という利点もあります。

登場人物メモ(※の説明):

  • ※1 DEK(Data Encryption Key) — 実データを暗号化する使い捨ての鍵。暗号化された状態でデータのそばに置ける
  • ※2 KEK(Key Encryption Key/マスタ鍵) — DEKを暗号化する上位の鍵。KMSの内側に留め、決して平文で取り出さない
アニメーション『エンベロープ暗号化(鍵を鍵で包む)』を開く
エンベロープ暗号化 — 鍵を鍵で包む二段構え① 暗号化して保管するとき平文データ写真・DB など🔑 DEK で暗号化🔒 暗号化データこれは大きい🔑 DEKデータ鍵(小さい)KEK で暗号化🔐 KMSKEK(マスタ鍵)= 外に出さない🔒 暗号化済みDEKこれも小さい✉ 封筒に一緒に保管🔒 暗号化データ🔒 暗号化済みDEK② 読み出すとき(復号)封筒から取り出す🔒 暗号化済みDEK🔒 暗号化データこれ開いて🔐 KMSKEK で復号(KEKは外に出ない)🔑 DEK平文の鍵を得る🔓 復号DEK でデータを開く平文データ元に戻ったKEK は KMS の外へ一度も出ない・往復するのは小さな DEK だけ保管場所ごと漏れても中身は DEK で守られ、その DEK も KEK なしでは開けない

ローテーションと動的シークレット

漏れを前提にするなら、鍵の寿命を短くするのが最も効きます。

  • 自動ローテーション — 定期的な鍵の差し替えを人手に頼らず自動化する。手動だと必ず放置され、古い鍵が残り続ける
  • 動的シークレット — DBユーザやクラウドの認証情報を 都度発行し、TTLが切れたら自動で失効させる。渡した瞬間から時限式で消える
  • 短命クレデンシャル — 有効期間が数分〜数時間なら、漏れても悪用できる窓が極端に小さい

動的シークレットを活かすには、アプリ側も失効を前提に再取得・接続の張り直しができる設計が要ります。「一度取れば一生使える」前提のコードは、短命化と相性が悪いのです。

最小権限とワークロードID

長期キーを配らないための最終形が、実行主体そのものの身元で認証するワークロードID ※1 です。

  • 身元で借りる — クラウド上のインスタンスやサービスアカウントは、キーを持たずとも「自分が誰か」をプラットフォームに証明し、その場限りの権限を得る
  • CIは OIDC ※2 連携 — ビルドのたびにIDプロバイダが署名した短命トークンを提示し、クラウドが一時的な権限を発行する。長期キーをリポジトリにもシークレットストアにも置かない
  • 最小権限の徹底 — 発行する権限は用途ごとに絞る。1つの主体に広い権限を与えると、乗っ取られたときの被害が跳ね上がる

認証そのものの仕組みは 認証 に、権限の絞り方の発想は同ユニット群に繋がります。

登場人物メモ(※の説明):

  • ※1 ワークロードID — 人ではなく実行中のプログラム(ワークロード)に与える身元。長期キーの代わりに使う
  • ※2 OIDC(OpenID Connect) — 「この主体は本物」と署名付きで証明する仕組み。CIとクラウドの間で長期キーを介さない橋渡しに使う

IaCとCIでの秘密の扱い

自動化が進むほど、秘密はコードとパイプラインの中を通り抜けるようになります。ここでの原則は「実体を通さず、参照だけを通す」です。

  • IaCには参照だけ書くIaC のコードに平文の秘密を書かず、マネージャ上のパスや識別子だけを記述し、実体は実行時に解決する
  • stateファイルに注意 — IaCの状態ファイルには適用済みの値が残りやすい。保存先を暗号化し、アクセスを絞る
  • CIは出力を封じるCI/CD ではシークレットをマスクし、ビルドログへ出さない。外部連携はOIDCの短命トークンで行う

⚠️ 上級で効く落とし穴

  • TTLとライフサイクルの不整合 — 動的シークレットの有効期限より処理が長引き、途中で突然失効する。再取得の実装が要る
  • KMS依存が単一障害点 — 復号のたびにKMSへ往復するため、KMSの停止や遅延、コストが効いてくる。適切なキャッシュとフォールバックを設計する
  • 監査ログに秘密が漏れる — 秘密を守るはずのログに、値そのものを書いてしまう本末転倒
  • デバッグ時のダンプ — 「一度も外に出さない」建前が、障害調査のメモリダンプや詳細ログで一気に崩れる

理解度チェック

そのまま解けます(成績は保存されません)。無料アカウントを作ると、学習の記録と進捗の山登りが始まります。

1. CIからクラウドへアクセスするとき 長期のアクセスキーを配らずに済ませる定番はどれ?

2. エンベロープ暗号化(envelope encryption)の仕組みとして正しいのは?

3. 環境変数に秘密を置くことの弱点として正しいのは?

4. シークレットマネージャやVaultに秘密を集約する主眼はどれ?

5. 「漏れても被害を小さくする」ために最も効くのはどれ?

6. エンベロープ暗号化でKMSに依存する運用の注意点として正しいのは?

7. エンベロープ暗号化で 実データを直接暗号化する使い捨ての鍵を英字3文字の略語で答えてください。

8. 動的シークレットで貸し出しに付ける「有効期限」を表す英字3文字の略語は?