AWS KMS完全ガイド:S3暗号化にAWS管理キーとCMKのどちらを選ぶべきか

S3バケットの暗号化設定を検討していると、必ずぶつかるのが「AWS管理キーで十分か、それともCustomer Managed Key(CMK)が必要か」という判断だ。コスト、制御レベル、監査要件——どれを優先するかによって答えが変わる。この記事では、AWS KMSの仕組みを実際の運用視点で整理し、S3暗号化における選択基準とコスト計算の考え方を具体的に解説する。

TL;DR:AWS管理キー vs Customer Managed Key(CMK)

比較項目 AWS管理キー(aws/s3) Customer Managed Key(CMK)
キーポリシーの制御 不可(AWSが管理) 可能(完全制御)
キーローテーション 1年(約365日)自動・変更不可 有効化すると1年ごとに自動(設定可能)
クロスアカウントアクセス 不可 可能(キーポリシーで制御)
キーの無効化・削除 不可 可能(削除は7〜30日の待機期間あり)
CloudTrail監査 KMS API呼び出しはログに記録される KMS API呼び出しはログに記録される
KMSキー料金 無料 月額料金あり(最新料金はAWS公式参照)
APIリクエスト料金 発生する 発生する
主なユースケース シンプルな暗号化、コスト優先 コンプライアンス、クロスアカウント、アクセス制御

AWS KMSの仕組み:S3暗号化のデータフロー

KMSを理解する上で最も重要な概念は、KMSが直接データを暗号化するわけではないという点だ。KMSはデータキー(Data Key)を生成・管理し、実際のデータ暗号化はS3側がそのデータキーを使って行うエンベロープ暗号化(Envelope Encryption)を採用している。

sequenceDiagram participant App as アプリケーション participant S3 as Amazon S3 participant KMS as AWS KMS App->>S3: PutObject(オブジェクト) S3->>KMS: GenerateDataKey(KMSキーID) KMS-->>S3: プレーンテキストキー + 暗号化済みキー S3->>S3: オブジェクトをデータキーで暗号化 S3->>S3: プレーンテキストキーを破棄 S3->>S3: 暗号化済みキーをメタデータに保存 S3-->>App: 保存完了 App->>S3: GetObject S3->>KMS: Decrypt(暗号化済みデータキー) KMS-->>S3: プレーンテキストデータキー S3->>S3: オブジェクトを復号 S3-->>App: プレーンテキストオブジェクト
  1. PUT操作時:S3はKMSに対してGenerateDataKeyリクエストを送る。KMSはプレーンテキストのデータキーと、KMSキーで暗号化されたデータキー(暗号化済みデータキー)の2つを返す。
  2. 暗号化処理:S3はプレーンテキストのデータキーでオブジェクトを暗号化し、プレーンテキストキーをメモリから削除する。暗号化済みデータキーはオブジェクトのメタデータとして保存される。
  3. GET操作時:S3はオブジェクトメタデータから暗号化済みデータキーを取り出し、KMSにDecryptリクエストを送る。KMSがプレーンテキストキーを返し、S3がオブジェクトを復号する。
  4. KMSキーの役割:データキーを暗号化・復号するための「マスターキー」として機能する。オブジェクト本体はKMSに送られない。
金庫の鍵(データキー)を保管する金庫(KMSキー)をイメージするとわかりやすい。実際の荷物(データ)は金庫の鍵で施錠され、その鍵自体はKMSが管理する別の金庫に入っている。

AWS KMSキーの種類と選択基準

KMSには複数のキータイプが存在する。S3暗号化のコンテキストで実際に選択肢となるのは以下の3つだ。

graph TD A["S3暗号化方式の選択"] --> B["SSE-S3
S3管理キー"] A --> C["SSE-KMS"] A --> D["SSE-C
顧客提供キー"] C --> E["AWS管理キー
aws/s3"] C --> F["Customer Managed Key
CMK"] E --> G["キーポリシー変更不可
ローテーション1年固定"] F --> H["キーポリシー完全制御
クロスアカウント対応"]

SSE-S3(S3管理キー)

厳密にはKMSを使わない。S3が独自に管理するキーでAES-256暗号化を行う。KMSのAPIコールが発生しないため、KMS料金は一切かからない。キーポリシーの制御やCloudTrailでのKMSレベルの監査は不要で、とにかくシンプルに暗号化したい場合の選択肢だ。ただし、誰がいつオブジェクトにアクセスしたかをKMSレベルで追跡することはできない。

SSE-KMS with AWS管理キー(aws/s3)

AWSがアカウントごとに自動作成するキーで、追加料金なしで使える。キーポリシーの変更やクロスアカウントアクセスの付与はできないが、KMS APIコールはCloudTrailに記録されるため、S3オブジェクトへのアクセスをKMSレベルで監査できる。ローテーションは1年(約365日)ごとに自動で行われ、変更不可だ。

SSE-KMS with Customer Managed Key(CMK)

自分でKMSキーを作成・管理する。キーポリシーで細粒度のアクセス制御が可能で、クロスアカウントアクセス、特定IAMロールへのアクセス制限、キーの無効化による緊急アクセス遮断など、運用上の柔軟性が大幅に上がる。コンプライアンス要件でキーの所有権証明が必要な場合や、複数アカウントにまたがるアーキテクチャでは実質的にCMK一択になる。

S3バケットへのSSE-KMS設定:CLIによる実装

実際の設定手順を示す。まずCMKを作成し、S3バケットのデフォルト暗号化に適用する流れだ。

ステップ1:CMKの作成

aws kms create-key \
  --description "S3暗号化用CMK" \
  --key-usage ENCRYPT_DECRYPT \
  --origin AWS_KMS \
  --region us-east-1

出力されたKeyIdを控えておく。次にエイリアスを付与して管理しやすくする。

aws kms create-alias \
  --alias-name alias/s3-encryption-key \
  --target-key-id <KeyIdをここに入力> \
  --region us-east-1

ステップ2:キーローテーションの有効化

CMKを作成しただけではローテーションは無効だ。明示的に有効化する必要がある。

aws kms enable-key-rotation \
  --key-id alias/s3-encryption-key \
  --region us-east-1

ローテーション設定の確認:

aws kms get-key-rotation-status \
  --key-id alias/s3-encryption-key \
  --region us-east-1

ステップ3:S3バケットのデフォルト暗号化設定

aws s3api put-bucket-encryption \
  --bucket my-example-bucket \
  --server-side-encryption-configuration '{
    "Rules": [
      {
        "ApplyServerSideEncryptionByDefault": {
          "SSEAlgorithm": "aws:kms",
          "KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:alias/s3-encryption-key"
        },
        "BucketKeyEnabled": true
      }
    ]
  }'

BucketKeyEnabled: trueは必ず設定すること。これを有効にすると、S3はバケットレベルのキーを使ってKMS APIコール数を大幅に削減する。オブジェクトごとにKMSを呼び出す代わりに、バケットキーを介してローカルで暗号化処理が行われるため、KMSリクエスト料金が劇的に下がる。大量のオブジェクトを扱うバケットでこれを設定し忘れると、KMS料金が予想外に膨らむ。

ステップ4:設定の確認

aws s3api get-bucket-encryption \
  --bucket my-example-bucket

CMKに必要なIAMポリシー設定

CMKを使ってS3にオブジェクトをPUT/GETするIAMロールには、KMSへのアクセス権限が必要だ。S3バケットポリシーだけでは不十分で、KMSキーポリシーとIAMポリシーの両方が正しく設定されていないとアクセスが拒否される。

🔽 IAMポリシー例(クリックして展開)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3KMSOperations",
      "Effect": "Allow",
      "Action": [
        "kms:GenerateDataKey",
        "kms:Decrypt"
      ],
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/<key-id>"
    }
  ]
}

S3へのPUT操作にはkms:GenerateDataKey、GET操作にはkms:Decryptが必要だ。kms:DescribeKeyはキーのメタデータ取得に使われるが、暗号化・復号操作そのものには必須ではない。最小権限の原則に従い、必要なアクションのみを付与すること。

graph LR IAMRole["IAMロール"] -->|kms:GenerateDataKey| KMS["AWS KMS"] IAMRole -->|kms:Decrypt| KMS KMS -->|データキー発行| S3["Amazon S3"] S3 -->|暗号化オブジェクト保存| Bucket["S3バケット"] KeyPolicy["KMSキーポリシー"] -.->|アクセス制御| KMS IAMPolicy["IAMポリシー"] -.->|アクセス制御| IAMRole

KMSのコスト構造:見落としがちなAPIリクエスト料金

KMSのコストで最も誤解されやすいのは、キー自体の料金よりAPIリクエスト料金の方が実際の請求に大きく影響するケースがあるという点だ。料金は変動するため必ずAWS公式ドキュメントで最新情報を確認してほしいが、コスト構造の考え方は以下の通りだ。

コスト項目 AWS管理キー CMK 備考
キー保管料金 無料 月額料金あり(AWS公式参照) キーが存在する限り発生
APIリクエスト料金 発生する 発生する 一定数の無料枠あり(AWS公式参照)
S3 Bucket Key使用時 APIコール削減効果あり APIコール削減効果あり 大量オブジェクト時に特に有効

実際の運用で問題になるのは、S3のオブジェクト数が多く、かつBucket Keyを有効にしていない場合だ。オブジェクトのPUT/GETごとにKMS APIコールが発生するため、アクセス頻度の高いバケットでは月間のAPIリクエスト数が想定を大きく超えることがある。Bucket Keyを有効にすることでこの問題の大部分は解消できる。

「CMKは高い」という印象を持つエンジニアが多いが、実際にはBucket Keyを有効にした状態でのAPIリクエスト料金の差は小さくなる。コスト差の本質はキー保管料金にある。

よくある失敗パターン:「暗号化されているのにアクセスできない」

本番環境でよく見るのが、S3バケットにCMKで暗号化されたオブジェクトが存在するのに、特定のIAMロールからGetObjectが403で返ってくるケースだ。S3バケットポリシーでs3:GetObjectを許可しているのに、なぜか読めない。

最初の誤診はS3バケットポリシーを疑うことだ。バケットポリシーを何度見直しても問題は見つからない。CloudTrailのS3データイベントログを見ると、エラーはS3レベルではなくKMSレベルで発生していることがわかる。

実際の原因はKMSキーポリシーにそのIAMロールが含まれていないことだ。SSE-KMSで暗号化されたオブジェクトへのGETは、S3の権限だけでなくKMSのDecrypt権限も必要になる。S3バケットポリシーとKMSキーポリシーの両方が通過して初めてオブジェクトを取得できる。

診断コマンド:CloudTrailでKMSのエラーを確認する。

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=Decrypt \
  --region us-east-1 \
  --max-results 10

KMSキーポリシーに対象ロールが含まれているか確認する:

aws kms get-key-policy \
  --key-id alias/s3-encryption-key \
  --policy-name default \
  --region us-east-1

S3のアクセス権限とKMSのDecrypt権限は独立した認可レイヤーだ。どちらか一方だけでは不十分で、両方が揃って初めてアクセスが成立する。

AWS管理キーとCMKの選択フロー

graph TD Start(["S3暗号化キーの選択"]) --> Q1{"クロスアカウント
アクセスが必要?"} Q1 -->|Yes| CMK["CMKを選択"] Q1 -->|No| Q2{"キーポリシーの
制御が必要?"} Q2 -->|Yes| CMK Q2 -->|No| Q3{"コンプライアンス要件で
キー所有権証明が必要?"} Q3 -->|Yes| CMK Q3 -->|No| Q4{"特定IAMロールへの
アクセス制限が必要?"} Q4 -->|Yes| CMK Q4 -->|No| AWS["AWS管理キーで十分"] CMK --> Note1["Bucket Key有効化を忘れずに"] AWS --> Note2["Bucket Key有効化を忘れずに"]
  1. クロスアカウントアクセスが必要な場合はCMK一択。AWS管理キーはアカウントをまたいで使用できない。
  2. コンプライアンス要件でキーポリシーの制御や監査証跡が必要な場合もCMKを選ぶ。
  3. 特定のIAMロールやサービスにのみアクセスを制限したい場合はCMKが必要。AWS管理キーではキーポリシーを変更できない。
  4. 上記いずれも不要で、シンプルな暗号化とコスト最小化が優先ならAWS管理キーで十分だ。

AWS KMS S3暗号化のまとめと次のステップ

AWS KMSを使ったS3暗号化の選択は、コスト・制御・コンプライアンスのトレードオフだ。多くのケースでAWS管理キーで十分だが、クロスアカウント構成やコンプライアンス要件があればCMKが必要になる。どちらを選ぶにせよ、S3 Bucket Keyの有効化は忘れずに設定すること——これだけでKMS関連コストを大幅に削減できる。

詳細は以下の公式ドキュメントを参照してほしい:

用語集(Glossary)

用語 説明
CMK(Customer Managed Key) ユーザーが作成・管理するKMSキー。キーポリシー、ローテーション設定、無効化・削除を自分で制御できる。
エンベロープ暗号化 データキーでデータを暗号化し、そのデータキー自体をマスターキーで暗号化する二重構造の暗号化方式。KMSが採用する基本モデル。
S3 Bucket Key バケットレベルで生成されるキーを使い、オブジェクトごとのKMS APIコールを削減する機能。KMSリクエスト料金の削減に直結する。
キーポリシー KMSキーへのアクセスを制御するリソースベースのポリシー。CMKでのみ変更可能。
SSE-KMS AWS KMSキーを使ったS3のサーバーサイド暗号化方式。AWS管理キーまたはCMKを指定できる。

Related Posts

コメント

このブログの人気の投稿

EC2 SSH接続タイムアウトの原因と修正方法 — セキュリティグループのインバウンドルール完全ガイド

S3パブリックアクセス拒否の原因と解決策:バケットレベルの「Block Public Access」が優先される仕組み

EC2インスタンスIDをメタデータから取得する方法 — IMDSv2が安全な理由