既存の Discourse サーバーを新しい AWS ベースの環境に移行しようとしており、アップロードはサーバーサイド暗号化(SSE-C)と顧客管理キーを使用してバケットに保存しています。復元プロセス中に、アップロードが S3 に保存されません。すべてのアップロードが失敗します。tap|p デバッグを適切に使用したところ、アップロードは行われているものの、返された ETag の検証が失敗していることがわかりました。これは、アップロード後に S3 から返される ETag が毎回異なるためです。たとえば、復元を試行した 2 回の試行で、 put_object 呼び出し の戻り値は次のようになります。
# 実行 1
# <struct Aws::S3::Types::PutObjectOutput expiration=nil, etag="\"d49ec2006cfd6fe957af2f711edd9a4b\"", checksum_crc32=nil, checksum_crc32c=nil, checksum_sha1=nil, checksum_sha256=nil, server_side_encryption="aws:kms", version_id="xAF23wQ.zwpoxVmmGiTjxfX0svMZbHAe", sse_customer_algorithm=nil, sse_customer_key_md5=nil, ssekms_key_id="**redacted**", ssekms_encryption_context=nil, bucket_key_enabled=true, request_charged=nil>
# 実行 2:
# <struct Aws::S3::Types::PutObjectOutput expiration=nil, etag="\"05edffee421c6aef950b3d4418ada293\"", checksum_crc32=nil, checksum_crc32c=nil, checksum_sha1=nil, checksum_sha256=nil, server_side_encryption="aws:kms", version_id="H2_8SVh.Yx2LKB4GIjhyPbVoj_.Vc1E2", sse_customer_algorithm=nil, sse_customer_key_md5=nil, ssekms_key_id="**redacted**", ssekms_encryption_context=nil, bucket_key_enabled=true, request_charged=nil>
(クライアントサイドの MD5 ハッシュと、ファイル名を含む put_object リクエストオプションも出力しているため、これらが同じファイルであることはわかっています)
SSE-C を使用すると、ETag レスポンスヘッダー の動作が異なることがわかりました。
顧客提供キー(SSE-C)または AWS Key Management Service(AWS KMS)キー(SSE-KMS)でサーバーサイド暗号化されたオブジェクトの ETag は、オブジェクトデータの MD5 ダイジェストではありません。
SSE-C でアップロードの整合性検証を行う唯一の方法は、Content-MD5 リクエストヘッダーを送信し、S3 に破損検出を行わせることです。また、既にアップロードされているチェック も SSE-C を使用すると壊れることに注意してください。ただし、これは SKIP_ETAG_VERIFY を使用して無効にすることができます。
すぐに PR を提出しないのは、2 つのアプローチ方法があるためです。
SKIP_ETAG_VERIFYをアップロード後の検証にも拡張する。これは安価でハックな方法であり、ユーザーは SSE-C の使用によりそれを無効にする必要があることを知っておく必要があります。または- Content-MD5 ヘッダーを使用するように切り替える(できれば常に)ことで、アップロードの整合性保護を行う。これは、より大きな PR のコストで、すべての人に機能するという利点があります。
(ちなみに、誰もこれに以前ヒットしなかったことに少し動揺しています。誰もアップロードに SSE-C を使用して Discourse を使用していないのでしょうか?)