

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

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

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

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

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

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

此迁移分为两个阶段：

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

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

如果您尚未从 V1 迁移到 V2，则必须先完成迁移。[Amazon 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 使用密钥承诺对**对象进行加密。
+  **解密行为：**可以解密有或没有密钥承诺的加密对象，提供向后兼容性。
+  **安全影响：**新对象受益于密钥承诺保护，而没有密钥承诺的现有对象仍然可以读取。这在迁移期间提供了安全性和向后兼容性之间的平衡。
+  **版本兼容性：使用此策略加密的**对象只能由 S3 加密客户端的 V3 和最新 V2 实现读取。

 **`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`** 

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

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

### 带有关键承诺的 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 加密对象的 Ruby Amazon SDK 版本。完成此步骤后，您的应用程序的 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>

 **Pre-migration (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
```

 **Post-migration (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 对象（加密对象及其指令文件），而不是一个。

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