

# 更新现有数据的服务器端加密
<a name="update-sse-encryption"></a>

默认情况下，所有 Amazon S3 存储桶都配置了加密，并且通过具有 Amazon S3 托管密钥的服务器端加密（SSE-S3）来自动加密对象。此默认加密设置适用于 Amazon S3 存储桶中的所有新对象。

使用 `UpdateObjectEncryption` API 操作，您能够以原子方式更新通用存储桶中现有加密对象的服务器端加密类型，即从具有 Amazon S3 托管式密钥的服务器端加密（SSE-S3）更改为具有 Amazon Key Management Service（Amazon KMS）密钥的服务器端加密（SSE-KMS）。`UpdateObjectEncryption` API 操作使用[信封加密](https://docs.amazonaws.cn/kms/latest/developerguide/kms-cryptography.html#enveloping)，以使用新指定的服务器端加密类型来重新加密用于加密和解密对象的数据密钥。

Amazon S3 在不移动任何数据的情况下执行此加密类型更新。换句话说，当您使用 `UpdateObjectEncryption` 操作时，不会复制您的数据，S3 Glacier Flexible Retrieval 或 S3 Glacier Deep Archive 中的已归档对象不会恢复，S3 Intelligent-Tiering 存储类别中的对象也不会在层之间移动。此外，`UpdateObjectEncryption` 操作会保留所有对象元数据属性，包括存储类别、创建日期、上次修改日期、ETag 以及校验和属性。

通用存储桶支持的所有 S3 存储类别都支持 `UpdateObjectEncryption` 操作。您可以使用 `UpdateObjectEncryption` 操作来执行以下操作：
+ 将加密的对象从具有 Amazon S3 托管式密钥的服务器端加密（SSE-S3）更改为具有 Amazon Key Management Service（Amazon KMS）加密密钥的服务器端加密（SSE-KMS）。
+ 更新对象级 SSE-KMS 加密对象以使用 S3 存储桶密钥，这会减少从 Amazon S3 到 Amazon KMS 的 Amazon KMS 请求流量。有关更多信息，请参阅 [使用 Amazon S3 存储桶密钥降低 SSE-KMS 的成本](bucket-key.md)。
+ 更改用于加密数据的客户自主管理型 KMS 密钥，这样您就可以遵守自定义密钥轮换标准。

**注意**  
此操作不支持未加密的对象，也不支持使用具有 Amazon KMS keys的双层服务器端加密（DSSE-KMS）或客户提供的加密密钥（SSE-C）进行加密的对象。

无论对象的大小或存储类别（包括 S3 Glacier Flexible Retrieval 或 S3 Glacier Deep Archive）如何，`UpdateObjectEncryption` 操作通常都会在数毫秒内完成。此操作不算作对 S3 Intelligent-Tiering 的访问，因此，如果您更改对象的服务器端加密类型，不频繁访问层或归档即时访问层中的对象将不会自动分层回到频繁访问层。

`UpdateObjectEncryption` 是一种对象级（数据面板）API 操作，已记录到 Amazon S3 服务器访问日志和 Amazon CloudTrail 数据事件中。有关更多信息，请参阅 [Amazon S3 的日志记录选项](logging-with-S3.md)。

 `UpdateObjectEncryption` 操作的定价与 `PUT`、`COPY`、`POST` 和 `LIST` 请求相同（每 1000 个请求），并且无论底层对象的存储类别如何，均始终按照 S3 Standard 存储类别请求收费。有关更多信息，请参阅 [Amazon S3 定价](https://www.amazonaws.cn/s3/pricing/)。

## 限制和注意事项
<a name="update-sse-encryption-restrictions"></a>

当您使用 `UpdateObjectEncryption` 操作时，以下限制和注意事项适用：
+ `UpdateObjectEncryption` 操作不支持未加密的对象，也不支持使用具有 Amazon KMS keys 的双层服务器端加密（DSSE-KMS）或客户提供的加密密钥（SSE-C）进行加密的对象。此外，您不能指定 SSE-S3 作为所请求的新加密类型 `UpdateObjectEncryption` 请求。
+ 您可以使用 `UpdateObjectEncryption` 操作来更新存储桶中启用了 S3 版本控制的对象。要更新特定版本的加密类型，您必须在 `UpdateObjectEncryption` 请求中指定版本 ID。如果未指定版本 ID，则 `UpdateObjectEncryption` 请求作用于对象的当前版本。有关 S3 版本控制的更多信息，请参阅[使用 S3 版本控制保留对象的多个版本](Versioning.md)。
+ `UpdateObjectEncryption` 操作对任何应用了 S3 对象锁定保留模式或法定保留的对象都将失败。如果某个对象具有治理模式保留期或法定保留，则在发出 `UpdateObjectEncryption` 请求之前，必须先移除该对象的对象锁定状态。您不能对应用了对象锁定合规模式保留期的对象使用 `UpdateObjectEncryption` 操作。有关 S3 对象锁定的更多信息，请参阅 [使用对象锁定以锁定对象](object-lock.md)。
+ 启用了实时复制功能的源存储桶上的 `UpdateObjectEncryption` 请求不会在目标存储桶中启动副本事件。如果要更改源存储桶和目标存储桶中对象的加密类型，则必须对源存储桶和目标存储桶中的对象发起单独的 `UpdateObjectEncryption` 请求。
+ 默认情况下，所有指定客户自主管理型 KMS 密钥的 `UpdateObjectEncryption` 请求都仅限于存储桶所有者的 Amazon Web Services 账户拥有的 KMS 密钥。如果您正在使用 Amazon Organizations，则可以通过联系 Amazon Web Services 支持 来请求使用组织内其它成员账户拥有的 Amazon KMS keys的能力。
+ 如果您使用 S3 批量复制来跨区域复制数据集，并且您的对象之前已将其服务器端加密类型从 SSE-S3 更新为 SSE-KMS，则您可能需要额外的权限。在源区域存储桶上，您必须拥有 `kms:decrypt` 权限。然后，您将需要针对目标区域中存储桶的 `kms:decrypt` 和 `kms:encrypt` 权限。
+ 您必须在您的 `UpdateObjectEncryption` 请求中提供完整的 KMS 密钥 ARN。您不能使用别名名称或别名 ARN。您可以在 AWS KMS 控制台中或使用 AWS KMS `DescribeKey` API 确定完整的 KMS 密钥 ARN。

## 所需的权限
<a name="update-sse-encryption-permissions"></a>

要执行 `UpdateObjectEncryption` 操作，您必须拥有以下权限：
+ `s3:PutObject`
+ `s3:UpdateObjectEncryption`
+ `kms:Encrypt`
+ `kms:Decrypt`
+ `kms:GenerateDataKey`
+ `kms:ReEncrypt*`

如果您正在使用 Amazon Organizations，则要将此操作与组织内其它 Amazon Web Services 账户提供的客户管理型 KMS 密钥结合使用，您必须具有 `organizations:DescribeAccount` 权限。还可以通过联系 Amazon Web Services 支持 来请求使用组织内其它成员账户拥有的 Amazon KMS keys的能力。

要执行 `UpdateObjectEncryption` 操作，请将以下 Amazon Identity and Access Management（IAM）策略添加到您的 IAM 角色。要使用此策略，请将 `amzn-s3-demo-bucket` 替换为通用存储桶的名称，并将另一个 `user input placeholders` 替换为您自己的信息。

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [{
            "Sid": "AllowUpdateObjectEncryption",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:UpdateObjectEncryption",
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:GenerateDataKey",
                "kms:ReEncrypt*",
                "organizations:DescribeAccount"
            ],
            "Resource": [
                "arn:aws:s3:::amzn-s3-demo-bucket",
                "arn:aws:s3:::amzn-s3-demo-bucket/*",
                "arn:aws:kms:us-east-1:111122223333:key/01234567-89ab-cdef-0123-456789abcdef"
            ]
        }
    ]
}
```

## 批量更新加密
<a name="update-sse-encryption-bulk"></a>

要使用单个请求更新多个 Amazon S3 对象的服务器端加密类型，您可以使用 S3 批量操作。您可以为 S3 批量操作提供要操作的对象列表，也可以指示批量操作生成基于对象列表的对象元数据，包括前缀、存储类别、创建日期、加密类型、KMS 密钥 ARN 或 S3 存储桶密钥状态。S3 批量操作调用相应的 API 操作来执行指定的操作。单个批量操作作业可对包含 PB 级数据的存储桶中的数十亿个对象执行指定的操作。有关批处理操作的更多信息，请参阅[使用批量操作批量执行对象操作](batch-ops.md)。

S3 批量操作特征包括跟踪进度、发送通知并存储所有操作的详细完成报告，从而提供完全托管、可审核的无服务器体验。可以通过 Amazon S3 控制台、Amazon Command Line Interface（Amazon CLI）、Amazon SDK 或 Amazon S3 REST API 使用 S3 批量操作。有关更多信息，请参阅 [更新对象加密](batch-ops-update-encryption.md)。

## 更新对象的加密
<a name="update-sse-encryption-single-object"></a>

您可以通过 Amazon Command Line Interface（Amazon CLI）、Amazon SDK 或 Amazon S3 REST API 更新对象的服务器端加密类型。

### 更新对象的加密
<a name="update-sse-encryption-single-object-procedure"></a>

#### 使用 Amazon CLI
<a name="update-sse-encryption-single-object-cli"></a>

要运行以下命令，您必须安装并配置 Amazon CLI。如果未安装 Amazon CLI，请参阅《Amazon Command Line Interface 用户指南》**中的[安装或更新最新版本的 Amazon CLI](https://docs.amazonaws.cn//cli/latest/userguide/getting-started-install.html)。

或者，可以从控制台中使用 Amazon CloudShell 运行 Amazon CLI 命令。Amazon CloudShell 是一个基于浏览器、预先经过身份验证的 Shell，您可以直接从 Amazon Web Services 管理控制台中启动它。有关更多信息，请参阅《Amazon CloudShell 用户指南》**中的 [What is CloudShell?](https://docs.amazonaws.cn//cloudshell/latest/userguide/welcome.html) 和 [Getting started with Amazon CloudShell](https://docs.amazonaws.cn//cloudshell/latest/userguide/getting-started.html)。

**使用 Amazon CLI 更新对象的加密**

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

1. 使用以下命令更新通用存储桶（例如 `amzn-s3-demo-bucket`）中单个对象 (`index.html`) 的加密，以便将 SSE-KMS 与 S3 存储桶密钥结合使用：

   ```
   aws s3api update-object-encryption \
   --bucket amzn-s3-demo-bucket \
   --key index.html \
   --object-encryption '{"SSEKMS": { "KMSKeyArn": "arn:aws:kms:us-east-1:111122223333:key/f12a345a-678e-9bbb-1025-62e317037583", "BucketKeyEnabled": true }}'
   ```
**注意**  
您必须指定完整的 Amazon KMS key Amazon 资源名称（ARN）。不支持 KMS 密钥 ID 和 KMS 密钥别名。

1. 运行 `head-object` 命令以查看对象的更新加密类型：

   ```
   aws s3api head-object --bucket amzn-s3-demo-bucket --key index.html
   ```

#### 使用 REST API
<a name="update-sse-encryption-single-object-rest-api"></a>

您可以发送 REST 请求以更新对象的加密。有关更多信息，请参阅 [https://docs.amazonaws.cn/AmazonS3/latest/API/API_UpdateObjectEncryption.html](https://docs.amazonaws.cn/AmazonS3/latest/API/API_UpdateObjectEncryption.html)。

#### 使用 Amazon SDK
<a name="update-sse-encryption-single-object-sdk"></a>

您可以使用 Amazon SDK 来更新对象的加密。有关更多信息，请参阅[支持的 SDK 的列表](https://docs.amazonaws.cn/AmazonS3/latest/API/API_UpdateObjectEncryption.html#API_UpdateObjectEncryption_SeeAlso)。

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

**Example**  
以下 Amazon SDK for Java 2.x 示例将通用存储桶中对象的加密类型更新为 SSE-KMS。  

```
    public void updateObjectEncryption(String bucketName,
                                       String objectKey,
                                       String versionId,
                                       String kmsKeyArn,
                                       boolean bucketKeyEnabled) {
        // Create the target object encryption type.
        ObjectEncryption objectEncryption = ObjectEncryption.builder()
                .ssekms(SSEKMSEncryption.builder()
                        .kmsKeyArn(kmsKeyArn)
                        .bucketKeyEnabled(bucketKeyEnabled)
                        .build())
                .build();

        // Create the UpdateObjectEncryption request.
        UpdateObjectEncryptionRequest request = UpdateObjectEncryptionRequest.builder()
                .bucket(bucketName)
                .key(objectKey)
                .versionId(versionId)
                .objectEncryption(objectEncryption)
                .build();

        // Update the object encryption.
        try {
            getS3Client().updateObjectEncryption(request);
            logger.info("Object encryption updated to SSE-KMS for {} in bucket {}", objectKey, bucketName);
        } catch (S3Exception e) {
            logger.error("Failed to update to object encryption: {} - Error code: {}", e.awsErrorDetails().errorMessage(),
                    e.awsErrorDetails().errorCode());
            throw e;
        }
    }
```

------
#### [ Python ]

**Example**  
以下 适用于 Python (Boto3) 的 Amazon SDK 示例说明如何将通用存储桶中对象的加密类型更新为 SSE-KMS。  

```
response = client.update_object_encryption(
    Bucket='string',
    Key='string',
    VersionId='string',
    ObjectEncryption={
        'SSEKMS': {
                'KMSKeyArn': 'string',
                'BucketKeyEnabled': True|False
        }
    }
)
```

------