

# 使用 AWS KMS (SSE-KMS) 指定服务器端加密
<a name="specifying-kms-encryption"></a>

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

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

有关更改通用存储桶的默认加密配置的更多信息，请参阅[配置默认加密](default-bucket-encryption.md)。

在将存储桶的默认加密配置更改为 SSE-KMS 时，不会更改存储桶中现有 Amazon S3 对象的加密类型。要在将默认加密配置更新为 SSE-KMS 后更改先前存在对象的加密类型，可以使用 Amazon S3 批量操作。您为 S3 批量操作提供对象列表，而批量操作调用相应的 API 操作。可以使用 [复制对象](batch-ops-copy-object.md) 操作来复制现有对象，这会将这些对象写回到与 SSE-KMS 加密对象相同的存储桶中。单个批量操作作业可对数十亿个对象执行指定操作。有关更多信息，请参阅[使用批量操作批量执行对象操作](batch-ops.md)和 *AWS Storage Blog* 博客文章 [How to retroactively encrypt existing objects in Amazon S3 using S3 Inventory, Amazon Athena, and S3 Batch Operations](https://aws.amazon.com/blogs/security/how-to-retroactively-encrypt-existing-objects-in-amazon-s3-using-s3-inventory-amazon-athena-and-s3-batch-operations/)。

您可以使用 Amazon S3 控制台、REST API 操作、AWS SDK 和 AWS Command Line Interface（AWS CLI）指定 SSE-KMS。有关更多信息，请参阅以下主题。

**注意**  
您可以在 Amazon S3 中使用多区域 AWS KMS keys。但是，Amazon S3 目前将多区域密钥视为单区域密钥，且不使用密钥的多区域特征。有关更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的 [Using multi-Region keys](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html)。

**注意**  
如果您希望使用其它账户拥有的 KMS 密钥，您必须有权使用该密钥。有关 KMS 密钥的跨账户权限的更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的[创建其他账户可以使用的 KMS 密钥](https://docs.aws.amazon.com//kms/latest/developerguide/key-policy-modifying-external-accounts.html#cross-account-console)。

## 使用 S3 控制台
<a name="add-object-encryption-kms"></a>

本主题描述如何使用 Amazon S3 控制台，将对象的加密类型设置或更改为使用具有 AWS Key Management Service（AWS KMS）密钥的服务器端加密（SSE-KMS）。

**注意**  
如果对象小于 5 GB，则可以更改对象的加密。如果对象大于 5GB，必须使用 [AWS CLI](mpu-upload-object.md#UsingCLImpUpload) 或 [AWS SDK](CopyingObjectsMPUapi.md) 来更改对象的加密。
有关更改对象的加密所需的其它权限的列表，请参阅 [Amazon S3 API 操作所需的权限](using-with-s3-policy-actions.md)。有关授予此权限的示例策略，请参阅[Amazon S3 基于身份的策略示例](example-policies-s3.md)。
如果更改对象的加密，则会创建一个新对象来替换旧对象。如果启用 S3 版本控制，则会创建对象的新版本，而现有对象将变为旧版本。更改属性的角色也会成为新对象（或对象版本）的拥有者。

**添加或更改对象的加密**

1. 登录到 AWS 管理控制台，然后通过以下网址打开 Amazon S3 控制台：[https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/)。

1. 在导航窗格中，选择**存储桶**，然后选择**通用存储桶**选项卡。导航到包含要更改的对象的 Amazon S3 存储桶或文件夹。

1. 选中要更改的对象所对应的复选框。

1. 在**操作**菜单上，从显示的选项列表中选择**编辑服务器端加密**。

1. 滚动到**服务器端加密**部分。

1. 在**加密设置**下，选择**使用默认加密的存储桶设置**或**覆盖默认加密的存储桶设置**。
**重要**  
如果您将 SSE-KMS 选项用于默认加密配置，则您将受到 AWS KMS 的每秒请求数（RPS）限额限制。有关 AWS KMS 限额以及如何请求增加限额的更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的[限额](https://docs.aws.amazon.com/kms/latest/developerguide/limits.html)。

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

   1. 在**加密类型**下，选择**具有 AWS Key Management Service 密钥的服务器端加密（SSE-KMS）**。

   1. 在 **AWS KMS 密钥**下，执行以下操作以选择您的 KMS 密钥：
      + 要从可用的 KMS 密钥列表中进行选择，请选择**从您的 AWS KMS keys 中进行选择**，然后从可用密钥的列表中选择您的 **KMS 密钥**。

        AWS 托管式密钥（`aws/s3`）和您的客户自主管理型密钥都显示在此列表中。有关客户自主管理型密钥的更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的[客户密钥和 AWS 密钥](https://docs.aws.amazon.com//kms/latest/developerguide/concepts.html#key-mgmt)。
      + 要输入 KMS 密钥 ARN，请选择**输入 AWS KMS key ARN**，然后在显示的字段中输入您的 KMS 密钥 ARN。
      + 要在 AWS KMS 控制台中创建新的客户自主管理型密钥，请选择**创建 KMS 密钥**。

        有关创建 AWS KMS key 的更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的[创建密钥](https://docs.aws.amazon.com//kms/latest/developerguide/create-keys.html)。
**重要**  
您只能使用与存储桶所在相同的 AWS 区域中可用的 KMS 密钥。Amazon S3 控制台仅列出与存储桶位于同一区域中的前 100 个 KMS 密钥。要使用未列出的 KMS 密钥，您必须输入 KMS 密钥 ARN。如果您希望使用其他账户拥有的 KMS 密钥，则必须首先有权使用该密钥，然后必须输入相应的 KMS 密钥 ARN。  
Amazon S3 仅支持对称加密 KMS 密钥，不支持非对称 KMS 密钥。有关更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的[确定对称和非对称 KMS 密钥](https://docs.aws.amazon.com//kms/latest/developerguide/find-symm-asymm.html)。

1. 在**其它复制设置**下，选择是要**复制源设置**、**请勿指定设置**还是**指定设置**。**复制源设置**是默认选项。如果您只想复制不带源设置属性的对象，请选择**请勿指定设置**。选择**指定设置**，来指定存储类、ACL、对象标签、元数据、服务器端加密和其它校验和的设置。

1. 选择**保存更改**。

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

## 使用 REST API
<a name="KMSUsingRESTAPI"></a>

创建对象时（即上传新对象或复制现有对象时），您可以指定使用具有 AWS KMS keys 的服务器端加密（SSE-KMS）来加密数据。为此，请将 `x-amz-server-side-encryption` 标头添加到请求。将标头的值设置为加密算法 `aws:kms`。Amazon S3 通过返回响应标头 `x-amz-server-side-encryption` 来确认已使用 SSE-KMS 存储您的对象。

如果您指定值为 `x-amz-server-side-encryption` 的 `aws:kms` 标头，则还可以使用以下请求标头：
+ `x-amz-server-side-encryption-aws-kms-key-id`
+ `x-amz-server-side-encryption-context`
+ `x-amz-server-side-encryption-bucket-key-enabled`

**Topics**
+ [支持 SSE-KMS 的 Amazon S3 REST API 操作](#sse-request-headers-kms)
+ [加密上下文（`x-amz-server-side-encryption-context`）](#s3-kms-encryption-context)
+ [AWS KMS 密钥 ID（`x-amz-server-side-encryption-aws-kms-key-id`）](#s3-kms-key-id-api)
+ [S3 桶密钥（`x-amz-server-side-encryption-aws-bucket-key-enabled`）](#bucket-key-api)

### 支持 SSE-KMS 的 Amazon S3 REST API 操作
<a name="sse-request-headers-kms"></a>

以下 REST API 操作接受 `x-amz-server-side-encryption`、`x-amz-server-side-encryption-aws-kms-key-id` 和 `x-amz-server-side-encryption-context` 请求标头。
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) – 使用 `PUT` API 操作上传数据时，您可以指定这些请求标头。
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html) – 复制对象时，您同时具有源对象和目标对象。如果使用 `CopyObject` 操作传递 SSE-KMS 标头，这些标头仅应用于目标对象。复制现有对象时，不论源对象是否已加密，都不会对目标对象加密，除非您显式请求服务器端加密。
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) – 使用 `POST` 操作上传对象时，可在表单字段（而不是在请求标头）中提供相同的信息。
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html) – 使用分段上传 API 操作上传大型对象时，可以指定这些标头。您可以在 `CreateMultipartUpload` 请求中指定这些标头。

使用服务器端加密存储对象时，以下 REST API 操作的响应标头将返回 `x-amz-server-side-encryption` 标头。
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html)

**重要**  
如果您不让使用安全套接字协议（SSL）、传输层安全性协议（TLS）或签名版本 4 针对受 AWS KMS 保护的对象发出所有 `GET` 和 `PUT` 请求，则这些请求都将失败。
如果对象使用 SSE-KMS，则不应对 `GET` 请求和 `HEAD` 请求发送加密请求标头，否则将显示 HTTP 400 BadRequest 错误。

### 加密上下文（`x-amz-server-side-encryption-context`）
<a name="s3-kms-encryption-context"></a>

如果您指定 `x-amz-server-side-encryption:aws:kms`，Amazon S3 API 将支持带有 `x-amz-server-side-encryption-context` 标头的加密上下文。加密上下文是一组键值对，其中包含有关数据的其他上下文信息。

Amazon S3 会自动使用对象或存储桶 Amazon Resource Name（ARN）作为加密上下文对。如果您在不启用 S3 存储桶密钥的情况下使用 SSE-KMS，则将对象 ARN 用作加密上下文；例如 `arn:aws:s3:::object_ARN`。但是，如果您使用 SSE-KMS 并启用 S3 存储桶密钥，则将存储桶 ARN 用于加密上下文；例如 `arn:aws:s3:::bucket_ARN`。

您可以选择使用 `x-amz-server-side-encryption-context` 标头提供其他的加密上下文对。但是，由于加密上下文未加密，请确保其中不包含敏感信息。Amazon S3 将此额外的密钥对与默认加密上下文一起存储。

有关 Amazon S3 中加密上下文的信息，请参阅 [加密上下文](UsingKMSEncryption.md#encryption-context)。有关加密上下文的一般信息，请参阅 *AWS Key Management Service 开发人员指南*中的 [AWS Key Management Service 概念 - 加密上下文](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context)。

### AWS KMS 密钥 ID（`x-amz-server-side-encryption-aws-kms-key-id`）
<a name="s3-kms-key-id-api"></a>

您可以使用 `x-amz-server-side-encryption-aws-kms-key-id` 标头指定用于保护数据的客户自主管理型密钥的 ID。如果您指定 `x-amz-server-side-encryption:aws:kms` 标头但未提供 `x-amz-server-side-encryption-aws-kms-key-id` 标头，Amazon S3 将使用 AWS 托管式密钥（`aws/s3`）来保护数据。如果要使用客户托管密钥，则必须提供客户托管密钥的 `x-amz-server-side-encryption-aws-kms-key-id` 标头。

**重要**  
在 Amazon S3 中使用 AWS KMS key 进行服务器端加密时，您必须选择对称加密 KMS 密钥。Amazon S3 仅支持对称加密 KMS 密钥。有关这些密钥的更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的[对称加密 KMS 密钥](https://docs.aws.amazon.com//kms/latest/developerguide/concepts.html#symmetric-cmks)。

### S3 桶密钥（`x-amz-server-side-encryption-aws-bucket-key-enabled`）
<a name="bucket-key-api"></a>

您可以使用 `x-amz-server-side-encryption-aws-bucket-key-enabled` 请求标头在对象级别启用或禁用 S3 存储桶密钥。S3 存储桶密钥通过减少从 Amazon S3 到 AWS KMS 的请求流量来降低您的 AWS KMS 请求成本。有关更多信息，请参阅 [使用 Amazon S3 存储桶密钥降低 SSE-KMS 的成本](bucket-key.md)。

如果您指定 `x-amz-server-side-encryption:aws:kms` 标头但未提供 `x-amz-server-side-encryption-aws-bucket-key-enabled` 标头，则您的对象将使用目标存储桶的 S3 存储桶密钥设置来加密对象。有关更多信息，请参阅 [在对象级别配置 S3 存储桶密钥](configuring-bucket-key-object.md)。

## 使用 AWS CLI
<a name="KMSUsingCLI"></a>

要使用以下示例 AWS CLI 命令，请将 `user input placeholders` 替换为您自己的信息。

当您上传新对象或复制现有对象时，可以指定使用具有 AWS KMS 密钥的服务器端加密来加密数据。为此，请将 `--server-side-encryption aws:kms` 标头添加到请求。使用 `--ssekms-key-id example-key-id` 添加您创建的[客户托管式 AWS KMS 密钥](https://docs.aws.amazon.com//kms/latest/developerguide/concepts.html#customer-cmk)。如果您指定 `--server-side-encryption aws:kms`，但未提供 AWS KMS 密钥 ID，Amazon S3 将使用 AWS 托管式密钥。

```
aws s3api put-object --bucket amzn-s3-demo-bucket --key example-object-key --server-side-encryption aws:kms --ssekms-key-id example-key-id --body filepath
```

此外，您还可以通过添加 `--bucket-key-enabled` 或 `--no-bucket-key-enabled` 在 PUT 或 COPY 操作中启用或禁用 Amazon S3 存储桶密钥。Amazon S3 存储桶密钥可以通过减少从 Amazon S3 到 AWS KMS 的请求流量来降低您的 AWS KMS 请求成本。有关更多信息，请参阅[使用 Amazon S3 存储桶密钥降低 SSE-KMS 的成本](https://docs.aws.amazon.com//AmazonS3/latest/userguide/bucket-key.html)。

```
aws s3api put-object --bucket amzn-s3-demo-bucket --key example-object-key --server-side-encryption aws:kms --bucket-key-enabled --body filepath
```

您可以通过将未加密的对象复制回原位来加密该对象以使用 SSE-KMS。

```
aws s3api copy-object --bucket amzn-s3-demo-bucket --key example-object-key --body filepath --bucket amzn-s3-demo-bucket --key example-object-key --sse aws:kms --sse-kms-key-id example-key-id --body filepath
```

## 使用 AWS SDK
<a name="kms-using-sdks"></a>

使用 AWS SDK 时，您可以请求 Amazon S3 使用 AWS KMS keys 进行服务器端加密。以下示例展示了如何将 SSE-KMS 与适用于 Java 和 .NET 的 AWS SDK 结合使用。有关其它 SDK 的信息，请参阅 AWS 开发人员中心上的[示例代码和库](https://aws.amazon.com/code)。

**重要**  
在 Amazon S3 中使用 AWS KMS key 进行服务器端加密时，您必须选择对称加密 KMS 密钥。Amazon S3 仅支持对称加密 KMS 密钥。有关这些密钥的更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的[对称加密 KMS 密钥](https://docs.aws.amazon.com//kms/latest/developerguide/concepts.html#symmetric-cmks)。

### `CopyObject` 操作
<a name="kms-copy-operation"></a>

在复制对象时，您添加相同的请求属性（`ServerSideEncryptionMethod` 和 `ServerSideEncryptionKeyManagementServiceKeyId`）来请求 Amazon S3 使用 AWS KMS key。有关复制对象的更多信息，请参阅 [复制、移动和重命名对象](copy-object.md)。

### `PUT` 操作
<a name="kms-put-operation"></a>

------
#### [ Java ]

当使用适用于 Java 的 AWS SDK 上传对象时，您可以通过添加 `SSEAwsKeyManagementParams` 属性来请求 Amazon S3 使用 AWS KMS key，如以下请求所示：

```
PutObjectRequest putRequest = new PutObjectRequest(bucketName,
   keyName, file).withSSEAwsKeyManagementParams(new SSEAwsKeyManagementParams());
```

在这种情况下，Amazon S3 使用 AWS 托管式密钥（`aws/s3`）。有关更多信息，请参阅 [使用具有 AWS KMS 密钥的服务器端加密（SSE-KMS）](UsingKMSEncryption.md)。您可以选择创建对称加密 KMS 密钥，并在请求中指定该密钥，如以下示例所示：

```
PutObjectRequest putRequest = new PutObjectRequest(bucketName,
   keyName, file).withSSEAwsKeyManagementParams(new SSEAwsKeyManagementParams(keyID));
```

有关创建客户托管密钥的更多信息，请参阅 *AWS Key Management Service 开发人员指南*中的[对 AWS KMS API 进行编程](https://docs.aws.amazon.com/kms/latest/developerguide/programming-top.html)。

有关上传对象的工作代码示例，请参阅以下主题。要使用这些示例，您必须更新这些代码示例并提供加密信息，如上述代码片段所示。
+ 有关在单个操作中上传对象，请参阅 [上传对象](upload-objects.md)。
+ 有关使用高级或低级分段上传 API 操作的分段上传，请参阅[使用分段上传操作上传对象](mpu-upload-object.md)。

------
#### [ .NET ]

当使用适用于 .NET 的 AWS SDK 上传对象时，您可以通过添加 `ServerSideEncryptionMethod` 属性来请求 Amazon S3 使用 AWS KMS key，如以下请求所示：

```
PutObjectRequest putRequest = new PutObjectRequest
 {
     BucketName = amzn-s3-demo-bucket,
     Key = keyName,
     // other properties
     ServerSideEncryptionMethod = ServerSideEncryptionMethod.AWSKMS
 };
```

在这种情况下，Amazon S3 使用 AWS 托管式密钥。有关更多信息，请参阅 [使用具有 AWS KMS 密钥的服务器端加密（SSE-KMS）](UsingKMSEncryption.md)。您可以选择创建自己的对称加密客户自主管理型密钥，并在请求中指定该密钥，如以下示例所示：

```
PutObjectRequest putRequest1 = new PutObjectRequest
{
  BucketName = amzn-s3-demo-bucket,
  Key = keyName,
  // other properties
  ServerSideEncryptionMethod = ServerSideEncryptionMethod.AWSKMS,
  ServerSideEncryptionKeyManagementServiceKeyId = keyId
};
```

有关创建客户托管密钥的更多信息，请参阅 *AWS Key Management Service 开发人员指南*中的[对 AWS KMS API 进行编程](https://docs.aws.amazon.com/kms/latest/developerguide/programming-top.html)。

有关上传对象的工作代码示例，请参阅以下主题。要使用这些示例，您必须更新这些代码示例并提供加密信息，如上述代码片段所示。
+ 有关在单个操作中上传对象，请参阅 [上传对象](upload-objects.md)。
+ 有关使用高级或低级分段上传 API 操作的分段上传，请参阅[使用分段上传操作上传对象](mpu-upload-object.md)。

------

### 预签名 URL
<a name="kms-presigned-urls"></a>

------
#### [ Java ]

在为使用 AWS KMS key加密的对象创建预签名 URL 时，您必须显式指定签名版本 4，如以下示例所示：

```
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setSignerOverride("AWSS3V4SignerType");
AmazonS3Client s3client = new AmazonS3Client(
        new ProfileCredentialsProvider(), clientConfiguration);
...
```

有关代码示例，请参阅 [使用预签名 URL 共享对象](ShareObjectPreSignedURL.md)。

------
#### [ .NET ]

在为使用 AWS KMS key加密的对象创建预签名 URL 时，您必须显式指定签名版本 4，如以下示例所示：

```
AWSConfigs.S3Config.UseSignatureVersion4 = true;
```

有关代码示例，请参阅 [使用预签名 URL 共享对象](ShareObjectPreSignedURL.md)。

------