SSE-KMSのリクエストコストが最大99%削減可能 S3バケットキーについて調べてみた #reinvent

SSE-KMSを使用してオブジェクトを暗号化する際に選択できるS3バケットキーについて紹介します。S3バケットキーを使えば、KMSへのリクエストコストを最大99%削減できるかも知れません。
2020.12.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、岩城です。

今年もre:Invent開幕しましたね!弊社は深夜にも関わらず多くの社員がワイワイガヤガヤしていたようですが、私は夜中に起きていられない人なのでいつもどおりの生活リズムで過ごす予定です。そういう意味でも現地で参加できたら良かった

さて、What's Newを見ていると気になるアップデートがありましたので紹介したいと思います。

Amazon S3 Bucket Keys reduce the costs of Server-Side Encryption with AWS Key Management Service (SSE-KMS)

なにやら「S3バケットキー」という見慣れない単語がありますね。

S3バケットキーを使用すればSSE-KMSのリクエストコストが最大99%も削減できるみたいです。

まずは、SSE-KMSの導入とS3バケットキーがないことによるKMSへのリクエストコストが掛かる理由を確認します。

S3バケットキーがなかった時代

S3バケットは暗号化を設定して、バケットに保存される全てのオブジェクトをS3側で暗号化することができます。サーバー側で暗号化するので、これをServer Side Encryption、SSE、サーバー側の暗号化などと言います。

暗号化には暗号化キーが必要になりますが、キーの管理方法の違いによって以下の3種類があります。

  • S3が管理するキーによるSSE(SSE-S3)
  • KMSに保存されているカスタマーマスターキー(CMK)によるSSE(SSE-KMS)
  • 利用者が指定したキーによるSSE(SSE-C)

本エントリに関係があるのはSSE-KMSです。他の2つは参考程度に覚えておいてください。

SSE-KMSを使用して暗号化すると、オブジェクト毎に個別のデータキーを生成し、そのデータキーとCMKを使って暗号化します。反対にオブジェクトをGETする場合は、CMKを使ってデータキーを複合して、そのデータキーを用いてオブジェクトを複合することになります。この辺りの仕組みが気になる方はAWSのドキュメントや以下の記事を参照してみてください。

このように、SSE-KMSで暗号化されたオブジェクトをPUT/GETすると、データキーの生成やCMKでデータキーを暗号化したり復号化したりするリクエストが発生し、KMSへのリクエストの度にコストが掛かります。このため、オブジェクト数がやそのオブジェクトに対するアクセス頻度が少なければ問題ありませんが、大量になってくるとKMSのコストが目立ってきます。

S3バケットキーの登場

ここで登場するのがS3バケットキーです。

S3バケットキーはSSE-KMSを使用してオブジェクトを暗号化する場合に選択できるオプションです。

S3バケットキーを有効にすると、KMSはバケット内のオブジェクトの一意のデータキーを作成するために使用されるS3バケットキーを生成します。

このS3バケットキーはS3内で期間限定で使用され、KMSにリクエストして暗号化操作を完了する必要がなくなります。

これにより、KMSで行っていたデータキーの生成、暗号化操作をS3バケットキーに寄せられ、S3からKMSへのリクエストが減少し、KMSへのリクエストに掛かるコストが最大99%削減可能になります。

(ドキュメントより引用)

既存バケットへの影響

S3バケットキーは、これから新しくバケットを作成するとSSE-KMSを選択した時点でデフォルトで有効になっていますが、既存バケットは無効になっています。

後から有効にすることができますが、有効にされた後に新しくPUTされたオブジェクトが対象となります。

既存オブジェクトは無効のままなので。既存オブジェクトを有効にしたい場合は、再度PUTし直す必要があります。

利用可能リージョン

全てのリージョンで利用可能です。

コスト

S3バケットキー利用による追加コストは掛かりません。

やってみた

新規バケットのパターン

まずは、新しくバケットを作成するパターンで確認してみます。

暗号化キータイプでSSE-KMSを選択すると、これまで存在しなかったバケットキーが追加されていることが分かります。

デフォルトでS3バケットキーが有効化されていました。

S3バケットキーが有効のバケットが作成されたので、プロパティを確認してみます有効になっていますね。

適当にPUTしたオブジェクトのプロパティも確認すると、有効になっていることが分かります。

S3バケットキーをわざわざ無効にする必要が思い当たらないのですが、PUT時にバケットキーのステータスを変更できるのか確認してみました。

コンソール上でも注意書きがありますが、コンソールからアップロードする場合、バケットの設定を継承するためオブジェクトレベルでS3バケットキーの変更はできません。グレーアウトされていますね。

「コンソールからアップロードする場合」とあるので、ではCLIなら可能なのかと思い試してみました。 AWS CLI v2を最新版に更新してから試しました。。今回利用した環境は以下のとおりです。

$ aws --version
aws-cli/2.1.6 Python/3.7.4 Darwin/17.7.0 exe/x86_64 prompt/off

put-objectの引数に--no-bucket-key-enabledを追加すると、S3バケットキーを無効にした状態でPUTできます。

$ aws s3api put-object --bucket s3-bucket-key-20201202 --key s3-bucket-key --body ./s3-bucket-key --no-bucket-key-enabled
{
    "ETag": "\"XXXXXXXXXXXXXXXXXXXXXXXXXX\"",
    "ServerSideEncryption": "aws:kms",
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:XXXXXXXXXX:key/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

オブジェクトのプロパティを確認してみると、BucketKeyEnabledがないので無効になっていることのようです。 この結果だけだと不安になったのでコンソールでも確認してみたところ、きちんと無効になっていました。

aws s3api head-object --bucket s3-bucket-key-20201202 --key s3-bucket-key
{
    "AcceptRanges": "bytes",
    "LastModified": "2020-12-02T07:17:38+00:00",
    "ContentLength": 0,
    "ETag": "\"XXXXXXXXXXXXXXXXXXXXXXXXXX\"",
    "ContentType": "binary/octet-stream",
    "ServerSideEncryption": "aws:kms",
    "Metadata": {},
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:XXXXXXXXXX:key/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

参考までに有効のときにCLIで確認した結果を載せておきます。BucketKeyEnabledがtrueになっていますね。

aws s3api head-object --bucket s3-bucket-key-20201202 --key s3-bucket-key
{
    "AcceptRanges": "bytes",
    "LastModified": "2020-12-02T06:59:08+00:00",
    "ContentLength": 0,
    "ETag": "\"XXXXXXXXXXXXXXXXXXXXXXXXXX\"",
    "ContentType": "binary/octet-stream",
    "ServerSideEncryption": "aws:kms",
    "Metadata": {},
    "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:XXXXXXXXXX:key/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "BucketKeyEnabled": true
}

既存バケットのパターン

既存バケットでも後からS3バケットキーを有効にできます。プロパティのサーバー側の暗号化設定から変更します。

変更手順はバケットキーを無効にするから有効にするだけなので割愛します。

先述したとおり、有効にする前の既存オブジェクトはS3バケットキーが無効なので注意してください。

既存オブジェクトを有効にするにはPUTし直すしかなさそうです。CLIを使ってスクリプト書いてPUTし直す方法の他にS3レプリケーションを使えるかも知れません。

S3レプリケーションについては試せていないのですが、コンソールを見る感じはいけそうです。ただし、注意書きにもあるとおり、KMSのリクエストレートの上限緩和を考慮したり、簡単ではなさそうな印象です。

機会があれば試してブログにしたいと思います。

おわりに

S3バケットキーの設定自体はとても簡単です。これから新たにバケットを作成する場合は、デフォルトで有効になっているため、意識せず使っていくものだと思いました。

既存バケットでS3バケットキーを有効にしても、既存オブジェクトへは反映されません。オブジェクトをPUTし直しす必要がありますが、KMSの利用料を抑えることができるかも知れないので一考の価値ありです。

本エントリを書くにあたって、KMSの概念をもう一度確認できたのでとても勉強になりました。

本エントリがどなたかのお役に立てれば幸いです。