概要
- S3のオブジェクトの暗号化といっても、サーバサイド暗号化にはいくつか種類がある。
- ただ、どんな違いがあるのかよくわかっていない。
- 試してみた。
対象
- S3バケットのオブジェクトに暗号化をする要件があるが、いまいちサーバサイド暗号化の種類の理解不足なので、ちょっとかじりたい。という方。
暗号化の種類
SSE-S3
- AmazonS3がデータ暗号化キーとマスター暗号化キーを管理
- 暗号化の使用に追加料金はかかりません
SSE-KMS
- AWSマネージド型キーまたは、カスタマー管理型のキーがありKMSでキーを管理
- AWS Key Management Service の料金が適用
SSE-C
- ユーザーが暗号化キーを管理
暗号化してみる
バケットを作成
- 非サーバサイド暗号化バケット
- SSE-S3でサーバサイド暗号化を行うバケット
- SSE-KMS(AWSマネージド型キー)でサーバサイド暗号化を行うバケット
- SSE-KMS(カスタマー管理型のキー)でサーバサイド暗号化を行うバケット
作成するテンプレート
AWSTemplateFormatVersion: '2010-09-09'
Resources:
NonEncryptedBucket:
Type: AWS::S3::Bucket
EncryptedBucketBySSES3:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
EncryptedBucketBySSEKMS:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KmsKey:
Type: AWS::KMS::Key
Properties:
Description: 'Key created with S3ServerSideEncryptionDemo template.'
KeyPolicy:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action: "kms:*"
Resource: "*"
EncryptedBucketByCustomerSSEKMS:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
KMSMasterKeyID: !Ref KmsKey
SSEAlgorithm: aws:kms
Outputs:
NonEncryptedBucket:
Value: !Ref NonEncryptedBucket
EncryptedBucketBySSES3:
Value: !Ref EncryptedBucketBySSES3
EncryptedBucketBySSEKMS:
Value: !Ref EncryptedBucketBySSEKMS
EncryptedBucketByCustomerSSEKMS:
Value: !Ref EncryptedBucketByCustomerSSEKMS
バケット作成
aws cloudformation create-stack \
--stack-name s3-server-side-encryption-demo \
--template-body file://template.yaml
バケットにファイルをアップロード
非暗号化バケット
NON_ENCRYPTED_BUCKET=$(aws cloudformation describe-stacks \
--stack-name s3-server-side-encryption-demo \
--query 'Stacks[].Outputs[?OutputKey==`NonEncryptedBucket`].OutputValue' \
--output text)
aws s3api put-object \
--bucket ${NON_ENCRYPTED_BUCKET} \
--key sample.png \
--body sample.png
# {
# "ETag": "\"b420fe104fb7b48b5dcd12de92c444b8\""
# }
SSE-S3暗号化バケット
暗号化をしないバケットへのアップロードと異なり、レスポンスからサーバサイド暗号化にAES256を使っていることが確認できます。
SSE_S3_ENCRYTED_BUCKET=$(aws cloudformation describe-stacks \
--stack-name s3-server-side-encryption-demo \
--query 'Stacks[].Outputs[?OutputKey==`EncryptedBucketBySSES3`].OutputValue' \
--output text)
aws s3api put-object \
--bucket ${SSE_S3_ENCRYTED_BUCKET} \
--key sample.png \
--body sample.png
# {
# "ETag": "\"b420fe104fb7b48b5dcd12de92c444b8\"",
# "ServerSideEncryption": "AES256"
# }
SSE-KMS暗号化バケット
このケースも、レスポンスからサーバサイド暗号化にKMSのキーを使っていることが確認できます。
KMSのキーを使っている場合、キーIDも確認できます。
SSE_KMS_ENCRYTED_BUCKET=$(aws cloudformation describe-stacks \
--stack-name s3-server-side-encryption-demo \
--query 'Stacks[].Outputs[?OutputKey==`EncryptedBucketBySSEKMS`].OutputValue' \
--output text)
aws s3api put-object \
--bucket ${SSE_KMS_ENCRYTED_BUCKET} \
--key sample.png \
--body sample.png
# {
# "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:1234567890xx:key/8fa790e9-10f6-4d6c-bca1-d9cb5af6e899",
# "ETag": "\"8ef45fd3802ab4bb8a8071d2d8d59294\"",
# "ServerSideEncryption": "aws:kms"
# }
KMSに作成したキーを利用しSSE-KMS暗号化バケット
ユーザ自身が作成したKMSのキーの場合も同様です。
CUSTOMER_SSE_KMS_ENCRYTED_BUCKET=$(aws cloudformation describe-stacks \
--stack-name s3-server-side-encryption-demo \
--query 'Stacks[].Outputs[?OutputKey==`EncryptedBucketByCustomerSSEKMS`].OutputValue' \
--output text)
aws s3api put-object \
--bucket ${CUSTOMER_SSE_KMS_ENCRYTED_BUCKET} \
--key sample.png \
--body sample.png
# {
# "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:1234567890xx:key/a52093d0-b506-4861-87dc-c5cda681c92e",
# "ETag": "\"1e6befc82805e250db067fd5c648452f\"",
# "ServerSideEncryption": "aws:kms"
# }
SSE-KMSの確認
SSE-KMSでサーバサイド暗号化したオブジェクトには、SSEKMSKeyIdが一緒にレスポンスが返ってくることが確認できることは上で述べました。
SSEKMSKeyIdからKMSのどのキーで暗号化が行われたのかを確認することで、このキーが「AWSマネージド型キー」なのか「カスタマー管理型のキー」なのか確認してみましょう。
SSE-KMS暗号化バケットで使用されたキー
SSEKMS_KEY_ID=$(aws s3api head-object \
--bucket ${SSE_KMS_ENCRYTED_BUCKET} \
--key sample.png \
--query 'SSEKMSKeyId' \
--output text)
aws kms describe-key --key-id ${SSEKMS_KEY_ID}
# {
# "KeyMetadata": {
# "Origin": "AWS_KMS",
# "KeyId": "8fa790e9-10f6-4d6c-bca1-d9cb5af6e899",
# "Description": "Default master key that protects my S3 objects when no other key is defined",
# "KeyManager": "AWS",
# "Enabled": true,
# "KeyUsage": "ENCRYPT_DECRYPT",
# "KeyState": "Enabled",
# "CreationDate": "2018-09-05T06:35:48.668000+00:00",
# "Arn": "arn:aws:kms:ap-northeast-1:1234567890xx:key/8fa790e9-10f6-4d6c-bca1-d9cb5af6e899",
# "AWSAccountId": "1234567890xx"
# }
# }
KeyManager : AWS となっていることから、AWSマネージド型キーを使っていることが確認できます。
KMSに作成したキーを利用しSSE-KMS暗号化バケットで使用されたキー
CUSTOMER_SSEKMS_KEY_ID=$(aws s3api head-object \
--bucket ${CUSTOMER_SSE_KMS_ENCRYTED_BUCKET} \
--key sample.png \
--query 'SSEKMSKeyId' \
--output text)
aws kms describe-key --key-id ${CUSTOMER_SSEKMS_KEY_ID}
# {
# "KeyMetadata": {
# "Origin": "AWS_KMS",
# "KeyId": "a52093d0-b506-4861-87dc-c5cda681c92e",
# "Description": "Key created with S3ServerSideEncryptionDemo template.",
# "KeyManager": "CUSTOMER",
# "Enabled": true,
# "KeyUsage": "ENCRYPT_DECRYPT",
# "KeyState": "Enabled",
# "CreationDate": "2019-11-15T13:51:24.941000+00:00",
# "Arn": "arn:aws:kms:ap-northeast-1:1234567890xx:key/a52093d0-b506-4861-87dc-c5cda681c92e",
# "AWSAccountId": "1234567890xx"
# }
# }
KeyManager : CUSTOMER となっていることから、カスタマー管理型のキーを使っていることが確認できます。
これはテンプレートの AWS::KMS::Key で作成されたキーです。
通常、KMSによる暗号化を指示した場合、デフォルトでは、KMS(AWS Key Management Service)のAWSマネージド型のキーを利用し暗号化を行うが、ユーザ自身がKMSで鍵を作成し、サーバサイド暗号化のキーに利用することが出来ることも確認できました。
非暗号化バケットにサーバサイド暗号化を指定してファイルをアップロード
上記では、バケット自体にサーバサイド暗号化の設定をしているバケットに対して、ファイルをアップロードする動作検証を行いました。
他に、サーバサイド暗号化の設定をしていないバケットに対して、ファイルのアップロード時にサーバサイド暗号化の指定をすることも可能です。
サーバサイド暗号化にSSE-S3を指定してアップロード
aws s3api put-object \
--bucket ${NON_ENCRYPTED_BUCKET} \
--key sample_by_SSE-S3.png \
--body sample.png \
--server-side-encryption AES256
# {
# "ETag": "\"b420fe104fb7b48b5dcd12de92c444b8\"",
# "ServerSideEncryption": "AES256"
# }
サーバサイド暗号化にSSE-KMSを指定してアップロード
aws s3api put-object \
--bucket ${NON_ENCRYPTED_BUCKET} \
--key sample_by_SSE-KMS.png \
--body sample.png \
--server-side-encryption aws:kms
# {
# "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:1234567890xx:key/8fa790e9-10f6-4d6c-bca1-d9cb5af6e899",
# "ETag": "\"cebd51529c2fcd566e1724e763047c23\"",
# "ServerSideEncryption": "aws:kms"
# }
サーバサイド暗号化にKMSに作成したキーでSSE-KMS暗号化を指定してアップロード
aws s3api put-object \
--bucket ${NON_ENCRYPTED_BUCKET} \
--key sample_by_CustomerSSE-KMS.png \
--body sample.png \
--server-side-encryption aws:kms \
--ssekms-key-id ${CUSTOMER_SSEKMS_KEY_ID}
# {
# "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:1234567890xx:key/a52093d0-b506-4861-87dc-c5cda681c92e",
# "ETag": "\"e9a3aa7b8af5dd8522edd316c64b46f3\"",
# "ServerSideEncryption": "aws:kms"
# }
ユーザが生成したキーを指定してアップロード(SSE-C)
また、暗号化キーをユーザ自身で管理し暗号化することも可能です。
SSE_CUSTOMER_KEY=$(cat /dev/urandom | base64 -i | fold -w 32 | head -n 1)
echo ${SSE_CUSTOMER_KEY}
# bKNQl8YfSwa7eKpxSpuamVc+90MQ5BHC
aws s3api put-object \
--bucket ${NON_ENCRYPTED_BUCKET} \
--key sample_by_SSE-C.png \
--body sample.png \
--sse-customer-algorithm AES256 \
--sse-customer-key ${SSE_CUSTOMER_KEY}
# {
# "SSECustomerKeyMD5": "rgDjryTvO47GvZmftTvtPw==",
# "SSECustomerAlgorithm": "AES256",
# "ETag": "\"66aae60ae1a0dd574cf119b899be7463\""
# }
SSM-Cで暗号化したファイルのダウンロード
暗号化キーをユーザ自身で管理する場合、バケットからオブジェクトを取得する際に、他のサーバサード暗号化の取得方法と異なります。
aws s3api head-object \
--bucket ${NON_ENCRYPTED_BUCKET} \
--key sample_by_SSE-C.png
#
# An error occurred (400) when calling the HeadObject operation: Bad Request
オブジェクトを取得する場合は、鍵を指定してあげる必要があるので、注意が必要です。
aws s3api head-object \
--bucket ${NON_ENCRYPTED_BUCKET} \
--key sample_by_SSE-C.png \
--sse-customer-algorithm AES256 \
--sse-customer-key ${SSE_CUSTOMER_KEY}
# {
# "AcceptRanges": "bytes",
# "ContentType": "binary/octet-stream",
# "LastModified": "2019-11-15T14:30:41+00:00",
# "ContentLength": 178061,
# "SSECustomerAlgorithm": "AES256",
# "ETag": "\"66aae60ae1a0dd574cf119b899be7463\"",
# "SSECustomerKeyMD5": "rgDjryTvO47GvZmftTvtPw==",
# "Metadata": {}
# }
さいごに
一般的にはSSM-S3でサーバサイドの暗号化は事足りるものだと思います(コスト的にも)。
ただ利用シーンや要件によっては、検証したサーバサイド暗号化が必要になるのかと思います。
その際の、参考になれば。
検証したテンプレートのリポジトリは S3ServerSideEncryptionDemo になります。