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

指定具有 Amazon S3 托管式密钥的服务器端加密(SSE-S3)

重要

Amazon S3 现在将具有 Amazon S3 托管密钥的服务器端加密(SSE-S3)作为 Amazon S3 中每个存储桶的基本加密级别。从 2023 年 1 月 5 日起,上传到 Amazon S3 的所有新对象都将自动加密,不会产生额外费用,也不会影响性能。S3 存储桶默认加密配置和上传的新对象的自动加密状态可在 Amazon CloudTrail 日志、S3 清单、S3 Storage Lens 存储统计管理工具、Amazon S3 控制台中获得,并可用作 Amazon Command Line Interface 和 Amazon SDK 中的附加 Amazon S3 API 响应标头。有关更多信息,请参阅默认加密常见问题解答

默认情况下,所有 Amazon S3 存储桶都配置了加密,所有上传到 S3 存储桶的新对象都会自动静态加密。具有 Amazon S3 托管密钥的服务器端加密(SSE-S3)是 Amazon S3 中每个存储桶的默认加密配置。要使用其他类型的加密,您可以指定要在 S3 PUT 请求中使用的服务器端加密类型,也可以在目标存储桶中设置默认加密配置。

如果您想在 PUT 请求中指定不同的加密类型,则可以使用具有 Amazon Key Management Service(Amazon KMS)密钥的服务器端加密(SSE-KMS)、具有 Amazon KMS 密钥的双层服务器端加密(DSSE-KMS)或具有客户提供的密钥的服务器端加密(SSE-C)。如果您想在目标存储桶中设置不同的默认加密配置,则可以使用 SSE-KMS 或 DSSE-KMS。

您可以使用 S3 控制台、REST API、Amazon SDK 和 Amazon Command Line Interface(Amazon CLI)指定 SSE-S3。有关更多信息,请参阅为 Amazon S3 存储桶设置默认服务器端加密行为

本主题介绍如何使用 Amazon Web Services Management Console设置或更改对象的加密类型。使用控制台复制对象时,Amazon S3 将按原样复制对象。这意味着,如果对源对象加密,则也会对目标对象加密。可以使用控制台添加或更改对象的加密。

注意

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

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

  2. 在左侧导航窗格中,选择存储桶

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

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

    将显示对象的详细信息页面,其中有几个部分显示您的对象的属性。

  5. 选择属性选项卡。

  6. 向下滚动到服务器端加密设置部分,然后选择编辑

  7. 加密设置下,选择使用存储桶默认加密设置覆盖存储桶默认加密设置

  8. 如果您选择覆盖默认加密的存储桶设置,请配置以下加密设置。

    1. 加密类型下,选择 Amazon S3 托管式密钥(SSE-S3)。SSE-S3 使用最强的数据块密码之一 [即 256 位高级加密标准(AES-256)] 来加密每个对象。有关更多信息,请参阅使用具有 Amazon S3 托管式密钥的服务器端加密(SSE-S3)

  9. 选择 Save changes(保存更改)

注意

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

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

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

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

使用 SSE-S3 加密存储对象后,以下 REST API 操作的响应标头将返回 x-amz-server-side-encryption 标头。

注意

如果您的对象使用 SSE-S3,请不要发送 GET 请求和 HEAD 请求的加密请求标头,否则会收到 HTTP 状态代码 400(错误请求)错误。

使用 Amazon SDK 时,您可以请求 Amazon S3 使用具有 Amazon S3 托管式加密密钥的服务器端加密(SSE-S3)。这部分提供了以多种语言使用 Amazon SDK 的示例。有关其他 SDK 的信息,请转到示例代码和库

Java

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

当使用分段上传 API 操作上传对象时,还可以请求 SSE-S3 加密:

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

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

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

例 示例

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

  • 使用 SSE-S3 上传新对象。

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

  • 检查对象的加密状态。

有关服务器端加密的更多信息,请参阅 使用 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 中指定 SSE-S3,请添加以下内容:

ServerSideEncryptionMethod = ServerSideEncryptionMethod.AES256

有关如何复制对象的有效示例,请参阅 使用 Amazon SDK

以下示例将上传对象。在请求中,该示例指示 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 中的类来将 SSE-S3 添加到您上传到 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 操作上传大型对象时,您可以为正在上传的对象指定 SSE-S3,如下所示:

  • 如果您使用低级别分段上传 API 操作,请在调用 Aws\S3\S3Client::createMultipartUpload() 方法时指定服务器端加密。要向请求添加 x-amz-server-side-encryption 请求标头,请使用值 array 指定 ServerSideEncryption 参数的 AES256 密钥。有关低级别分段上传 API 操作的更多信息,请参阅使用 Amazon SDK(低级别 API)

  • 当使用高级别分段上传 API 操作时,请使用 CreateMultipartUpload API 操作的 ServerSideEncryption 参数来指定服务器端加密。有关将 setOption() 方法与高级别分段上传 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() 不会加密目标,除非您通过将值 AES256 用于 ServerSideEncryption 参数,显式请求对目标对象进行服务器端加密。以下 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-S3 对存储的对象进行静态加密。在您读回对象时,它将自动解密。

下面的 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 # Example usage: 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__

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

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 # Example usage: 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 中的对象没有使用服务器端加密,则该方法将返回 null

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

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 # Example usage: 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 用户指南》AWS::S3::Bucket ServerSideEncryptionRule 主题中的使用默认加密创建存储桶通过 Amazon KMS 服务器端加密使用 S3 存储桶密钥创建存储桶示例。