

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 亚马逊 S3 加密客户端迁移（从 V2 到 V3）
<a name="s3-encryption-migration-v2-v3"></a>

**注意**  
如果您使用的是 S3 加密客户端的 V1，则必须先迁移到 V2，然后再迁移到 V3。[亚马逊 S3 加密客户端迁移（从 V1 到 V2）](s3-encryption-migration-v1-v2.md)有关从 V1 迁移到 V2 的说明，请参阅。

本主题介绍如何将您的应用程序从亚马逊简单存储服务 (Amazon S3) Simple Service 加密客户端的版本 2 (V2) 迁移到版本 3 (V3)，并确保应用程序在整个迁移过程中的可用性。V3 引入了 AES GCM 以及密钥承诺和承诺政策，以增强安全性并防止数据密钥被篡改。

## 迁移概述
<a name="s3-encryption-migration-v2-v3-overview"></a>

Amazon S3 加密客户端第 3 版引入了带有密钥承诺的 AES GCM，以增强安全性。这种新的加密算法可防止数据密钥被篡改，并确保加密数据的完整性。迁移到 V3 需要仔细规划，以便在整个过程中保持应用程序可用性和数据可访问性。

此迁移分为两个阶段：

1. **更新现有客户端以读取新格式。**首先，将适用于 Ruby 的 AWS SDK 的更新版本部署到您的应用程序。这将允许现有的 V2 加密客户端解密新 V3 客户端写入的对象。如果您的应用程序使用多个 SDK AWS SDKs，则必须单独升级每个 SDK。

2. **将加密和解密客户端迁移到 V3。**一旦所有 V2 加密客户端都能读取新格式，就可以将现有的加密和解密客户端迁移到各自的 V3 版本。这包括配置承诺策略和更新代码以使用新的客户端配置选项。

如果您尚未从 V1 迁移到 V2，则必须先完成迁移。[亚马逊 S3 加密客户端迁移（从 V1 到 V2）](s3-encryption-migration-v1-v2.md)有关从 V1 迁移到 V2 的详细说明，请参阅。

## 了解 V3 的功能
<a name="s3-encryption-migration-v2-v3-understanding"></a>

Amazon S3 加密客户端第 3 版引入了两个关键安全功能：承诺策略和带密钥承诺的 AES GCM。了解这些功能对于规划迁移策略和确保加密数据的安全性至关重要。

### 承诺政策
<a name="s3-encryption-migration-v2-v3-commitment-policies"></a>

承诺策略控制加密客户端在加密和解密操作期间如何处理密钥承诺。密钥承诺可确保加密数据只能使用用于加密数据的精确密钥进行解密，从而防止某些类型的加密攻击。

V3 加密客户端支持三个承诺策略选项：

 **`FORBID_ENCRYPT_ALLOW_DECRYPT`** 

此策略对没有密钥承诺的对象进行加密，并允许使用和不使用密钥承诺对两个对象进行解密。
+  **加密行为：**使用与 V2 相同的算法套件对对象进行加密，无需密钥承诺。
+  **解密行为：**可以解密使用或不使用密钥承诺加密的对象。
+  **安全影响：**此政策不强制执行密钥承诺，可能允许篡改。使用此策略加密的对象不会受益于密钥承诺的增强安全保护。只有在需要保持与 V2 加密行为的兼容性时，才在迁移期间使用此策略。
+  **版本兼容性：**S3 加密客户端的所有 V2 和 V3 实现均可读取使用此策略加密的对象。

 **`REQUIRE_ENCRYPT_ALLOW_DECRYPT`**

此策略使用密钥承诺对对象进行加密，并允许使用和不使用密钥承诺对两个对象进行解密。
+  **加密行为：**使用带有密钥承诺的 AES GCM 使用密钥承诺对对象进行加密。
+  **解密行为：**可以解密使用或不使用密钥承诺加密的对象，从而提供向后兼容性。
+  **安全影响：**新对象受益于密钥承诺保护，而没有密钥承诺的现有对象仍然可以读取。这样可以在迁移期间在安全性和向后兼容性之间取得平衡。
+  **版本兼容性：**使用此策略加密的对象只能由 V3 和 S3 加密客户端的最新 V2 实现进行读取。

 **`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`** 

此策略对使用密钥承诺的对象进行加密，并且仅允许解密使用密钥承诺加密的对象。
+  **加密行为：**使用带有密钥承诺的 AES GCM 使用密钥承诺对对象进行加密。
+  **解密行为：**只能解密使用密钥承诺加密的对象。尝试在没有密钥承诺的情况下解密对象将失败。
+  **安全影响：**该政策通过对所有操作强制执行密钥承诺来提供最高级别的安全性。只有在使用密钥承诺对所有对象进行重新加密并且所有客户端都已升级到 V3 之后，才使用此策略。
+  **版本兼容性：**使用此策略加密的对象只能由 V3 和 S3 加密客户端的最新 V2 实现进行读取。此策略还禁止读取由 V2 或 V1 客户端加密的对象。

**注意**  
在规划迁移时，首先`REQUIRE_ENCRYPT_ALLOW_DECRYPT`要保持向后兼容性，同时获得对新对象的密钥承诺所带来的安全优势。只有`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`在所有对象都重新加密并且所有客户端都已升级到 V3 之后才会移至。

### 带有关键承诺的 AES GCM
<a name="s3-encryption-migration-v2-v3-aes-gcm-kc"></a>

带有密钥承诺的 AES GCM (`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`) 是 V3 中引入的一种新加密算法，它通过防止数据密钥被篡改来增强安全性。了解此算法的工作原理以及何时适用，对于规划迁移非常重要。

 **与以前的算法有何`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`不同** 

S3 加密客户端的先前版本使用 AES CBC 或 AES GCM，但没有密钥承诺，对指令文件中的数据密钥进行加密。 `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`向加密过程添加加密承诺，将加密数据绑定到特定密钥。这样可以防止攻击者篡改指令文件中的加密数据密钥并导致客户端使用错误的密钥解密数据。

如果没有密钥承诺，攻击者就有可能修改指令文件中的加密数据密钥，使其解密为不同的密钥，从而可能允许未经授权的访问或数据损坏。 `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`通过确保加密的数据密钥只能解密为加密期间使用的原始密钥来防止这种攻击。

 **版本兼容性** 

使用加密的对象`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`只能通过 S3 加密客户端的 V3 实现以及支持读取 V3 格式的 V2 的某些过渡版本进行解密。没有此过渡支持的 V2 客户端无法解密使用加密的指令文件。`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`

**警告**  
在启用加密之前`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`（通过使用`REQUIRE_ENCRYPT_ALLOW_DECRYPT`或`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`承诺策略），请确保所有需要读取您的加密对象的客户端都已升级到 V3 或支持 V3 格式的过渡版本。如果任何不支持过渡的 V2 客户端尝试读取使用加密的对象`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`，则解密将失败。

在迁移过程中，您可以使用`FORBID_ENCRYPT_ALLOW_DECRYPT`承诺策略继续加密，而不必`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`同时允许 V3 客户端读取使用密钥承诺加密的对象。这提供了一个安全的迁移路径，您可以先升级所有读取器，然后切换到使用密钥承诺进行加密。

## 更新现有客户端以读取新格式
<a name="s3-encryption-migration-v2-v3-update-clients"></a>

V3 加密客户端使用 V2 客户端默认不支持的加密算法和密钥承诺功能。迁移的第一步是将 V2 解密客户端更新为可以读取 V3 加密对象的 AWS SDK for Ruby 版本。完成此步骤后，您的应用程序的 V2 客户端将能够解密由 V3 加密客户端加密的对象。

要读取由 V3 客户端（使用`REQUIRE_ENCRYPT_ALLOW_DECRYPT`或`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`承诺策略的客户端）加密的对象，您需要使用 Gem 版本 1.93.0 或更高版本。`aws-sdk-s3`此版本支持使用密钥承诺解密使用 AES GCM 加密的对象。

 **从命令行安装** 

对于通过命令行安装 `aws-sdk-s3` gem 的项目，请使用版本选项验证是否安装了最低版本 1.208.0。

```
gem install aws-sdk-s3 -v '>= 1.208.0'
```

 **使用 Gemfile** 

对于使用 Gemfile 管理依赖关系的项目，请将 G `aws-sdk-s3` em 的最低版本设置为 1.208.0。例如：

```
gem 'aws-sdk-s3', '>= 1.208.0'
```

1. 修改您的 Gemfile 以指定最低版本。

1. 运行`bundle update aws-sdk-s3`更新 gem。

1. 要验证您的版本，请运行 `bundle info aws-sdk-s3`。

**注意**  
更新到最新版本后，您现有的 V2 加密客户端将能够解密由 V3 客户端加密的对象。但是，他们将继续使用 V2 算法对新对象进行加密，直到您按照下一节所述将其迁移到 V3。

## 将加密和解密客户端迁移到 V3
<a name="s3-encryption-migration-v2-v3-migrate"></a>

更新客户端以读取新的加密格式后，您可以将应用程序更新为 V3 加密和解密客户端。以下步骤向您展示了如何成功地将代码从 V2 迁移到 V3。

在更新代码以使用 V3 加密客户端之前，请确保您已按照上述步骤操作并使用的是 `aws-sdk-s3` Gem 版本 1.93.0 或更高版本。

**注意**  
使用 AES-GCM 解密时，在开始使用解密的数据之前，请通读整个对象。这是为了验证自加密以来是否未对对象进行过修改。

### 配置 V3 客户端
<a name="s3-encryption-migration-v2-v3-configure"></a>

V3 加密客户端引入了新的配置选项，用于控制密钥承诺行为和向后兼容性。了解这些选项对于成功迁移至关重要。

 **承诺政策** 

该`commitment_policy`参数控制加密客户端在加密和解密操作期间如何处理密钥承诺。这是 V3 客户端最重要的配置选项。
+  `:require_encrypt_allow_decrypt`-使用密钥承诺对新对象进行加密，并允许使用或不使用密钥承诺解密对象。这是迁移的推荐设置，因为它可以增强新对象的安全性，同时保持与现有 V2 对象的向后兼容性。
+  `:forbid_encrypt_allow_decrypt`-无需密钥承诺即可加密新对象（使用 V2 算法），并允许使用或不使用密钥承诺解密对象。只有在迁移期间需要保持 V2 加密行为时，例如某些客户端还无法读取 V3 加密对象时，才使用此设置。
+  `:require_encrypt_require_decrypt`-使用密钥承诺加密新对象，并且仅允许解密使用密钥承诺加密的对象。只有在使用密钥承诺对所有对象进行重新加密并且所有客户端都已升级到 V3 之后，才使用此设置。

 **安全配置文件** 

该`security_profile`参数决定是否支持读取由较早版本的加密客户端写入的对象。此参数对于在迁移期间保持向后兼容性至关重要。
+  `:v3_and_legacy`-允许 V3 客户端解密由 V1 和 V2 加密客户端加密的对象。在迁移期间使用此设置可确保您的 V3 客户端可以读取所有现有的加密对象。
+  `:v3`-仅允许 V3 客户端解密由 V2 加密客户端加密的对象。如果您已经将所有 V1 对象迁移为 V2 格式，请使用此设置。
+ 如果未指定，则客户端将仅解密由 V3 客户端加密的对象。仅将其用于不存在旧对象的新应用程序开发。

 **信封\_位置** 

该`envelope_location`参数决定加密元数据（包括加密的数据密钥）的存储位置。此参数影响哪些对象受 AES GCM 的保护，并使用密钥承诺。
+  `:metadata`（默认）-将加密元数据存储在 S3 对象的元数据标头中。这是默认行为，建议在大多数用例中使用。使用元数据存储时，带有密钥承诺的 AES GCM 不适用。
+  `:instruction_file`-将加密元数据存储在具有可配置后缀的单独的 S3 对象（指令文件）中。使用说明文件时，带有密钥承诺的 AES GCM 可保护加密的数据密钥免遭篡改。如果您需要密钥承诺为数据密钥本身提供的额外安全性，请使用此设置。

使用时`:instruction_file`，您可以选择指定`instruction_file_suffix`参数以自定义用于指令文件对象的后缀。默认后缀为。`.instruction`

 **何时使用每个配置选项** 

在迁移过程中，请遵循以下推荐的配置策略：

1.  **初始迁移：**设置`commitment_policy: :require_encrypt_allow_decrypt`和`security_profile: :v3_and_legacy`。这允许您的 V3 客户端使用密钥承诺加密新对象，同时仍然能够解密所有现有的 V1 和 V2 对象。

1.  **升级所有客户端后：**继续使用`commitment_policy: :require_encrypt_allow_decrypt`和，`security_profile: :v3_and_legacy`直到重新加密所有需要密钥承诺保护的对象。

1.  完@@ **整 V3 强制执行：**只有在使用密钥承诺重新加密所有对象并且您不再需要读取 V1/V2 对象之后，您才可以选择切换到`commitment_policy: :require_encrypt_require_decrypt`并删除该`security_profile`参数（或者`:v2`如果 V2 对象仍然存在，则将其设置为）。

对于`envelope_location`，请继续使用现有的存储方法（`:metadata`或`:instruction_file`），除非您有具体的理由要对其进行更改。如果您当前正在使用元数据存储，并且希望获得带有密钥承诺的 AES GCM 的额外安全性，则可以切换到`:instruction_file`，但请注意，这将需要更新所有读取这些对象的客户端。

### 将加密和解密客户端迁移到 V3
<a name="s3-encryption-migration-v2-v3-migrate"></a>

更新客户端以读取新的加密格式后，您可以将应用程序更新为 V3 加密和解密客户端。以下示例向您展示了如何成功地将代码从 V2 迁移到 V3。

#### 使用 V3 加密客户端
<a name="s3-encryption-migration-v2-v3-using-v3-clients"></a>

 **迁移前 (V2)** 

```
require 'aws-sdk-s3'

# Create V2 encryption client with KMS
client = Aws::S3::EncryptionV2::Client.new(
  kms_key_id: kms_key_id,
  key_wrap_schema: :kms_context,
  content_encryption_schema: :aes_gcm_no_padding,
  security_profile: :v2_and_legacy,
  commitment_policy: :forbid_encrypt_allow_decrypt
)

# Encrypt and upload object
client.put_object(bucket: 'my-bucket', key: 'my-object', body: 'secret data')

# Download and decrypt object
resp = client.get_object(bucket: 'my-bucket', key: 'my-object')
decrypted_data = resp.body.read
```

 **迁移期间（具有向后兼容性的 V3）** 

```
require 'aws-sdk-s3'

# Create V3 encryption client with KMS
client = Aws::S3::EncryptionV3::Client.new(
  kms_key_id: kms_key_id,
  key_wrap_schema: :kms_context,
  content_encryption_schema: :aes_gcm_no_padding,
  security_profile: :v3_and_legacy,
  commitment_policy: :require_encrypt_allow_decrypt
)

# Encrypt and upload object
client.put_object(bucket: 'my-bucket', key: 'my-object', body: 'secret data')

# Download and decrypt object
resp = client.get_object(bucket: 'my-bucket', key: 'my-object')
decrypted_data = resp.body.read
```

 **迁移后 (V3)** 

```
require 'aws-sdk-s3'

# Create V3 encryption client with KMS
client = Aws::S3::EncryptionV3::Client.new(
  kms_key_id: kms_key_id,
  key_wrap_schema: :kms_context,
  content_encryption_schema: :aes_gcm_no_padding,
  security_profile: :v3,
  # Use the commitment policy (REQUIRE_ENCRYPT_REQUIRE_DECRYPT)
  # This encrypts with key commitment and does not decrypt V2 objects
  commitment_policy: :require_encrypt_require_decrypt
)

# Encrypt and upload object
client.put_object(bucket: 'my-bucket', key: 'my-object', body: 'secret data')

# Download and decrypt object
resp = client.get_object(bucket: 'my-bucket', key: 'my-object')
decrypted_data = resp.body.read
```

V3 的主要区别在于`commitment_policy`参数的添加。将其设置为`:require_encrypt_require_decrypt`可确保使用密钥承诺对新对象进行加密，并且客户端仅解密使用密钥承诺加密的对象，从而增强安全性，防止数据密钥被篡改。

通`put_object`话本身保持不变。所有安全增强功能都是在客户端级别配置的。

### 其他示例
<a name="s3-encryption-migration-v2-v3-additional-examples"></a>

本节提供了有关特定迁移场景和配置选项的其他示例，这些示例可能在 V2 到 V3 迁移期间很有用。

#### 指令文件与元数据存储
<a name="s3-encryption-migration-v2-v3-example-storage"></a>

S3 加密客户端可以将加密元数据（包括加密的数据密钥）存储在两个不同的位置：在 S3 对象的元数据标头中或单独的指令文件中。存储方法的选择会影响哪些对象受益于具有密钥承诺保护的 AES GCM。

 **元数据存储（默认）** 

默认情况下，加密客户端将加密元数据存储在 S3 对象的元数据标头中。这是大多数用例的推荐方法，因为它会将加密元数据与对象一起保存，并且不需要管理单独的指令文件对象。

```
require 'aws-sdk-s3'

# Create V3 encryption client with metadata storage (default)
client = Aws::S3::EncryptionV3::Client.new(
  kms_key_id: kms_key_id,
  key_wrap_schema: :kms_context,
  content_encryption_schema: :aes_gcm_no_padding,
  security_profile: :v3_and_legacy,
  commitment_policy: :require_encrypt_allow_decrypt,
  envelope_location: :metadata # Explicitly set to metadata (this is the default)
)

# Encrypt and upload object
# Encryption metadata is stored in the object's metadata headers
client.put_object(bucket: 'my-bucket', key: 'my-object',body: 'secret data')
```

使用元数据存储时，带有密钥承诺的 AES GCM 不适用于加密的数据密钥。但是，使用`commitment_policy: :require_encrypt_allow_decrypt`或时，内容加密仍然受益于密钥承诺`:require_encrypt_require_decrypt`。

 **指令文件存储** 

或者，您可以将加密客户端配置为将加密元数据存储在名为指令文件的单独的 S3 对象中。在 V3 中使用说明文件时，加密的数据密钥受带有密钥承诺的 AES GCM 保护，从而提供额外的安全性，防止数据密钥被篡改。

```
require 'aws-sdk-s3'

# Create V3 encryption client with instruction file storage
client = Aws::S3::EncryptionV3::Client.new(
  kms_key_id: kms_key_id,
  key_wrap_schema: :kms_context,
  content_encryption_schema: :aes_gcm_no_padding,
  security_profile: :v3_and_legacy,
  commitment_policy: :require_encrypt_allow_decrypt,
  envelope_location: :instruction_file, # Store metadata in separate instruction file
  instruction_file_suffix: '.instruction' # Optional: customize the suffix (default is '.instruction')
)

# Encrypt and upload object
# Encryption metadata is stored in a separate object: 'my-object.instruction'
client.put_object(bucket: 'my-bucket', key: 'my-object', body: 'secret data')

# When retrieving the object, the client automatically reads the instruction file
resp = client.get_object(bucket: 'my-bucket', key: 'my-object')
decrypted_data = resp.body.read
```

使用时`envelope_location: :instruction_file`，加密客户端会创建两个 S3 对象：

1. 加密的数据对象（例如`my-object`）

1. 包含加密元数据的指令文件（例如`my-object.instruction`）

该`instruction_file_suffix`参数允许您自定义用于指令文件的后缀。默认值为 `.instruction`。

 **何时使用每种存储方法** 
+  在大多数场景中@@ **使用元数据存储**。它简化了对象管理，因为加密元数据会随对象一起传输。
+  当需要考虑对象元数据大小或需要将加密元数据与加密对象分开时，请@@ **使用指令文件存储**。请注意，使用指令文件需要管理两个 S3 对象（加密对象及其指令文件），而不是一个。

**警告**  
如果从元数据存储更改为指令文件存储（反之亦然），则使用新存储方法配置的客户机将无法读取使用旧存储方法加密的现有对象。仔细规划存储方法并保持应用程序间的一致性。