[アップデート] Amazon S3 で SSE-C の使用を制御できる IAM 条件キーが追加されました

S3 用条件キーとしては過去最長の s3:x-amz-server-side-encryption-customer-algorithm (50字)です。

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

コンバンハ、千葉(幸)です。

Amazon S3 の SSE-C の使用を 強制 / 抑制 できる 条件キーが追加されました。IAM ポリシーや S3 バケットポリシーなどで使用できます。

これで 3 つのサーバサイド暗号化タイプすべてで、条件キーによる制御が可能になりました。

SSE-C 暗号化とは何か

SSE-C は、Amazon S3 の サーバーサイド暗号化 で用意されている3つのオプションのうちのひとつです。

  • SSE-S3
    • Amazon S3 が管理するキーによるサーバー側の暗号化
  • SSE-KMS
    • AWS Key Management Service に保存されている KMS キーによるサーバー側の暗号化
  • SSE-C
    • お客様が指定したキーによるサーバー側の暗号化

どの暗号化タイプでも暗号化キーが必要となり、その管理方式は以下の通りです。

暗号化タイプ 暗号化キー
SSE-S3 S3によって管理されカスタマーは考慮不要
SSE-KMS AWS KMSキーとしてカスタマーが管理
SSE-C カスタマーが生成し提供が必要

SSE-C とそれ以外の暗号化タイプでは「IAMの権限のみでアクセスできるかどうか」という観点で差異があります。

例えば SSE-S3 であれば Amazon S3 に対する権限が、SSE-KMS であればそれに加えて AWS KMS に対する権限があれば、そのタイプで暗号化されたオブジェクトにアクセス可能です。つまり IAM の権限さえあれば誰でも触れる状態であり、仮に強い権限を持つアクセスキーの流出が起こった際にはその権限を利用してデータが盗まれる、という可能性もあります。

それに対して SSE-C で暗号化されたオブジェクトは IAM 権限だけではアクセスできません。例えば GET リクエストを実行する際には暗号化の際に指定したカスタマー提供キーの情報を含める必要があり、それが不十分な場合にはリクエストは拒否されます。IAM 以外の制御レイヤとしての機能が期待できます。

一方で、その仕様からマネジメントコンソールでの操作の大部分が制限される、キーそのものや「どのオブジェクトをどのキーで暗号化したか」というマッピングはカスタマー側で管理する必要があり手間が増える、などデメリットとして機能する側面もあります。使い所は考慮が必要です。

何が追加されたのか

最下行の条件キーs3:x-amz-server-side-encryption-customer-algorithmが追加されました。

条件キー 暗号化タイプ
s3:x-amz-server-side-encryption SSE-S3
s3:x-amz-server-side-encryption-aws-kms-key-id SSE-KMS
s3:x-amz-server-side-encryption-customer-algorithm SSE-C

これまで他の暗号化タイプ向けの条件キーは存在していましたが、今回のアップデートにより SSE-C 向けが追加されすべてのタイプが対応しました。これらは以下のページから確認できます。

いずれの条件キーも対応しているアクションは以下の通りです。種類が限られていますので、ポリシー設計の際にはご注意ください。

  • s3:BypassGovernanceRetention
  • s3:PutObject
  • s3:ReplicateObject

何ができるようになったのか

条件キーの指定により、以下の制御ができるようになりました。

  • SSE-C を強制(SSE-C で暗号化されていないオブジェクトのアップロードを拒否)
  • SSE-C を抑制(SSE-C で暗号化されたオブジェクトのアップロードを拒否)

前者は社内のコンプライアンスに準じるためなど追加の制御レイヤが必要な場合、後者は SSE-C によるデメリットを回避したい場合などでの使用が想定されます。

多くの場合 S3 バケットポリシーに条件キーを書くことになるかと思いますが、IAM ポリシーや他のポリシーでの使用がマッチする場合もあるでしょう。

やってみた

実際に条件キーs3:x-amz-server-side-encryption-customer-algorithmを使用して SSE-C の強制、抑制を試してみます。

以下のドキュメントにサンプルのポリシーが記載されているので、それに則ります。

S3 バケットchibayuki-hoge-hogeのバケットポリシーを変更し、それぞれでの挙動を確認します。なお、S3 にリクエストを実行する IAM エンティティは十分な権限を有しており、変更もしません。

SSE-C の使用を強制するポリシー

以下のバケットポリシーを設定しました。

{
    "Version": "2012-10-17",
    "Id": "PutObjectPolicy",
    "Statement": [
        {
            "Sid": "RequireSSECObjectUploads",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::chibayuki-hoge-hoge/*",
            "Condition": {
                "Null": {
                    "s3:x-amz-server-side-encryption-customer-algorithm": "true"
                }
            }
        }
    ]
}

SSE-C 暗号化を指定していない("s3:x-amz-server-side-encryption-customer-algorithm": "true"が Null)場合には PutObject を拒否する、という定義です。

SSE-S3を指定して PutObject を試みるとエラーになりました。

% aws s3api put-object\
    --bucket chibayuki-hoge-hoge\
    --key test-sse-s3.txt\
    --body test.txt\
    --server-side-encryption AES256

An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

それに対してSSE-Cを指定した場合は正常に実行されます。

# 32byte 文字列を生成
% SSE_CUSTOMER_KEY=$(openssl rand -hex 16)

# 生成した文字列を暗号化キーとして指定しアップロードの実行
% aws s3api put-object\
    --bucket chibayuki-hoge-hoge\
    --key test-sse-c.txt\
    --body test.txt\
    --sse-customer-algorithm AES256\
    --sse-customer-key $SSE_CUSTOMER_KEY
{
    "ETag": "\"d4a576a2586a5ede7ba9b38c6fac4cdf\"",
    "VersionId": "yFbKjfKb8HOEaDYHOazIhpwdiVpGxCB9",
    "SSECustomerAlgorithm": "AES256",
    "SSECustomerKeyMD5": "DslyBMav7heRaJFCpfa0DA=="
}

ちなみにマネジメントコンソールからアップロードするときにSSE-Cは指定できないため、この状態のバケットにファイルをアップロードしたい場合はコンソール以外の手段をとる必要があります。

SSE-C が選べない

S3_Management_Console_No_SSE-C

▼例えばSSE-S3を指定してアップロードするとエラーになる

S3_Management_Console_Error_uproad

SSE-C の使用を抑制するポリシー

先ほどとは逆のパターンです。Sidは評価ロジックには関係ないため、実質的にはtruefalseになっただけです。

{
    "Version": "2012-10-17",
    "Id": "PutObjectPolicy",
    "Statement": [
        {
            "Sid": "RestrictSSECObjectUploads",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::chibayuki-hoge-hoge/*",
            "Condition": {
                "Null": {
                    "s3:x-amz-server-side-encryption-customer-algorithm": "false"
                }
            }
        }
    ]
}

SSE-S3を指定した PutObject が問題なく成功しました。

% aws s3api put-object\
    --bucket chibayuki-hoge-hoge\
    --key test-sse-s3.txt\
    --body test.txt\
    --server-side-encryption AES256
{
    "ETag": "\"1a6f8abe44f6b9c5a7c2435c43749dea\"",
    "ServerSideEncryption": "AES256",
    "VersionId": "ixjpY7N2V8pkAfaMbCeaDwd7hZdyed46"
}

逆に、SSE-Cを指定した PutObject は拒否されました。

% aws s3api put-object\
    --bucket chibayuki-hoge-hoge\
    --key test-sse-c.txt\
    --body test.txt\
    --sse-customer-algorithm AES256\
    --sse-customer-key $SSE_CUSTOMER_KEY

An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

これで条件キーの挙動が確認できました。他の暗号化タイプに対しても、条件キーさえ変えてあげれば同様のポリシーで対応できそうですね。

終わりに

Amazon S3 の SSE-C 暗号化を 強制 / 抑制 できる IAM 条件キーが追加された、というアップデートでした。

SSE-C を使っているケースはあまり聞かないな、と思っていたのですが、冒頭で挙げたアップデート記事でまさにな記述がありました。

お客様の大半は、S3 に組み込まれた暗号化キーに関するサポートを、S3 が管理するキー (SSE-S3) または AWS Key Management Service (KMS) キー (SSE-KMS) のいずれかを使用して活用しています。

SSE-C を使うケースはそこまで多くないかもしれませんが、それを制御できる条件キーはあるよ、ということを覚えておくと役に立つかも知れません。

何かの機会に思い出していただければ幸いです。

以上、 チバユキ (@batchicchi) がお送りしました。

参考