お客様が指定したキーによるサーバー側の暗号化 (SSE−C) の使用 - Amazon Simple Storage Service

お客様が指定したキーによるサーバー側の暗号化 (SSE−C) の使用

サーバー側の暗号化は、保管時のデータ保護に関するものです。サーバー側の暗号化では、オブジェクトのメタデータではなく、オブジェクトデータのみが暗号化されます。お客様が用意したキーでのサーバー側の暗号化 (SSE−C) を使用すると、独自の暗号化キーを保存できます。リクエストの一部として用意された暗号化キーで、Amazon S3 は、ディスクに書き込む際のデータ暗号化と、オブジェクトにアクセスする際のデータ復号を管理します。したがって、データの暗号化と復号を実行するコードをお客様が管理する必要はありません。必要なことは、お客様が用意する暗号化キーを管理することだけです。

オブジェクトをアップロードする場合、Amazon S3 はお客様が用意した暗号化キーを使用してデータに AES−256 暗号化を適用します。その後、Amazon S3 はメモリから暗号化キーを削除します。オブジェクトを取得するときは、リクエストの中で同じ暗号化キーを指定する必要があります。Amazon S3 では、最初に指定された暗号化キーが一致することを確認した後、オブジェクトを復号してから、オブジェクトデータを返します。

SSE-C の使用に追加料金はかかりません。ただし、SSE-C を設定および使用するためのリクエストには、標準の Amazon S3 リクエスト料金が発生します。料金については、Amazon S3 の料金を参照してください。

注記

Amazon S3 では、お客様が用意した暗号化キーを保存しません。代わりに、以降のリクエストを検証するために、ランダムな SALT 値が付加された暗号化キーの Hash-based Message Authentication Code (HMAC) 値が保存されます。SALT 値が付加された HMAC 値を使用して、暗号化キーの値を求めたり、暗号化されたオブジェクトの内容を復号したりすることはできません。これは、暗号化キーを紛失した場合、オブジェクトが失われることを意味します。

S3 レプリケーションは、SSE-C で暗号化されたオブジェクトをサポートします。暗号化されたオブジェクトのレプリケーションの詳細については、「サーバー側の暗号化 (SSE-C、SSE-S3、SSE-KMS、DSSE-KMS) で作成されたオブジェクトをレプリケートする」を参照してください。

SSE-C の詳細については、以下のトピックを参照してください。

SSE−C の概要

このセクションでは、SSE-C の概要を示します。SSE-C を使用する際は、以下の考慮事項に注意してください。

  • HTTPS を使用する必要があります。

    重要

    SSE−C を使用する場合、Amazon S3 は HTTP 経由で行われたリクエストをすべて拒否します。セキュリティ上の考慮事項として、誤って HTTP で送信されたキーは漏洩したと見なすことをお勧めします。キーを破棄して、必要に応じて更新してください。

  • レスポンスのエンティティタグ (ETag) はオブジェクトデータの MD5 ハッシュではありません。

  • 使用した暗号化キーと暗号化したオブジェクトのマッピングは、お客様に管理していただきます。Amazon S3 では暗号化キーを保存しません。どのオブジェクトにどの暗号化キーを使用したかは、お客様が管理してください。

    • バケットのバージョニングが有効になっている場合、この機能を使用してアップロードする各オブジェクトバージョンに、独自の暗号化キーを使用できます。どのオブジェクトバージョンにどの暗号化キーを使用したかは、お客様が管理してください。

    • クライアント側の暗号化キーはお客様が管理するため、キーの更新など、クライアント側での追加の安全対策はお客様に管理していただきます。

    警告

    暗号化キーを紛失した場合、暗号化キーを使用せずにオブジェクトに対して GET リクエストを実行すると失敗し、オブジェクトは失われます。

SSE-C の要件と制限

特定の Amazon S3 バケット内のすべてのオブジェクトの SSE-C を要求するには、バケットポリシーを使用できます。

例えば、次のバケットポリシーは、SSE-C を要求する x-amz-server-side-encryption-customer-algorithm ヘッダーを含まないすべてのリクエストに対して、オブジェクトのアップロード (s3:PutObject) 許可を拒否します。

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

特定の Amazon S3 バケット内のすべてのオブジェクトのサーバー側の暗号化を制限する場合も、ポリシーを使用できます。例えば、SSE-C を要求する x-amz-server-side-encryption-customer-algorithm ヘッダーがリクエストに含まれている場合、次のバケットポリシーはすべてのユーザーに対し、オブジェクト (s3:PutObject) をアップロードするアクセス許可を拒否します。

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

バケットポリシーを使用して s3:PutObject に対する SSE-C を要求する場合は、すべてのマルチパートアップロードリクエスト (CreateMultiPartUpload、UploadPart、CompleteMultipartUpload) に x-amz-server-side-encryption-customer-algorithm ヘッダーを含める必要があります。

署名済み URL および SSE−C

新しいオブジェクトのアップロード、既存のオブジェクトやオブジェクトメタデータの取得などのオペレーションに使用できる署名付き URL を生成できます。署名付き URL では、次のように SSE−C がサポートされます。

  • 署名付き URL を作成するときに、署名の計算で x-amz-server-side​-encryption​-customer-algorithm ヘッダーを使用してアルゴリズムを指定する必要があります。

  • 署名付き URL を使用して新しいオブジェクトをアップロードするとき、既存のオブジェクトを取得するとき、またはオブジェクトメタデータのみを取得するときに、クライアントアプリケーションのリクエストですべての暗号化ヘッダーを指定する必要があります。

    注記

    SSE−C 以外のオブジェクトでは、署名付き URL を生成し、その URL をブラウザに直接貼り付けることで、データにアクセスできます。

    ただし、これは SSE−C オブジェクトには行えません。署名付き URL に加えて SSE−C オブジェクトに固有の HTTP ヘッダーも含める必要があります。したがって、SSE−C オブジェクトの署名付き URL はプログラムでのみ使用できます。

署名付き URL の詳細については、「署名付き URL の使用」を参照してください。

お客様が用意したキーによるサーバー側の暗号化 (SSE−C) の指定

REST API を使用したオブジェクトの作成時に、お客様が用意したキー (SSE−C) を使用してサーバー側の暗号化を指定できます。SSE−C を使用する場合は、次のリクエストヘッダーを使用して暗号化キー情報を指定する必要があります。

名前 説明
x-amz-server-side​-encryption​-customer-algorithm

暗号化アルゴリズムを指定するには、このヘッダーを使用します。ヘッダーの値は AES256 である必要があります。

x-amz-server-side​-encryption​-customer-key

Amazon S3 でデータを暗号化または復号するために使用する base64 でエンコードされた 256 ビットの暗号化キーを指定するには、このヘッダーを使用します。

x-amz-server-side​-encryption​-customer-key-MD5

RFC 1321 に従って、暗号化キーの base64 エンコードされた 128 ビット MD5 ダイジェストを指定するには、このヘッダーを使用します。Amazon S3 では、このヘッダーを使用してメッセージの整合性を調べて、送信された暗号化キーにエラーがないことを確認します。

AWS SDK ラッパーライブラリを使用して、これらのヘッダーをリクエストに追加できます。必要に応じて、アプリケーションから直接 Amazon S3 REST API を呼び出すことができます。

注記

Amazon S3 コンソールを使用してオブジェクトをアップロードしたり SSE−C をリクエストしたりすることはできません。また、SSE−C を使用して保存されている既存のオブジェクトを更新すること (ストレージクラスの変更やメタデータの追加など) もできません。

SSE−C をサポートする Amazon S3 REST API

次の Amazon S3 API は、お客様が用意した暗号化キー (SSE−C) を使用したサーバー側の暗号化をサポートします。

  • GET オペレーション — GET API (GET Object を参照) を使用してオブジェクトを取得するときに、このリクエストヘッダーを指定できます。

  • HEAD オペレーション — HEAD API (HEAD Object を参照) を使用してオブジェクトメタデータを取得するには、これらのリクエストヘッダーを指定できます。

  • PUT オペレーション — PUT API (PUT Object を参照) を使用してデータをアップロードするときに、これらのリクエストヘッダーを指定できます。

  • マルチパートアップロード — マルチパートアップロード API を使用して大きいオブジェクトをアップロードするときに、これらのヘッダーを指定できます。これらのヘッダーは、開始リクエスト (Initiate Multipart Upload を参照) と、後続の各パートのアップロードリクエスト (Upload Part または Upload Part - Copy を参照) で指定します。各パートのアップロードリクエストでは、暗号化情報がマルチパートアップロードの開始リクエストで指定した情報と同じである必要があります。

  • POST オペレーション — POST オペレーションを使用してオブジェクトをアップロードする場合は (POST Object を参照)、リクエストヘッダーの代わりに、フォームフィールドで同じ情報を指定します。

  • Copy オペレーション — オブジェクトをコピーする場合 (PUT Object − Copy を参照)、ソースオブジェクトとターゲットオブジェクトがあります。

    • AWS 管理のキーによるサーバー側の暗号化を使用してターゲットオブジェクトを暗号化する場合は、x-amz-server-side​-encryption リクエストヘッダーを指定する必要があります。

    • SSE−C を使用してターゲットオブジェクトを暗号化する場合は、前の表で説明した 3 つのヘッダーを使用して暗号化情報を指定する必要があります。

    • ソースオブジェクトが SSE−C を使用して暗号化されている場合、Amazon S3 でオブジェクトを復号してコピーできるように、次のヘッダーを使用して暗号化キーの情報を指定する必要があります。

      名前 説明
      x-amz-copy-source​-server-side​-encryption​-customer-algorithm

      Amazon S3 でソースオブジェクトを復号するために使用するアルゴリズムを指定するには、このヘッダーを含めます。この値は、AES256 である必要があります。

      x-amz-copy-source​-server-side​-encryption​-customer-key

      Amazon S3 でソースオブジェクトを復号するために使用する base64 でエンコードされた暗号化キーを指定するには、このヘッダーを含めます。この暗号化キーは、Amazon S3 でソースオブジェクトを作成したときに指定したキーであることが必要です。それ以外の場合、Amazon S3 でオブジェクトを復号できません。

      x-amz-copy-source-​server-side​-encryption​-customer-key-MD5

      RFC 1321 に従って、暗号化キーの base64 エンコードされた 128 ビット MD5 ダイジェストを指定するには、このヘッダーを含めます。

次の例では、お客様が用意したキーによるサーバー側の暗号化 (SSE−C) をオブジェクト用にリクエストする方法を示します。この例では、次の操作を実行します。各オペレーションでは、SSE−C 関連ヘッダーをリクエストで指定する方法を示します。

  • Put object — オブジェクトをアップロードし、顧客が用意した暗号キーによるサーバー側の暗号化をリクエストします。

  • Get object — 前のステップでアップロードしたオブジェクトをダウンロードします。リクエストでは、オブジェクトのアップロード時に指定したのと同じ暗号化情報を提供します。Amazon S3 は、オブジェクトを復号して返すために、この情報を必要とします。

  • Get object metadata — オブジェクトのメタデータを取得します。オブジェクトの作成時に使用したのと同じ暗号化情報を指定します。

  • Copy object — 以前にアップロードしたオブジェクトのコピーを作成します。ソースオブジェクトは SSE−C を使用して保存されるため、コピーリクエストで暗号化情報を指定する必要があります。デフォルトでは、明示的にリクエストした場合に限り、Amazon S3 はオブジェクトのコピーを暗号化します。この例では、オブジェクトの暗号化されたコピーを保存するように Amazon S3 に指示します。

Java
注記

この例では、1 つのオペレーションでオブジェクトをアップロードする方法を示します。マルチパートアップロード API を使用して大きなオブジェクトをアップロードする場合は、この例に示したのと同じ方法で暗号化情報を指定します。AWS SDK for Java を使用するマルチパートアップロードの例については、マルチパートアップロードを使用したオブジェクトのアップロード を参照してください。

必要な暗号化情報を追加するには、リクエストに SSECustomerKey を含めます。SSECustomerKey クラスの詳細については、REST API」セクションを参照してください。

SSE−C の詳細については、お客様が指定したキーによるサーバー側の暗号化 (SSE−C) の使用 を参照してください。ワーキングサンプルの作成とテストに関する手順については、Amazon S3 Java コード例のテスト を参照してください。

import com.amazonaws.AmazonServiceException; import com.amazonaws.SdkClientException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.*; import javax.crypto.KeyGenerator; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class ServerSideEncryptionUsingClientSideEncryptionKey { private static SSECustomerKey SSE_KEY; private static AmazonS3 S3_CLIENT; private static KeyGenerator KEY_GENERATOR; public static void main(String[] args) throws IOException, NoSuchAlgorithmException { Regions clientRegion = Regions.DEFAULT_REGION; String bucketName = "*** Bucket name ***"; String keyName = "*** Key name ***"; String uploadFileName = "*** File path ***"; String targetKeyName = "*** Target key name ***"; // Create an encryption key. KEY_GENERATOR = KeyGenerator.getInstance("AES"); KEY_GENERATOR.init(256, new SecureRandom()); SSE_KEY = new SSECustomerKey(KEY_GENERATOR.generateKey()); try { S3_CLIENT = AmazonS3ClientBuilder.standard() .withCredentials(new ProfileCredentialsProvider()) .withRegion(clientRegion) .build(); // Upload an object. uploadObject(bucketName, keyName, new File(uploadFileName)); // Download the object. downloadObject(bucketName, keyName); // Verify that the object is properly encrypted by attempting to retrieve it // using the encryption key. retrieveObjectMetadata(bucketName, keyName); // Copy the object into a new object that also uses SSE-C. copyObject(bucketName, keyName, targetKeyName); } catch (AmazonServiceException e) { // The call was transmitted successfully, but Amazon S3 couldn't process // it, so it returned an error response. e.printStackTrace(); } catch (SdkClientException e) { // Amazon S3 couldn't be contacted for a response, or the client // couldn't parse the response from Amazon S3. e.printStackTrace(); } } private static void uploadObject(String bucketName, String keyName, File file) { PutObjectRequest putRequest = new PutObjectRequest(bucketName, keyName, file).withSSECustomerKey(SSE_KEY); S3_CLIENT.putObject(putRequest); System.out.println("Object uploaded"); } private static void downloadObject(String bucketName, String keyName) throws IOException { GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, keyName).withSSECustomerKey(SSE_KEY); S3Object object = S3_CLIENT.getObject(getObjectRequest); System.out.println("Object content: "); displayTextInputStream(object.getObjectContent()); } private static void retrieveObjectMetadata(String bucketName, String keyName) { GetObjectMetadataRequest getMetadataRequest = new GetObjectMetadataRequest(bucketName, keyName) .withSSECustomerKey(SSE_KEY); ObjectMetadata objectMetadata = S3_CLIENT.getObjectMetadata(getMetadataRequest); System.out.println("Metadata retrieved. Object size: " + objectMetadata.getContentLength()); } private static void copyObject(String bucketName, String keyName, String targetKeyName) throws NoSuchAlgorithmException { // Create a new encryption key for target so that the target is saved using // SSE-C. SSECustomerKey newSSEKey = new SSECustomerKey(KEY_GENERATOR.generateKey()); CopyObjectRequest copyRequest = new CopyObjectRequest(bucketName, keyName, bucketName, targetKeyName) .withSourceSSECustomerKey(SSE_KEY) .withDestinationSSECustomerKey(newSSEKey); S3_CLIENT.copyObject(copyRequest); System.out.println("Object copied"); } private static void displayTextInputStream(S3ObjectInputStream input) throws IOException { // Read one line at a time from the input stream and display each line. BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } System.out.println(); } }
.NET
注記

マルチパートアップロード API を使用した大きなオブジェクトのアップロードの例については、マルチパートアップロードを使用したオブジェクトのアップロード および AWS SDK の使用 (低レベル API) を参照してください。

SSE−C の詳細については、お客様が指定したキーによるサーバー側の暗号化 (SSE−C) の使用 を参照してください。作業サンプルの作成およびテストについては、Amazon S3 .NET コード例の実行 を参照してください。

using Amazon; using Amazon.S3; using Amazon.S3.Model; using System; using System.IO; using System.Security.Cryptography; using System.Threading.Tasks; namespace Amazon.DocSamples.S3 { class SSEClientEncryptionKeyObjectOperationsTest { private const string bucketName = "*** bucket name ***"; private const string keyName = "*** key name for new object created ***"; private const string copyTargetKeyName = "*** key name for object copy ***"; // Specify your bucket region (an example region is shown). private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2; private static IAmazonS3 client; public static void Main() { client = new AmazonS3Client(bucketRegion); ObjectOpsUsingClientEncryptionKeyAsync().Wait(); } private static async Task ObjectOpsUsingClientEncryptionKeyAsync() { try { // Create an encryption key. Aes aesEncryption = Aes.Create(); aesEncryption.KeySize = 256; aesEncryption.GenerateKey(); string base64Key = Convert.ToBase64String(aesEncryption.Key); // 1. Upload the object. PutObjectRequest putObjectRequest = await UploadObjectAsync(base64Key); // 2. Download the object and verify that its contents matches what you uploaded. await DownloadObjectAsync(base64Key, putObjectRequest); // 3. Get object metadata and verify that the object uses AES-256 encryption. await GetObjectMetadataAsync(base64Key); // 4. Copy both the source and target objects using server-side encryption with // a customer-provided encryption key. await CopyObjectAsync(aesEncryption, base64Key); } catch (AmazonS3Exception e) { Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message); } catch (Exception e) { Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message); } } private static async Task<PutObjectRequest> UploadObjectAsync(string base64Key) { PutObjectRequest putObjectRequest = new PutObjectRequest { BucketName = bucketName, Key = keyName, ContentBody = "sample text", ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; PutObjectResponse putObjectResponse = await client.PutObjectAsync(putObjectRequest); return putObjectRequest; } private static async Task DownloadObjectAsync(string base64Key, PutObjectRequest putObjectRequest) { GetObjectRequest getObjectRequest = new GetObjectRequest { BucketName = bucketName, Key = keyName, // Provide encryption information for the object stored in Amazon S3. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; using (GetObjectResponse getResponse = await client.GetObjectAsync(getObjectRequest)) using (StreamReader reader = new StreamReader(getResponse.ResponseStream)) { string content = reader.ReadToEnd(); if (String.Compare(putObjectRequest.ContentBody, content) == 0) Console.WriteLine("Object content is same as we uploaded"); else Console.WriteLine("Error...Object content is not same."); if (getResponse.ServerSideEncryptionCustomerMethod == ServerSideEncryptionCustomerMethod.AES256) Console.WriteLine("Object encryption method is AES256, same as we set"); else Console.WriteLine("Error...Object encryption method is not the same as AES256 we set"); // Assert.AreEqual(putObjectRequest.ContentBody, content); // Assert.AreEqual(ServerSideEncryptionCustomerMethod.AES256, getResponse.ServerSideEncryptionCustomerMethod); } } private static async Task GetObjectMetadataAsync(string base64Key) { GetObjectMetadataRequest getObjectMetadataRequest = new GetObjectMetadataRequest { BucketName = bucketName, Key = keyName, // The object stored in Amazon S3 is encrypted, so provide the necessary encryption information. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; GetObjectMetadataResponse getObjectMetadataResponse = await client.GetObjectMetadataAsync(getObjectMetadataRequest); Console.WriteLine("The object metadata show encryption method used is: {0}", getObjectMetadataResponse.ServerSideEncryptionCustomerMethod); // Assert.AreEqual(ServerSideEncryptionCustomerMethod.AES256, getObjectMetadataResponse.ServerSideEncryptionCustomerMethod); } private static async Task CopyObjectAsync(Aes aesEncryption, string base64Key) { aesEncryption.GenerateKey(); string copyBase64Key = Convert.ToBase64String(aesEncryption.Key); CopyObjectRequest copyRequest = new CopyObjectRequest { SourceBucket = bucketName, SourceKey = keyName, DestinationBucket = bucketName, DestinationKey = copyTargetKeyName, // Information about the source object's encryption. CopySourceServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, CopySourceServerSideEncryptionCustomerProvidedKey = base64Key, // Information about the target object's encryption. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = copyBase64Key }; await client.CopyObjectAsync(copyRequest); } } }

前のセクションの例では、PUT、GET、Head、および COPY オペレーションで、お客様が用意したキーによるサーバー側の暗号化 (SSE−C) をリクエストする方法を示しています。このセクションでは、SSE−C をサポートするその他の Amazon S3 API について説明します。

Java

大きなオブジェクトをアップロードするために、マルチパートアップロード API を使用できます (マルチパートアップロードを使用したオブジェクトのアップロードとコピー を参照)。高レベル API または低レベル API を使用して、大きなオブジェクトをアップロードできます。これらの API は、リクエストでの暗号化関連のヘッダーをサポートします。

  • 高レベルの TransferManager API を使用する場合は、PutObjectRequest で暗号化専用のヘッダーを指定します (「マルチパートアップロードを使用したオブジェクトのアップロード」を参照)。

  • 低レベル API を使用する場合は、暗号化関連情報を InitiateMultipartUploadRequest で指定し、続けて各 UploadPartRequest で同じ暗号化情報を指定します。CompleteMultipartUploadRequest で暗号化専用のヘッダーを指定する必要はありません。例については、AWS SDK の使用 (低レベル API) を参照してください。

次の例では、TransferManager を使用してオブジェクトを作成し、SSE−C 関連の情報を提供する方法を示します。この例では、次のような処理を実行します。

  • TransferManager.upload() メソッドを使用してオブジェクトを作成します。PutObjectRequest インスタンスで、リクエストする暗号キーの情報を指定します。Amazon S3 は、お客様が用意したキーを使用してオブジェクトを暗号化します。

  • TransferManager.copy() メソッドを呼び出してオブジェクトのコピーを作成します。この例では、新しい SSECustomerKey を使用してオブジェクトのコピーを暗号化するように Amazon S3 に指示します。ソースオブジェクトは SSE−C で暗号化されているため、CopyObjectRequest はソースオブジェクトの暗号化キーを提供し、Amazon S3 で復号してからコピーできるようにします。

import com.amazonaws.AmazonServiceException; import com.amazonaws.SdkClientException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.CopyObjectRequest; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.SSECustomerKey; import com.amazonaws.services.s3.transfer.Copy; import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.TransferManagerBuilder; import com.amazonaws.services.s3.transfer.Upload; import javax.crypto.KeyGenerator; import java.io.File; import java.security.SecureRandom; public class ServerSideEncryptionCopyObjectUsingHLwithSSEC { public static void main(String[] args) throws Exception { Regions clientRegion = Regions.DEFAULT_REGION; String bucketName = "*** Bucket name ***"; String fileToUpload = "*** File path ***"; String keyName = "*** New object key name ***"; String targetKeyName = "*** Key name for object copy ***"; try { AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withRegion(clientRegion) .withCredentials(new ProfileCredentialsProvider()) .build(); TransferManager tm = TransferManagerBuilder.standard() .withS3Client(s3Client) .build(); // Create an object from a file. PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, new File(fileToUpload)); // Create an encryption key. KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(256, new SecureRandom()); SSECustomerKey sseCustomerEncryptionKey = new SSECustomerKey(keyGenerator.generateKey()); // Upload the object. TransferManager uploads asynchronously, so this call // returns immediately. putObjectRequest.setSSECustomerKey(sseCustomerEncryptionKey); Upload upload = tm.upload(putObjectRequest); // Optionally, wait for the upload to finish before continuing. upload.waitForCompletion(); System.out.println("Object created."); // Copy the object and store the copy using SSE-C with a new key. CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucketName, keyName, bucketName, targetKeyName); SSECustomerKey sseTargetObjectEncryptionKey = new SSECustomerKey(keyGenerator.generateKey()); copyObjectRequest.setSourceSSECustomerKey(sseCustomerEncryptionKey); copyObjectRequest.setDestinationSSECustomerKey(sseTargetObjectEncryptionKey); // Copy the object. TransferManager copies asynchronously, so this call returns // immediately. Copy copy = tm.copy(copyObjectRequest); // Optionally, wait for the upload to finish before continuing. copy.waitForCompletion(); System.out.println("Copy complete."); } catch (AmazonServiceException e) { // The call was transmitted successfully, but Amazon S3 couldn't process // it, so it returned an error response. e.printStackTrace(); } catch (SdkClientException e) { // Amazon S3 couldn't be contacted for a response, or the client // couldn't parse the response from Amazon S3. e.printStackTrace(); } } }
.NET

大きなオブジェクトをアップロードするために、マルチパートアップロード API を使用できます (「マルチパートアップロードを使用したオブジェクトのアップロードとコピー」を参照)。AWSSDK for .NET には、大きなオブジェクトをアップロードするため、高レベルおよび低レベルの両方の API が用意されています。これらの API は、リクエストでの暗号化関連のヘッダーをサポートします。

  • 高レベルの Transfer-Utility API を使用するときには、次に示すように TransferUtilityUploadRequest で暗号化固有のヘッダーを提供します。コード例については、マルチパートアップロードを使用したオブジェクトのアップロード を参照してください。

    TransferUtilityUploadRequest request = new TransferUtilityUploadRequest() { FilePath = filePath, BucketName = existingBucketName, Key = keyName, // Provide encryption information. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key, };
  • 低レベル API を使用する場合は、マルチパートアップロードの開始リクエストで暗号化関連情報を提供し、以降のパートのアップロードリクエストでは同じ暗号化情報を提供します。マルチパートアップロードの完了リクエストでは、暗号化固有のヘッダーを提供する必要はありません。例については、AWS SDK の使用 (低レベル API) を参照してください。

    既存の大きなオブジェクトをコピーする低レベルのマルチパートアップロードの例を次に示します。この例では、コピーされるオブジェクトは SSE−C を使用して Amazon S3 に保存されており、ターゲットオブジェクトも SSE−C を使用して保存します。例えば、以下を実行します。

    • 暗号化キーと関連情報を提供することによって、マルチパートアップロードのリクエストを開始します。

    • CopyPartRequest でソースオブジェクトとターゲットオブジェクトの暗号化キーを提供します。

    • オブジェクトメタデータを取得することによって、コピーされるソースオブジェクトのサイズを取得します。

    • 5 MB のパート単位でオブジェクトをアップロードします。

    using Amazon; using Amazon.S3; using Amazon.S3.Model; using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Threading.Tasks; namespace Amazon.DocSamples.S3 { class SSECLowLevelMPUcopyObjectTest { private const string existingBucketName = "*** bucket name ***"; private const string sourceKeyName = "*** source object key name ***"; private const string targetKeyName = "*** key name for the target object ***"; private const string filePath = @"*** file path ***"; // Specify your bucket region (an example region is shown). private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2; private static IAmazonS3 s3Client; static void Main() { s3Client = new AmazonS3Client(bucketRegion); CopyObjClientEncryptionKeyAsync().Wait(); } private static async Task CopyObjClientEncryptionKeyAsync() { Aes aesEncryption = Aes.Create(); aesEncryption.KeySize = 256; aesEncryption.GenerateKey(); string base64Key = Convert.ToBase64String(aesEncryption.Key); await CreateSampleObjUsingClientEncryptionKeyAsync(base64Key, s3Client); await CopyObjectAsync(s3Client, base64Key); } private static async Task CopyObjectAsync(IAmazonS3 s3Client, string base64Key) { List<CopyPartResponse> uploadResponses = new List<CopyPartResponse>(); // 1. Initialize. InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest { BucketName = existingBucketName, Key = targetKeyName, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key, }; InitiateMultipartUploadResponse initResponse = await s3Client.InitiateMultipartUploadAsync(initiateRequest); // 2. Upload Parts. long partSize = 5 * (long)Math.Pow(2, 20); // 5 MB long firstByte = 0; long lastByte = partSize; try { // First find source object size. Because object is stored encrypted with // customer provided key you need to provide encryption information in your request. GetObjectMetadataRequest getObjectMetadataRequest = new GetObjectMetadataRequest() { BucketName = existingBucketName, Key = sourceKeyName, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key // " * **source object encryption key ***" }; GetObjectMetadataResponse getObjectMetadataResponse = await s3Client.GetObjectMetadataAsync(getObjectMetadataRequest); long filePosition = 0; for (int i = 1; filePosition < getObjectMetadataResponse.ContentLength; i++) { CopyPartRequest copyPartRequest = new CopyPartRequest { UploadId = initResponse.UploadId, // Source. SourceBucket = existingBucketName, SourceKey = sourceKeyName, // Source object is stored using SSE-C. Provide encryption information. CopySourceServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, CopySourceServerSideEncryptionCustomerProvidedKey = base64Key, //"***source object encryption key ***", FirstByte = firstByte, // If the last part is smaller then our normal part size then use the remaining size. LastByte = lastByte > getObjectMetadataResponse.ContentLength ? getObjectMetadataResponse.ContentLength - 1 : lastByte, // Target. DestinationBucket = existingBucketName, DestinationKey = targetKeyName, PartNumber = i, // Encryption information for the target object. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; uploadResponses.Add(await s3Client.CopyPartAsync(copyPartRequest)); filePosition += partSize; firstByte += partSize; lastByte += partSize; } // Step 3: complete. CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest { BucketName = existingBucketName, Key = targetKeyName, UploadId = initResponse.UploadId, }; completeRequest.AddPartETags(uploadResponses); CompleteMultipartUploadResponse completeUploadResponse = await s3Client.CompleteMultipartUploadAsync(completeRequest); } catch (Exception exception) { Console.WriteLine("Exception occurred: {0}", exception.Message); AbortMultipartUploadRequest abortMPURequest = new AbortMultipartUploadRequest { BucketName = existingBucketName, Key = targetKeyName, UploadId = initResponse.UploadId }; s3Client.AbortMultipartUpload(abortMPURequest); } } private static async Task CreateSampleObjUsingClientEncryptionKeyAsync(string base64Key, IAmazonS3 s3Client) { // List to store upload part responses. List<UploadPartResponse> uploadResponses = new List<UploadPartResponse>(); // 1. Initialize. InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest { BucketName = existingBucketName, Key = sourceKeyName, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; InitiateMultipartUploadResponse initResponse = await s3Client.InitiateMultipartUploadAsync(initiateRequest); // 2. Upload Parts. long contentLength = new FileInfo(filePath).Length; long partSize = 5 * (long)Math.Pow(2, 20); // 5 MB try { long filePosition = 0; for (int i = 1; filePosition < contentLength; i++) { UploadPartRequest uploadRequest = new UploadPartRequest { BucketName = existingBucketName, Key = sourceKeyName, UploadId = initResponse.UploadId, PartNumber = i, PartSize = partSize, FilePosition = filePosition, FilePath = filePath, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; // Upload part and add response to our list. uploadResponses.Add(await s3Client.UploadPartAsync(uploadRequest)); filePosition += partSize; } // Step 3: complete. CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest { BucketName = existingBucketName, Key = sourceKeyName, UploadId = initResponse.UploadId, //PartETags = new List<PartETag>(uploadResponses) }; completeRequest.AddPartETags(uploadResponses); CompleteMultipartUploadResponse completeUploadResponse = await s3Client.CompleteMultipartUploadAsync(completeRequest); } catch (Exception exception) { Console.WriteLine("Exception occurred: {0}", exception.Message); AbortMultipartUploadRequest abortMPURequest = new AbortMultipartUploadRequest { BucketName = existingBucketName, Key = sourceKeyName, UploadId = initResponse.UploadId }; await s3Client.AbortMultipartUploadAsync(abortMPURequest); } } } }