KMS + Secrets Manager ハンズオン

機密情報を安全に扱う ― 暗号化キー管理・シークレット保管・自動ローテーション・アプリからの参照

AWS KMS Secrets Manager 暗号化 ローテーション CloudTrail マネコン操作 所要時間 60〜75 分 v1.0

📋 概要

パスワードや API キーをコードに直接書くのは重大なセキュリティリスクです。このハンズオンでは、AWS KMS で暗号化キーを管理し、Secrets Manager でシークレットを安全に保管・自動ローテーションし、アプリケーションから安全に参照する流れを実践します。

項目内容
対象サービスAWS KMS、AWS Secrets Manager、S3、CloudTrail、Lambda
主な学習内容カスタマーキー / キーポリシー / SSE-KMS / シークレット保管 / 自動ローテーション / アプリ参照
所要時間60〜75 分
難易度★★★☆☆(中級者向け)
前提知識IAM の基礎・暗号化の概念・JSON の読み書き
費用目安約 1 USD(KMS キー 1 USD/月 + シークレット 0.40 USD/月。日割りで少額)
ℹ️ KMS と Secrets Manager の役割分担
サービス役割
KMS暗号化キーそのものを管理。他サービスのデータを暗号化する「鍵」
Secrets Managerパスワード等の「値」を KMS で暗号化して保管・ローテーション

🏗️ アーキテクチャ

🔑 KMS カスタマーキー handson-key
キーポリシーでアクセス制御
↓ 暗号化に使用
🗝️ Secrets Manager handson/db-credentials
DB のユーザー名・パスワードを KMS で暗号化保管
↕ 自動ローテーション(Lambda)
🔄 ローテーション Lambda
定期的にパスワードを自動更新
↓ get_secret_value(IAM 権限)
🧑‍💻 アプリ / CloudShell(boto3)
実行時に最新のシークレットを取得

すべての操作は CloudTrail に記録される

KMS の Decrypt や Secrets Manager の GetSecretValue はすべて CloudTrail に記録され、「いつ・誰が・どの鍵で復号したか」を監査できます。

✅ 前提条件

🔑 ステップ 1 ― KMS カスタマーキーの作成

1-1. キーを作成する

「KMS(Key Management Service)」→「キーの作成」 をクリックします。

設定項目設定値
キーのタイプ対称(Symmetric)
キーの使用法暗号化および復号
エイリアスhandson-key
1-2. キー管理者・使用者を設定

「キー管理者」に自分の IAM ユーザー / ロールを、「このキーを使用できる AWS アカウントとユーザー」に利用するロールを指定します。これが キーポリシー として保存されます。

ℹ️ キーポリシーが最優先

KMS では、IAM ポリシーだけでなく キーポリシー でも明示的に許可されている必要があります。キーポリシーに記載のないプリンシパルは、IAM で許可されていても使えません。

1-3. キーローテーションを有効化

作成後、キーの詳細「キーのローテーション」タブで 「自動キーローテーション」 を有効にします(年 1 回、AWS が自動でキーマテリアルを更新。アプリ側の変更は不要)。

✅ 確認ポイント

カスタマー管理型キー一覧に handson-key が「有効」で表示され、キー ARN が確認できれば成功です。

🔒 ステップ 2 ― S3 を KMS で暗号化(SSE-KMS)

2-1. バケットのデフォルト暗号化を設定

S3 バケット handson-kms-xxxx を作成し、「プロパティ」→「デフォルトの暗号化」→「編集」で以下を設定します。

暗号化タイプAWS Key Management Service キー(SSE-KMS)
AWS KMS キーhandson-key を選択
バケットキー有効(KMS リクエスト削減)
2-2. アップロードして暗号化を確認
echo "encrypt me with KMS" > kms-test.txt aws s3 cp kms-test.txt s3://handson-kms-xxxx/kms-test.txt # オブジェクトの暗号化方式を確認 aws s3api head-object --bucket handson-kms-xxxx --key kms-test.txt

レスポンスに "ServerSideEncryption": "aws:kms" と KMS キー ARN が表示されれば、KMS で暗号化されています。

2-3. CloudTrail で Decrypt を確認

オブジェクトをダウンロードすると、KMS の Decrypt API が呼ばれます。「CloudTrail」→「イベント履歴」 でイベント名 Decrypt を検索すると、誰がいつ復号したかが記録されています。

✅ 確認ポイント

オブジェクトが aws:kms で暗号化され、ダウンロード時に CloudTrail に Decrypt が記録されれば成功です。キーへのアクセス権がないユーザーはダウンロードできません。

🗝️ ステップ 3 ― Secrets Manager でシークレット管理

3-1. シークレットを作成

「Secrets Manager」→「新しいシークレットを保存する」 をクリックします。

シークレットのタイプその他のシークレット(または RDS の認証情報)

キー / 値のペアで以下を入力します。

{
  "username": "appuser",
  "password": "InitialP@ssw0rd!",
  "host": "handson-rds.xxxx.ap-northeast-1.rds.amazonaws.com",
  "dbname": "handson_db"
}
暗号化キーhandson-key(または aws/secretsmanager)
シークレット名handson/db-credentials

「次へ」を進めて保存します(ローテーションは次のステップで設定するため、まずは無効)。

3-2. CLI で取得テスト
aws secretsmanager get-secret-value \ --secret-id handson/db-credentials \ --query SecretString --output text

保存した JSON が復号されて返ってくれば成功です(裏で KMS による復号が行われています)。

✅ 確認ポイント

Secrets Manager の一覧に handson/db-credentials が表示され、CLI で値を取得できれば成功です。値はコンソール上でも「シークレットの値を取得する」を押すまでマスクされています。

🔄 ステップ 4 ― 自動ローテーションの設定

4-1. ローテーションを有効化

handson/db-credentials を開き、「ローテーション」タブ →「ローテーションを編集」をクリックします。

自動ローテーション有効
スケジュール30 日ごと
ローテーション関数新しい Lambda 関数を作成(テンプレート使用)

RDS の認証情報タイプなら、AWS 提供のローテーションテンプレート Lambda が自動作成されます。その他のシークレットの場合は雛形 Lambda が作られます。

4-2. 即時ローテーションをテスト

「ローテーションを今すぐ実行」をクリックします。ローテーション Lambda が新しいパスワードを生成し、シークレットの新バージョン(AWSCURRENT)として保存します。

# ローテーション後に値が変わっていることを確認 aws secretsmanager get-secret-value \ --secret-id handson/db-credentials \ --query SecretString --output text
ℹ️ ローテーションの 4 ステップ(createSecret → setSecret → testSecret → finishSecret)

ローテーション Lambda は、新パスワード生成 → DB に反映 → 接続テスト → ラベル切替(AWSPENDING→AWSCURRENT)という 4 段階で安全に更新します。アプリは常に AWSCURRENT を取得するだけでよく、切替を意識する必要がありません。

✅ 確認ポイント

ローテーション実行後にパスワードが変化し、「バージョン」に新しい AWSCURRENT が記録されていれば成功です。

🧑‍💻 ステップ 5 ― アプリケーションから参照する

コードにパスワードを書かず、実行時に Secrets Manager から取得するパターンを実装します。

5-1. boto3 で取得するサンプル

CloudShell で以下の Python を実行します。

import boto3, json

session = boto3.session.Session()
client = session.client("secretsmanager", region_name="ap-northeast-1")

resp = client.get_secret_value(SecretId="handson/db-credentials")
secret = json.loads(resp["SecretString"])

print("user:", secret["username"])
print("host:", secret["host"])
# このあと secret["password"] で DB 接続する(パスワードはコードに書かない)
5-2. アプリ用 IAM ロールに最小権限を付与

EC2 / Lambda / ECS のロールに、特定シークレットだけ読める権限を付けます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "secretsmanager:GetSecretValue",
      "Resource": "arn:aws:secretsmanager:ap-northeast-1:<AccountId>:secret:handson/db-credentials-*"
    },
    {
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "<handson-key の ARN>"
    }
  ]
}

Secrets Manager だけでなく、暗号化に使った KMS キーの kms:Decrypt も必要な点に注意します。

✅ 確認ポイント

boto3 でシークレットを取得でき、ローテーション後も常に最新のパスワードが返ることを確認できれば、ハードコーディングを排除した安全な構成が完成です。

🧹 クリーンアップ

⚠️ 課金防止のためクリーンアップを実施

KMS キーは 1 USD/月、シークレットは 0.40 USD/月の課金があります。使い終わったら削除してください。

削除手順

  1. ローテーション Lambda を削除
    Lambda → 自動作成された SecretsManager... 関数を削除
  2. シークレットを削除(スケジュール削除)
    Secrets Manager → handson/db-credentials → 「アクション」→「シークレットを削除」(待機期間 7〜30 日。最短は CLI で --force-delete-without-recovery
  3. S3 オブジェクト・バケットを削除
    handson-kms-xxxx を空にして削除
  4. KMS キーを削除予約
    KMS → handson-key → 「キーの削除をスケジュール」(最短 7 日の待機期間。即削除は不可)
ℹ️ KMS キーは即削除できない

KMS キーは誤削除によるデータ復号不能を防ぐため、最短 7 日の待機期間後に削除されます。それまでは「削除保留中」で課金は停止します。

学習のまとめ

習得したスキル実践内容
KMS キー管理カスタマーキー作成・キーポリシー・自動ローテーション
SSE-KMS 暗号化S3 を KMS で暗号化・CloudTrail で Decrypt 監査
シークレット保管Secrets Manager で認証情報を暗号化保管
自動ローテーションLambda による定期パスワード更新・4 ステップの仕組み
アプリ参照boto3 で実行時取得・最小権限 IAM(SecretsManager + KMS)