TT Lab
はじめる
学ぶ 学習パス コース

KCSA — Kubernetesセキュリティアソシエイト

シークレット — 隠すより破棄が速いほうがよい

TT Labで続きを見る

一言でいうと

シークレット管理の成熟度は、「どれだけうまく隠したか」ではなく、「漏えいしたと仮定したとき、取り消して交換するのに 何分かかるか」で測られます。この観点1つが、優先順位のすべてを変えます。

なぜ必要なのか

標準的なアドバイスはこうです。「コードにハードコードせず環境変数で渡し、.envは.gitignoreに入れてください。」 このアドバイスが防げる脅威は、たった1つです。ソースリポジトリに平文で入ってしまうことです。

実際の漏えい経路はもっとたくさんあります。プロセスのメモリ、クラッシュレポート、CIのログ、イメージのレイヤー、 APMのダッシュボード、誤って公開されたデバッグ用エンドポイント。環境変数に移すだけでは、これらのどれも防げません。

どう動くのか

環境変数は保管場所ではなく受け渡しの方式である

.envファイルを読み込んだあとに削除しても意味がありません。値はすでにカーネルがプロセスごとに保持しており、 Linuxではそれをファイルのように読めます。

tr '\0' '\n' < /proc/2841/environ

同じUIDかrootなら、そのまま読めます。コンテナの中でも変わりません。 同じPodのサイドカー、ノードにアクセスできる人、kubectl debug --target=appで接続したデバッグコンテナが すべて同じものを見ます。

環境変数が漏れるほかの経路も、整理しておくとよいでしょう。

KubernetesのSecretの実際の置き場所

保存方式を選ぶ3つの基準

「暗号化されるか」は、よい基準ではありません。代わりに、次の3つを問いましょう。

  1. 露出する経路がいくつあるか
  2. 取り消しと交換に何分かかるか
  3. 誰がいつ読んだかがわかるか

この基準で見ると、保存方式の順序は「暗号化の強さ」の順ではなく、「事故のときの対応時間が短くなる」順 に並びます。

最善は、静的なキーを作らないこと

ローテーションは運用手順ではなく、設計上の属性である

最も重要な文です。コードがキーを1つしか想定していなければ、どれだけ優れたシークレットマネージャーを使っても、実際の交換は 起きません。

Webhookの検証がSECRET1つしか見ないなら、キーを変えた瞬間に、古いキーで署名されたリクエストがすべて拒否されます。 送信側と受信側を原子的に同時に変える方法がないため、事実上交換が不可能になり、 そのため誰もローテーションをしなくなります。

解決策は、署名と検証の分離です。署名は現在のキー1つで行い、検証は有効なキーの集合全体に 対して試します。環境変数の名前が単数から複数に変わること(WEBHOOK_SECRET → WEBHOOK_SECRETS)が、 この設計の目印です。JWTなら、kidヘッダー + JWKSが同じ役割を果たします。 発行者がJWKSに新しいキーを先に公開し、検証者が取得したあとに、署名キーを切り替えます。

そして観測です。どのキーで検証が成功したかをkey_indexのようなタグでメトリクスに残せば、 「古いキーで署名されたリクエストが本当になくなったか」を、推測ではなくグラフで確認して、安全に古いキーを削除できます。

検知よりも対応時間が先

コミット前フックはローカルの設定なので、git commit --no-verifyを1回実行すれば回避され、新しく参加した人は フックをインストールしないまま数日を過ごします。実際の強制力は、サーバー側のプッシュ保護から生まれます。

そして、検知に投資する前に問うべき質問があります。 「このシークレットが露出したと仮定したとき、取り消しと交換に何分かかるか。」 この数字が大きければ、検知をどれだけ細かくしても、事故のときの損失は減りません。

現場での姿

著者がまとめた事故対応の順序が、この観点の決定版です。シークレットがすでにコミットされてしまった状況で、 最もよくある反応は履歴の書き換えですが、順序が間違っています。

公開リポジトリにプッシュされた認証情報は、数秒から数分のうちに自動化されたスキャナーに収集されます。 そして、履歴を消しても残るものがあります。フォークされたリポジトリ、すでにクローンした開発者たちのローカルのコピー、 プラットフォームが保管するPR参照(コミットハッシュを知っていれば、いまだにアクセスできる場合が多いのです)、 検索エンジンやコード検索サービスのキャッシュ、CIのキャッシュとアーティファクト。 さらに、整理したあとで誰かが既存のクローンからそのままプッシュすると、消したコミットが復活します。

そのため順序は、取り消し → 影響の調査 → 履歴の整理です。 AWSのキーなら、新しいキーの作成 → デプロイ → 古いキーをInactiveに → 削除の順で無停止で交換し、 CloudTrailでそのキーがどこで使われたかを調査します。 見慣れないIP、普段使っていないリージョン、予想外のAPI呼び出しが、侵害を判断するシグナルです。 「履歴の書き換えは、漏えいを元に戻す措置ではなく、再発を減らす衛生作業です。」

External Secrets Operatorのようなツールを使っても、クラスターの衛生管理が免除されるわけではないという指摘も重要です。 ExternalSecretのマニフェストには値がないのでGitにコミットしてもかまいませんが、 Operatorが最終的に値をクラスターのSecretとして実体化するため、RBACと保存時の暗号化の問題は そのまま残ります。

次のラボですること

次のラボでは、PSAラベルを自分で付けて、restrictedに違反するPodが拒否されることを確認します。 シークレットそのものはラボよりもクイズで扱いますが、前のモジュールのラボで作成したEncryptionConfigurationが、 まさにここで述べた「etcdの平文保存」問題の解決策であることを、あらためて確認しておいてください。