SJ blog
security
A

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

S3暗号化の全種類比較 — SSE-S3/SSE-KMS/SSE-C/クライアントサイド

S3の4種類の暗号化方式(SSE-S3, SSE-KMS, DSSE-KMS, SSE-C, クライアントサイド)を比較。鍵管理の違い、KMS API呼び出しコスト、バケットキー設定、試験頻出ポイントを解説。

一言結論

S3暗号化は「誰が鍵を管理するか」と「監査ログが必要かどうか」で方式を選び、SSE-KMSを使う場合はS3 Bucket Keyを必ず有効化してKMS APIコストを最大99%削減することが大規模利用の前提条件だ。

S3の暗号化オプション一覧

S3の暗号化は「誰が鍵を管理するか」によって4種類に分類される。

方式鍵管理者KMSコスト監査ログ特記事項
SSE-S3 (AES-256)AWSなしなしデフォルト。最も簡単
SSE-KMSAWS/ユーザーありCloudTrailに記録鍵管理・監査が必要な場合
DSSE-KMSAWS/ユーザーありCloudTrailに記録二重暗号化(規制対応)
SSE-CユーザーなしCloudTrailに記録鍵をユーザーが管理
クライアントサイドユーザーなしなし暗号化後にS3に保存

SSE-KMS の詳細

SSE-KMSはS3オブジェクトをKMSキーで暗号化する。アップロード時にKMSのGenerateDataKey、ダウンロード時にDecryptのAPI呼び出しが発生する。

# SSE-KMSでオブジェクトをアップロード
aws s3 cp myfile.txt s3://my-bucket/ \
  --sse aws:kms \
  --sse-kms-key-id arn:aws:kms:ap-northeast-1:123456789012:key/xxx

# バケットのデフォルト暗号化をSSE-KMSに設定
aws s3api put-bucket-encryption \
  --bucket my-bucket \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "arn:aws:kms:ap-northeast-1:123456789012:key/xxx"
      },
      "BucketKeyEnabled": true
    }]
  }'

S3 Bucket Key — KMSコスト削減

S3 Bucket Keyを有効にすると、オブジェクトごとにKMS APIを呼び出さず、バケットレベルのデータキーを使って暗号化する。大量のオブジェクトがある場合にKMSコストを最大99%削減できる。

通常のSSE-KMS:
  各オブジェクトアップロード → KMS GenerateDataKey呼び出し
  各オブジェクトダウンロード → KMS Decrypt呼び出し

S3 Bucket Key有効:
  バケットキー(データキー)をS3が一定期間キャッシュ
  → KMS API呼び出し頻度が大幅減少

デメリット:CloudTrailのKMSイベントが減るため、オブジェクトレベルの詳細な監査には適さない。

SSE-C の特徴と要件

SSE-Cはユーザーが鍵を管理し、リクエスト時に鍵を渡す方式だ。

# SSE-Cでのアップロード(HTTPS必須)
aws s3 cp myfile.txt s3://my-bucket/ \
  --sse-c AES256 \
  --sse-c-key "$(openssl rand -base64 32)"

# SSE-Cでのダウンロード(同じ鍵が必要)
aws s3 cp s3://my-bucket/myfile.txt ./myfile.txt \
  --sse-c AES256 \
  --sse-c-key "保存しておいた鍵"

重要な制約:

  • HTTPSが必須(HTTPでは鍵が平文で送信されるため自動拒否)
  • AWSは鍵を保存しない → 鍵を失うとオブジェクト復号不可能
  • AWS CLIでSSE-Cを使う場合、SDKから直接使う必要がある(マネジメントコンソール非対応)

クライアントサイド暗号化

S3にアップロードする前にクライアント側で暗号化する。S3には暗号化済みのバイナリが保存される。

import boto3
from aws_encryption_sdk import EncryptionSDKClient, CommitmentPolicy

enc_client = EncryptionSDKClient(
    commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
)

# 暗号化
ciphertext, _ = enc_client.encrypt(
    source=open('myfile.txt', 'rb').read(),
    key_provider=kms_key_provider
)

# S3にアップロード(暗号化済み)
s3 = boto3.client('s3')
s3.put_object(Bucket='my-bucket', Key='myfile.txt', Body=ciphertext)

暗号化の強制

S3バケットに非暗号化アップロードを禁止するポリシー:

// SSE-KMSでない場合にアップロードを拒否
{
  "Statement": [{
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::my-bucket/*",
    "Condition": {
      "StringNotEquals": {
        "s3:x-amz-server-side-encryption": "aws:kms"
      }
    }
  }]
}
// 特定のKMSキー以外での暗号化を拒否
{
  "Statement": [{
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::my-bucket/*",
    "Condition": {
      "StringNotEqualsIfExists": {
        "s3:x-amz-server-side-encryption-aws-kms-key-id":
          "arn:aws:kms:ap-northeast-1:123456789012:key/xxx"
      }
    }
  }]
}

試験頻出ポイント

問題パターン回答
監査・コンプライアンス要件でキー使用履歴が必要SSE-KMS(CloudTrail連携)
KMSコストを最小化しつつSSE-KMSを使うS3 Bucket Keyを有効化
AWSに鍵を渡したくないSSE-C またはクライアントサイド
最もシンプルな暗号化SSE-S3(デフォルト)
HTTPSなしでのSSE-C自動でリクエスト拒否
二重暗号化が規制で必要DSSE-KMS

まとめ

S3暗号化の選択は「誰が鍵を管理するか」と「監査要件があるか」で決まる。特にSSE-KMSはKMSコストとCloudTrail監査のトレードオフを理解することが重要だ。S3 Bucket Keyは大規模利用時のコスト対策として必ず有効化を検討する。