指定 Amazon S3 加密 - Amazon Simple Storage Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

指定 Amazon S3 加密

创建对象时,您可以指定使用具有 Amazon S3 托管加密密钥的服务器端加密来加密您的数据。当您要上传新对象或复制现有对象时,也是这种情况。这种加密称为 SSE-S3。

您可以使用 S3 控制台、REST API、Amazon 软件开发工具包和 Amazon CLI 指定 SSE-S3。有关更多信息,请参阅以下主题。

有关如何复制未加密对象的示例,请参阅 复制对象

本主题介绍如何使用 Amazon Web Services Management Console设置或更改对象的加密类型。使用控制台复制对象时,控制台将按原样复制对象。如果源被加密,则目标对象也会被加密。控制台还允许您添加或更改对象的加密。

注意

如果更改对象的加密,则会创建一个新对象来替换旧对象。如果启用 S3 版本控制,则会创建对象的新版本,而现有对象将变为旧版本。更改属性的角色也会成为新对象或(对象版本)的拥有者。

添加或更改对象的加密
  1. 登录到 Amazon Web Services Management Console,然后通过以下网址打开 Amazon S3 控制台:https://console.aws.amazon.com/s3/

  2. Bucket(存储桶) 列表中,请选择包含对象的存储桶的名称。

  3. Objects(对象) 列表中,请选择要为其添加或更改加密的对象的名称。

    Object overview(对象概述)随即打开,其中显示对象的属性。

  4. Server-side encryption settings (服务器端加密设置) 下,请选择 Edit (编辑)

    Edit server-side encryption (编辑服务器端加密) 页面随即打开。

  5. 要为对象启用服务器端加密,请在 Server-side encryption (服务器端加密) 下选择 Enable (启用)

  6. 要使用 Amazon S3 托管密钥启用服务器端加密,请在 Encryption key type (加密密钥类型) 下,请选择 Amazon S3 key (SSE-S3) (Amazon S3 密钥 (SSE-S3))

    有关使用 Amazon S3 服务器端加密对数据进行加密的更多信息,请参阅 使用具有 Amazon S3 托管式加密密钥的服务器端加密(SSE-S3)

  7. 选择保存更改

注意

此操作将加密应用于所有指定的对象。加密文件夹时,请等待保存操作完成,然后再将新对象添加到文件夹。

创建对象时(即,上传新对象或复制现有对象时),您可以通过为请求添加 x-amz-server-side-encryption 标头来指定您是否希望 Amazon S3 加密您的数据。将标头的值设置为 Amazon S3 支持的加密算法 AES256。通过返回响应标头 x-amz-server-side-encryption,Amazon S3 确认已使用服务器端加密存储了您的数据元。

以下 REST 上传 API 接受 x-amz-server-side-encryption 请求标题。

使用分段上传 API 上传大型对象时,您可以通过为启动分段上传请求添加 x-amz-server-side-encryption 标头来指定服务器端加密。复制现有对象时,不论源对象是否已经加密,都不会加密目标对象,除非您显式请求服务器端加密。

使用服务器端加密存储对象后,以下 REST API 的响应标头将返回 x-amz-server-side-encryption 标头。

注意

如果对象使用 SSE-S3,则不应对 GET 请求和 HEAD 请求发送加密请求标头,否则将出现 HTTP 400 BadRequest 错误。

使用 Amazon 软件开发工具包时,您可以请求 Amazon S3 使用 Amazon S3 托管式加密密钥。这部分提供了以多种语言使用 Amazon 软件开发工具包的示例。有关其他 SDK 的信息,请转到示例代码和库

Java

当您使用 Amazon SDK for Java 上传对象时,可以使用服务器端加密为对象加密。要请求服务器端加密,请使用 ObjectMetadataPutObjectRequest 属性设置 x-amz-server-side-encryption 请求标头。当您调用 AmazonS3ClientputObject() 方法时,Amazon S3 将加密并保存数据。

当使用分段上传 API 上传对象时,还可以请求服务器端加密:

  • 使用高级别分段上传 API 时,请在上传对象时使用 TransferManager 方法将服务器端加密应用于对象。可以使用将 ObjectMetadata 视为参数的任一上传方法。有关更多信息,请参阅使用分段上传上传对象

  • 当使用低级别分段上传 API 时,应在启动分段上传时指定服务器端加密。您通过调用 ObjectMetadata 方法添加 InitiateMultipartUploadRequest.setObjectMetadata() 属性。有关更多信息,请参阅使用 Amazon 软件开发工具包(低级别 API)

不能直接更改对象的加密状态 (加密未加密的对象或解密已加密的对象)。要更改对象的加密状态,请为对象创建一个副本,从而为副本指定所需的加密状态,然后删除原始对象。仅当您显式请求服务器端加密时,Amazon S3 才会加密复制的对象。要通过 Java API 请求加密复制的对象,请使用 ObjectMetadata 属性在 CopyObjectRequest 中指定服务器端加密。

例 示例

以下示例演示如何使用 Amazon SDK for Java 设置服务器端加密。它展示了如何执行以下任务:

  • 使用服务器端加密上传新对象。

  • 通过为对象创建副本来更改对象的加密状态 (本示例中为加密之前未加密的对象)。

  • 检查对象的加密状态。

有关服务器端加密的更多信息,请参阅 使用 REST API。有关创建和测试有效示例的说明,请参阅 测试 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.internal.SSEResultBase; import com.amazonaws.services.s3.model.*; import java.io.ByteArrayInputStream; public class SpecifyServerSideEncryption { public static void main(String[] args) { Regions clientRegion = Regions.DEFAULT_REGION; String bucketName = "*** Bucket name ***"; String keyNameToEncrypt = "*** Key name for an object to upload and encrypt ***"; String keyNameToCopyAndEncrypt = "*** Key name for an unencrypted object to be encrypted by copying ***"; String copiedObjectKeyName = "*** Key name for the encrypted copy of the unencrypted object ***"; try { AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withRegion(clientRegion) .withCredentials(new ProfileCredentialsProvider()) .build(); // Upload an object and encrypt it with SSE. uploadObjectWithSSEEncryption(s3Client, bucketName, keyNameToEncrypt); // Upload a new unencrypted object, then change its encryption state // to encrypted by making a copy. changeSSEEncryptionStatusByCopying(s3Client, bucketName, keyNameToCopyAndEncrypt, copiedObjectKeyName); } 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 uploadObjectWithSSEEncryption(AmazonS3 s3Client, String bucketName, String keyName) { String objectContent = "Test object encrypted with SSE"; byte[] objectBytes = objectContent.getBytes(); // Specify server-side encryption. ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentLength(objectBytes.length); objectMetadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION); PutObjectRequest putRequest = new PutObjectRequest(bucketName, keyName, new ByteArrayInputStream(objectBytes), objectMetadata); // Upload the object and check its encryption status. PutObjectResult putResult = s3Client.putObject(putRequest); System.out.println("Object \"" + keyName + "\" uploaded with SSE."); printEncryptionStatus(putResult); } private static void changeSSEEncryptionStatusByCopying(AmazonS3 s3Client, String bucketName, String sourceKey, String destKey) { // Upload a new, unencrypted object. PutObjectResult putResult = s3Client.putObject(bucketName, sourceKey, "Object example to encrypt by copying"); System.out.println("Unencrypted object \"" + sourceKey + "\" uploaded."); printEncryptionStatus(putResult); // Make a copy of the object and use server-side encryption when storing the copy. CopyObjectRequest request = new CopyObjectRequest(bucketName, sourceKey, bucketName, destKey); ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION); request.setNewObjectMetadata(objectMetadata); // Perform the copy operation and display the copy's encryption status. CopyObjectResult response = s3Client.copyObject(request); System.out.println("Object \"" + destKey + "\" uploaded with SSE."); printEncryptionStatus(response); // Delete the original, unencrypted object, leaving only the encrypted copy in Amazon S3. s3Client.deleteObject(bucketName, sourceKey); System.out.println("Unencrypted object \"" + sourceKey + "\" deleted."); } private static void printEncryptionStatus(SSEResultBase response) { String encryptionStatus = response.getSSEAlgorithm(); if (encryptionStatus == null) { encryptionStatus = "Not encrypted with SSE"; } System.out.println("Object encryption status is: " + encryptionStatus); } }
.NET

在上传对象时,可指示 Amazon S3 加密对象。要更改现有对象的加密状态,请复制该对象并删除源对象。默认情况下,仅当您显式请求目标对象的服务器端加密时,复制操作才会加密目标。要在 CopyObjectRequest 中指定服务器端加密,请添加以下命令:

ServerSideEncryptionMethod = ServerSideEncryptionMethod.AES256

有关如何复制对象的有效示例,请参阅 使用 Amazon 软件开发工具包

以下示例将上传对象。在请求中,该示例指示 Amazon S3 加密对象。该示例随后检索对象元数据并验证使用的加密方法。有关创建和测试有效示例的信息,请参阅 运行 Amazon S3 .NET 代码示例

using Amazon; using Amazon.S3; using Amazon.S3.Model; using System; using System.Threading.Tasks; namespace Amazon.DocSamples.S3 { class SpecifyServerSideEncryptionTest { private const string bucketName = "*** bucket name ***"; private const string keyName = "*** key name for object created ***"; // 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); WritingAnObjectAsync().Wait(); } static async Task WritingAnObjectAsync() { try { var putRequest = new PutObjectRequest { BucketName = bucketName, Key = keyName, ContentBody = "sample text", ServerSideEncryptionMethod = ServerSideEncryptionMethod.AES256 }; var putResponse = await client.PutObjectAsync(putRequest); // Determine the encryption state of an object. GetObjectMetadataRequest metadataRequest = new GetObjectMetadataRequest { BucketName = bucketName, Key = keyName }; GetObjectMetadataResponse response = await client.GetObjectMetadataAsync(metadataRequest); ServerSideEncryptionMethod objectEncryption = response.ServerSideEncryptionMethod; Console.WriteLine("Encryption method used: {0}", objectEncryption.ToString()); } 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); } } } }
PHP

本主题介绍如何使用 Amazon SDK for PHP 版本 3 中的类来将服务器端加密添加到您上载到 Amazon Simple Storage Service (Amazon S3) 的对象。本主题假定您已按照 使用Amazon SDK for PHP和运行 PHP 示例 的说明执行操作,并正确安装了 Amazon SDK for PHP。

要将对象上传到 Amazon S3,请使用 Aws\S3\S3Client::putObject() 方法。要将 x-amz-server-side-encryption 请求标头添加到您的上传请求,请使用值 ServerSideEncryption 指定 AES256 参数,如以下代码示例中所示。有关服务器端加密请求的信息,请参阅 使用 REST API

require 'vendor/autoload.php'; use Aws\S3\S3Client; $bucket = '*** Your Bucket Name ***'; $keyname = '*** Your Object Key ***'; // $filepath should be an absolute path to a file on disk. $filepath = '*** Your File Path ***'; $s3 = new S3Client([ 'version' => 'latest', 'region' => 'us-east-1' ]); // Upload a file with server-side encryption. $result = $s3->putObject([ 'Bucket' => $bucket, 'Key' => $keyname, 'SourceFile' => $filepath, 'ServerSideEncryption' => 'AES256', ]);

作为响应,Amazon S3 会返回 x-amz-server-side-encryption 标头以及已用于加密对象数据的加密算法的值。

在使用分段上传 API 上传大型对象时,您可以为正在上传的对象指定服务器端加密,如下所示:

要确定现有对象的加密状态,请通过调用 Aws\S3\S3Client::headObject() 方法检索对象元数据,如下面的 PHP 代码示例所示。

require 'vendor/autoload.php'; use Aws\S3\S3Client; $bucket = '*** Your Bucket Name ***'; $keyname = '*** Your Object Key ***'; $s3 = new S3Client([ 'version' => 'latest', 'region' => 'us-east-1' ]); // Check which server-side encryption algorithm is used. $result = $s3->headObject([ 'Bucket' => $bucket, 'Key' => $keyname, ]); echo $result['ServerSideEncryption'];

要更改现有对象的加密状态,请使用 Aws\S3\S3Client::copyObject() 方法复制对象并删除源对象。默认情况下,copyObject() 不会加密目标,除非您通过将值 ServerSideEncryption 用于 AES256 参数,显式请求对目标对象进行服务器端加密。以下 PHP 代码示例将复制对象并向复制的对象添加服务器端加密。

require 'vendor/autoload.php'; use Aws\S3\S3Client; $sourceBucket = '*** Your Source Bucket Name ***'; $sourceKeyname = '*** Your Source Object Key ***'; $targetBucket = '*** Your Target Bucket Name ***'; $targetKeyname = '*** Your Target Object Key ***'; $s3 = new S3Client([ 'version' => 'latest', 'region' => 'us-east-1' ]); // Copy an object and add server-side encryption. $s3->copyObject([ 'Bucket' => $targetBucket, 'Key' => $targetKeyname, 'CopySource' => "{$sourceBucket}/{$sourceKeyname}", 'ServerSideEncryption' => 'AES256', ]);
Ruby

在使用 Amazon SDK for Ruby 上传对象时,您可以指定使用服务器端加密 (SSE) 对存储的对象进行静态加密。在您读回对象时,它将自动解密。

下面的 Amazon SDK for Ruby 版本 3 示例演示了如何指定对上传到 Amazon S3 的文件进行静态加密。

require "aws-sdk-s3" # Wraps Amazon S3 object actions. class ObjectPutSseWrapper attr_reader :object # @param object [Aws::S3::Object] An existing Amazon S3 object. def initialize(object) @object = object end def put_object_encrypted(object_content, encryption) @object.put(body: object_content, server_side_encryption: encryption) true rescue Aws::Errors::ServiceError => e puts "Couldn't put your content to #{object.key}. Here's why: #{e.message}" false end end def run_demo bucket_name = "doc-example-bucket" object_key = "my-encrypted-content" object_content = "This is my super-secret content." encryption = "AES256" wrapper = ObjectPutSseWrapper.new(Aws::S3::Object.new(bucket_name, object_content)) return unless wrapper.put_object_encrypted(object_content, encryption) puts "Put your content into #{bucket_name}:#{object_key} and encrypted it with #{encryption}." end run_demo if $PROGRAM_NAME == __FILE__

有关演示在不使用 SSE 的情况下上传对象的示例,请参阅 上传对象

下面的代码示例演示了如何确定现有对象的加密状态。

require "aws-sdk-s3" # Wraps Amazon S3 object actions. class ObjectGetEncryptionWrapper attr_reader :object # @param object [Aws::S3::Object] An existing Amazon S3 object. def initialize(object) @object = object end # Gets the object into memory. # # @return [Aws::S3::Types::GetObjectOutput, nil] The retrieved object data if successful; otherwise nil. def get_object @object.get rescue Aws::Errors::ServiceError => e puts "Couldn't get object #{@object.key}. Here's why: #{e.message}" end end # Replace bucket name and object key with an existing bucket and object that you own. def run_demo bucket_name = "doc-example-bucket" object_key = "my-object.txt" wrapper = ObjectGetEncryptionWrapper.new(Aws::S3::Object.new(bucket_name, object_key)) obj_data = wrapper.get_object return unless obj_data encryption = obj_data.server_side_encryption.nil? ? "no" : obj_data.server_side_encryption puts "Object #{object_key} uses #{encryption} encryption." end run_demo if $PROGRAM_NAME == __FILE__

如果存储在 Amazon S3 中的对象没有使用服务器端加密,则该方法将返回空值。

要更改现有对象的加密状态,请复制该对象并删除源对象。原定设置情况下,复制方法不会加密目标,除非您明确请求服务器端加密。您可以通过在选项哈希参数中指定 server_side_encryption 值来请求对目标对象进行加密,如下面的 Ruby 代码示例所示。此代码示例演示如何复制对象和加密副本。

require "aws-sdk-s3" # Wraps Amazon S3 object actions. class ObjectCopyEncryptWrapper attr_reader :source_object # @param source_object [Aws::S3::Object] An existing Amazon S3 object. This is used as the source object for # copy actions. def initialize(source_object) @source_object = source_object end # Copy the source object to the specified target bucket, rename it with the target key, and encrypt it. # # @param target_bucket [Aws::S3::Bucket] An existing Amazon S3 bucket where the object is copied. # @param target_object_key [String] The key to give the copy of the object. # @return [Aws::S3::Object, nil] The copied object when successful; otherwise, nil. def copy_object(target_bucket, target_object_key, encryption) @source_object.copy_to(bucket: target_bucket.name, key: target_object_key, server_side_encryption: encryption) target_bucket.object(target_object_key) rescue Aws::Errors::ServiceError => e puts "Couldn't copy #{@source_object.key} to #{target_object_key}. Here's why: #{e.message}" end end # Replace the source and target bucket names with existing buckets you own and replace the source object key # with an existing object in the source bucket. def run_demo source_bucket_name = "doc-example-bucket1" source_key = "my-source-file.txt" target_bucket_name = "doc-example-bucket2" target_key = "my-target-file.txt" target_encryption = "AES256" source_bucket = Aws::S3::Bucket.new(source_bucket_name) wrapper = ObjectCopyEncryptWrapper.new(source_bucket.object(source_key)) target_bucket = Aws::S3::Bucket.new(target_bucket_name) target_object = wrapper.copy_object(target_bucket, target_key, target_encryption) return unless target_object puts "Copied #{source_key} from #{source_bucket_name} to #{target_object.bucket_name}:#{target_object.key} and "\ "encrypted the target with #{target_object.server_side_encryption} encryption." end run_demo if $PROGRAM_NAME == __FILE__

要在使用 Amazon CLI 上载对象时指定 SSE-S3,请使用以下示例。

aws s3api put-object --bucket DOC-EXAMPLE-BUCKET1 --key object-key-name --server-side-encryption AES256 --body file path

有关更多信息,请参阅 Amazon CLI 参考中的 put-object。要在使用 Amazon CLI 复制对象时指定 SSE-S3,请参阅 copy-object

有关使用 Amazon CloudFormation 设置加密的示例,请参阅 Amazon CloudFormation 用户指南中的使用默认加密创建存储桶通过 Amazon KMS 服务器端加密使用 S3 存储桶密钥创建存储桶