シークレット管理

パスワード、API キー、証明書などの機密情報を安全に保存 / 配布 / ローテーションする手法

セキュリティ運用

シークレット管理とは

シークレット管理は、パスワード、API キー、DB 接続情報、TLS 証明書などの機密情報を安全に保存・配布・ローテーションする手法である。「安全に」の中身は 4 つに分解できる。保存時に暗号化されていること、値を読める主体が権限で絞られていること、値を交換 (ローテーション) できること、誰がいつ取得したかが監査ログに残ることである。この 4 つのうちどれが欠けているかで、シークレットの置き場所の優劣が決まる。

暗号化だけを見て安心しないこと。実際の事故の大半は暗号アルゴリズムが破られて起きるのではなく、値が平文で読める場所 (リポジトリ、ログ、チャット、スクリーンショット) にコピーされて起きる。だからシークレット管理の設計は「暗号を強くする」よりも「値が転写される経路を減らす」ことが本題になる。AWS なら Secrets ManagerKMS が担当する領域である。

ハードコードが致命的になる理由

まず典型的な失敗の形を並べる。

// ❌ コードに直接埋め込む (履歴に永久に残る)
const API_KEY = 'sk-abc123def456';

// ❌ .env を Git にコミット (.gitignore は追跡開始後のファイルには効かない)
// .env
DATABASE_PASSWORD=secret123

// ❌ IaC テンプレートに値を書く (リポジトリと変更履歴の両方に転写される)
// ✅ シークレットストアの参照 (名前や ARN) だけを書き、値は実行時に取得する

ハードコードが他のミスと決定的に違うのは、取り消しが効かない点にある。Git のコミットは内容から一意な ID が決まる不変オブジェクトなので、後のコミットで行を消しても過去のコミットはそのまま残る。さらに悪いことに、履歴を書き換えて強制プッシュしても、値は次の場所に生き続ける。他の開発者の手元のクローン、フォークされたリポジトリ、削除したはずのコミットを ID で直接指したときのキャッシュされた表示、そのコミットを参照しているプルリクエストである。GitHub は公式ドキュメントで、履歴書き換えの副作用を管理する前に「まずそのシークレットを失効またはローテーションせよ」と順序を明示しており、失効させれば履歴書き換え自体が不要になる場合も多いとしている。

ここから実務上の結論が出る。コミットしてしまったシークレットは「消す」対象ではなく漏洩したものとして扱い、無効化して作り直す対象である。この判断を数分で下せるかどうかが被害の大きさを決めるので、ローテーションの手順を平時に用意しておくこと自体が対策になる。

保存場所の選び方

置き場所を比べるときは「暗号化されているか」ではなく、先の 4 要素のうち何が備わっているかで見る。

置き場所保存時の暗号化自動ローテーション取得の監査向く用途
Secrets Managerあり (KMS)ありありDB 認証情報、API キー
SSM Parameter Store (SecureString)あり (KMS)なし (自分で仕組みを作る)あり交換頻度の低い機密設定値
環境変数に値を直接設定サービス次第なし (再デプロイが必要)実質なし機密でない設定値

Parameter Store の SecureString も KMS で暗号化されるので、暗号の強さで劣るわけではない。差が出るのはローテーションを仕組みとして持っているか、クロスアカウントで共有できるか、といった運用機能の側である。料金体系と使い分けの詳細は Secrets Manager 側で扱う。

環境変数の限界

「環境変数に入れたから安全」という理解は誤りだが、その理由も誤解されやすい。例えば Lambda の環境変数は保存時に KMS で暗号化されている。それでも AWS 自身が、DB 認証情報や API キーには環境変数ではなく Secrets Manager を使うよう推奨している。理由は暗号の弱さではなく、次の性質にある。

  • 設定を読める権限があれば値が見える: 関数設定の取得権限を持つ利用者やロールは、復号済みの値をそのまま読める。暗号化は保存媒体を守るだけで、権限設計の代わりにはならない。
  • 子プロセスへ継承される: 環境変数はプロセスの属性なので、そこから起動した別のコマンドにもそのまま渡る。同じホストで同一ユーザー権限を取られた場合、稼働中プロセスの環境から値を読み出せる。
  • 意図せず出力に混ざる: 例外時のスタックトレース、デバッグ用の環境ダンプ、CI のログ、クラッシュレポートに載る。マスク処理は「マスクすべき名前」を知っている値にしか効かない。
  • 交換にデプロイが必要: 値を変えるには設定変更と再デプロイが要る。この重さが「面倒だからローテーションしない」を生み、結果として漏洩の窓が開いたままになる。

したがって実務では、環境変数にはシークレットのではなくシークレットの名前や識別子を置き、値は起動時にシークレットストアから取得してメモリ上に保持する形にする。こうすると値の交換がデプロイから切り離せる。

ローテーションの意義と落とし穴

ローテーションの目的は「漏れないようにすること」ではない。漏れたことに気づけないケースがある前提で、有効な期間を時間で区切って被害を有限にすることである。90 日ごとに交換していれば、いつ漏れたか分からない認証情報でも悪用できる期間は最大 90 日に収まる。逆に一度も交換していない認証情報は、過去に関わった全員と全ての履歴が現在の攻撃面になる。

流れは次のようになる。

1. 新しいパスワードを生成する
2. データベース側に新パスワードを登録する (この時点で旧パスワードも有効)
3. 保管しているシークレットの値を新パスワードに切り替える
4. 稼働中のアプリケーションが取得し直して新パスワードを使い始める
5. 旧パスワードを無効化する

見落としやすいのは 2 と 5 の間である。新旧どちらでも認証できる期間を作らずに切り替えると、まだ旧パスワードを握っているプロセスの接続が一斉に失敗する。自動ローテーションが障害の原因として嫌われるのはたいていこの設計漏れが理由で、ローテーションそのものが危険なわけではない。

もう一点、アプリケーション側が起動時に一度だけ取得して保持し続ける実装だと、値を切り替えても古いまま動き続ける。取得結果をキャッシュする場合は有効期限を設け、認証エラーを受けたら取得し直す経路を用意しておく。

コミット前に止める仕組み

事後の履歴書き換えが割に合わないので、防御は入口に寄せる。

# git-secrets: フックを入れてコミット時に検出させる
git secrets --install
git secrets --register-aws   # AWS のアクセスキー等のパターンを登録

# .gitignore
.env
.env.local
*.pem

二つ注意点がある。まず .gitignoreまだ追跡されていないファイルにしか効かない。既にコミット済みのファイルを後から書き足しても無視されないので、git rm --cached で追跡から外す操作が別途必要になる。次に、この種の検出は既知のパターンとの照合なので、独自形式のトークンや自前の認証情報は素通りする。手元のフックは回避もできるため、リポジトリ側のスキャンとプッシュ時の遮断を併用し、検出をすり抜ける前提で運用する。

漏洩したときの順番

順番そのものが対策の質を決める。調査を先にやると、調査している間ずっと有効な認証情報が外にある状態が続く。

1. 無効化する (使えなくすることが最優先・調査より先)
2. 新しい値を発行して切り替える
3. アクセスログを確認する (AWS なら CloudTrail 等)
4. その認証情報で何ができたか、実際に何をされたかを分ける
5. 転写された場所をすべて洗う (履歴・ログ・チャット・課題管理・スクリーンショット)
6. 再発防止を入口の仕組みに落とす

5 が抜けやすい。値は 1 か所に留まらず、貼り付けられた場所すべてに複製されている。そして履歴書き換えを選ぶ場合も、他人のクローンやフォークからは消せないという制約は変わらないので、あくまで 1 の補助手段にすぎない。

Kubernetes での注意点

Kubernetes の Secret に格納される値は Base64 で符号化されるだけで、暗号化ではない。公式ドキュメントも、Secret は既定では API サーバーの背後のデータストア (etcd) に暗号化されずに保存されると明記している。つまり API アクセス権や etcd への到達手段があれば読める。

さらに見落としやすい経路がある。あるネームスペースで Pod を作成できる権限を持つ利用者は、その Pod に Secret をマウントさせることで、同じネームスペースの任意の Secret を読み取れる。Deployment を作れる権限も間接的に同じ力を持つ。したがって Secret の直接参照だけを絞っても防御にならない。

対処は 3 段構えになる。保存時暗号化を有効にする、Secret への権限を最小化して Pod 作成権限も同じ目線で見直す、そして値の保管自体を外部のシークレットストアへ寄せる。AWS 環境なら Secrets Store CSI Driver 経由で Secrets Manager の値を参照する構成が使える。

さらに掘り下げるなら関連書籍が参考になる。

この記事は役に立ちましたか?

関連用語

関連する記事