シークレットローテーション

API キーやデータベースパスワードなどの秘密情報を定期的に自動更新するセキュリティプラクティス

セキュリティ運用

シークレットローテーションとは

シークレットローテーション (Secret Rotation) は、API キー、データベースパスワード、暗号鍵などの秘密情報を定期的に自動更新するセキュリティプラクティスである。秘密情報が漏洩した場合の影響を時間的に限定し、長期間同じ認証情報が使われるリスクを軽減する。

なぜローテーションが必要か

  • 漏洩した認証情報の有効期間を限定する (30 日でローテーションすれば、漏洩の影響は最大 30 日)
  • 適用される基準や社内規程が認証情報の定期更新を求めている場合、自動ローテーションの実行履歴がそのまま証跡になる (要求される頻度や代替策が認められるかは基準ごとに違うので、原文で確認する)
  • 退職者がアクセスに使っていた認証情報を無効化する

Secrets Manager のローテーションには 2 つの形態がある。一般のシークレットは、Secrets Manager がローテーション関数 (Lambda) を呼び出して更新する。一方 Amazon RDS や AuroraRedshift、DocumentDB のマスターユーザー認証情報は、各サービス側が設定と実行を受け持つマネージドローテーションが使えるため、Lambda 関数を自分で用意しなくてよい。ただしマネージドローテーションの対象はマスターユーザーであって、アプリケーションが日常的に使う権限を絞ったユーザーの認証情報は対象外なので、そちらはローテーション関数を設定する。

ローテーションの 4 ステップ

ローテーションは、Secrets Manager がローテーション関数を 4 回呼び出す形で進む。各段階でシークレットのバージョンに付くステージングラベルが移動していく。

1. createSecret:  新しいパスワードを生成し、AWSPENDING ラベルで保存
2. setSecret:     DB のパスワードを新しいものに変更
3. testSecret:    新しいパスワードで DB に接続できることを確認
4. finishSecret:  AWSPENDING → AWSCURRENT に昇格、古いパスワードを AWSPREVIOUS に

ここで誤解しやすいのは、ステージングラベルがシークレットのどのバージョンを指すかという目印であって、データベース側で古いパスワードを生かし続ける仕組みではない点である。AWSPREVIOUS は直前の正常なバージョンを取り出せるようにするためのラベルにすぎない。単一ユーザー方式では setSecret の時点でデータベースのパスワードが切り替わるので、古いパスワードを握ったままのクライアントが張り直す接続は認証に失敗し得る。確立済みの接続は接続時に認証を済ませているため途中で切れることはないが、ローテーション直後に新しい接続を張る経路には、認証エラー時にシークレットを取り直して再試行する処理を入れておく。

切り替えの隙を避けたい場合は、2 つのユーザーを交互に更新する方式 (alternating users) を選ぶ。初回のローテーションで元のユーザーを複製し、以降はどちらか一方のパスワードだけを更新するため、新しい認証情報を検証している間はもう一方のユーザーの認証情報が有効なまま残る。これが可用性の高い選択肢とされている理由である。

Lambda でのシークレット取得

呼び出しごとに Secrets Manager の API を叩くと遅延と API 料金が積み上がるため、実行環境が再利用される性質を活かしてモジュールスコープにキャッシュを置くのが定石である。

import { GetSecretValueCommand, SecretsManagerClient } from '@aws-sdk/client-secrets-manager';

const sm = new SecretsManagerClient({});
let cachedSecret: string | null = null;

async function getDbPassword(): Promise<string> {
  if (cachedSecret) return cachedSecret;
  const result = await sm.send(new GetSecretValueCommand({ SecretId: 'myapp/db-password' }));
  cachedSecret = JSON.parse(result.SecretString!).password;
  return cachedSecret!;
}

注意: このキャッシュが残るのはコールドスタートの間ではなく、逆に同じ実行環境が再利用される (ウォームスタートの) 間である。実行環境は一定時間使われ続けることがあるため、ローテーション後も古いパスワードを掴んだままになり得る。TTL 付きキャッシュにするか、認証エラーを検知したらキャッシュを捨てて取り直す経路を用意する。

ローテーション対象と頻度

頻度は対象の性質で決まる。人手を介さず更新できるものは短く、配布先が多くて切り替えに調整がいるものは長めに置く、というのが実際の落としどころである。

対象推奨頻度方法
DB パスワード30〜90 日Secrets Manager 自動ローテーション
API キー90 日Secrets Manager + カスタム Lambda
JWT 署名鍵90 日JWKS エンドポイントで公開鍵を配布
TLS 証明書自動 (ACM)ACM が自動更新

実践的な知識は関連書籍でも得られる。

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

関連用語

関連する記事