

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

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

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

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

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

此迁移分为两个阶段：

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

2. **将加密和解密客户端迁移到 V3。**一旦您的所有 V2 加密客户端都能读取新格式，您就可以将现有的加密和解密客户端迁移到各自的 V3 版本。

## 理解 V3 概念
<a name="s3-encryption-migration-v2-v3-concepts"></a>

Amazon S3 加密客户端的版本 3 引入了新的安全功能，可增强对数据密钥篡改的保护。了解这些概念对于成功迁移至关重要。

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

承诺策略控制加密客户端在加密和解密操作期间如何处理密钥承诺。V3 提供了三种策略选项来支持不同的迁移方案和安全要求：

**`FORBID_ENCRYPT_ALLOW_DECRYPT`**  
**加密行为：**使用与 V2 相同的算法，无需密钥承诺即可加密对象。  
**解密行为：**允许解密使用和不使用密钥承诺加密的对象。  
**安全隐患：**此政策不强制执行密钥承诺，可能允许篡改指令文件中的加密数据密钥。只有在初始迁移阶段，当你需要 V2 客户端读取新加密的对象时，才使用此策略。  
**版本兼容性：**所有 V2 和 V3 实现均可读取使用此策略加密的对象。

**`REQUIRE_ENCRYPT_ALLOW_DECRYPT`（默认）**  
**加密行为：**使用`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法对具有密钥承诺的对象进行加密。  
**解密行为：**允许解密使用密钥承诺加密的对象和不使用密钥承诺加密的对象。  
**安全影响：**此策略为新加密的对象提供了强大的安全性，同时保持了读取旧对象的向后兼容性。这是大多数迁移场景的推荐策略。  
**版本兼容性：**使用此策略加密的对象只能由 V3 和最新的 V2 实现读取。V2 客户端无法解密这些对象。但是，使用此策略的 V3 客户端仍然可以解密由 V2 客户端加密的对象。

**`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`**  
**加密行为：**使用`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法对具有密钥承诺的对象进行加密。  
**解密行为：**仅允许解密使用密钥承诺加密的对象。拒绝未经密钥承诺加密的对象。  
**安全影响：**该政策通过对所有操作强制执行密钥承诺来提供最高级别的安全性。只有在所有对象都使用密钥承诺重新加密并且您不再需要读取旧版 V1 或 V2 加密对象之后，才使用此策略。  
**版本兼容性：**使用此策略加密的对象只能由 V3 和最新的 V2 实现读取。此外，使用此策略的客户端无法解密由 V1 或 V2 客户端加密的对象。

**迁移注意事项：**在迁移期间，`FORBID_ENCRYPT_ALLOW_DECRYPT`如果需要 V2 客户端读取新对象，请先移至所有客户端升级到 V3 `REQUIRE_ENCRYPT_ALLOW_DECRYPT` 之后。最后，`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`只有在重新加密所有旧对象之后才考虑。

### ALG\_AES\_256\_GCM\_HKDF\_ \_COMMIT\_KEY SHA512 算法
<a name="s3-encryption-migration-v2-v3-aes-gcm-kc"></a>

该`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法是 V3 中引入的一种新的加密算法，它为存储在指令文件中的加密数据密钥提供了增强的安全性。

**指令文件影响：**该`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法仅影响指令文件，指令文件是单独的 S3 对象，用于存储包括加密数据密钥在内的加密元数据。在对象元数据（默认存储方法）中存储加密元数据的对象不受此算法变更的影响。

**防篡改：**该`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法通过加密方式将加密的数据密钥绑定到加密上下文，从而防止数据密钥被篡改。这可以防止攻击者在指令文件中替换不同的加密数据密钥，这可能会导致使用意想不到的密钥进行解密。

**版本兼容性：**使用该`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法加密的对象只能通过 V3 实现和包含 V3 解密支持的最新 V2 过渡版本的 SDK 进行解密。

**警告**  
**重要：**在使用`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法启用加密（通过使用`REQUIRE_ENCRYPT_ALLOW_DECRYPT`或`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`承诺策略）之前，必须确保将读取这些对象的所有客户端都已升级到 V3 或支持 V3 解密的最新 V2 过渡版本。未能先升级所有读取器将导致新加密对象的解密失败。

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

您必须先将现有客户端更新到最新的 SDK 版本。完成此步骤后，您的应用程序的 V2 客户端将能够解密由 V3 加密客户端加密的对象，而无需更新应用程序的代码库。

### 生成并安装最新版本的 适用于 C\+\+ 的 AWS SDK
<a name="s3-encryption-migration-v2-v3-build-install-sdk"></a>

 **从源代码使用 SDK 的应用程序** 

如果您 适用于 C\+\+ 的 AWS SDK 从源代码构建和安装，请从[`aws/aws-sdk-cpp`](https://github.com/aws/aws-sdk-cpp)上下载或克隆 SDK 源代码 GitHub。然后重复正常的构建和安装步骤。

如果您要 适用于 C\+\+ 的 AWS SDK 从 1.11.x 之前的版本升级，请参阅此[变更日志](https://github.com/aws/aws-sdk-cpp/blob/main/CHANGELOG.md)，了解每个主要版本中引入的重大更改。有关如何构建和安装的更多信息 适用于 C\+\+ 的 AWS SDK，请参阅[适用于 C\+\+ 的 AWS SDK 从源代码获取](sdk-from-source.md)。

 **从 Vcpkg 使用 SDK 的应用程序** 

如果您的应用程序使用 [Vcpkg](https://github.com/microsoft/vcpkg) 来跟踪 SDK 更新，只需使用现有的 Vcpkg 升级方法将 SDK 升级到最新版本即可。请记住，在版本发布和通过程序包管理器提供该版本之间会有延迟。最新版本始终可以通过[从源代码安装](sdk-from-source.md)获得。

您可以运行以下命令来升级程序包 `aws-sdk-cpp`：

```
vcpkg upgrade aws-sdk-cpp
```

并验证程序包 `aws-sdk-cpp` 的版本：

```
vcpkg list aws-sdk-cpp
```

版本应至少为 1.11.x 才能支持 v3 加密对象的解密。

有关将 Vcpkg 与配合使用的更多信息 适用于 C\+\+ 的 AWS SDK，请参阅。[适用于 C\+\+ 的 AWS SDK 从包管理器那里获取](sdk-from-pm.md)

### 构建、安装和部署您的应用程序
<a name="s3-encryption-migration-v2-v3-build-deploy-apps"></a>

如果您的应用程序静态链接到 适用于 C\+\+ 的 AWS SDK，则无需在应用程序中更改代码，但您必须重新构建应用程序才能使用最新的 SDK 更改。动态链接不需要完成此步骤。

升级应用程序的依赖版本并验证应用程序功能后，继续将应用程序部署到队列中。应用程序部署完成后，您可以继续下一阶段，将应用程序迁移到使用 V3 加密和解密客户端。

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

以下步骤向您展示如何成功地将代码从 Amazon S3 加密客户端的 V2 迁移到 V3。由于需要更改代码，因此无论应用程序是静态链接还是动态链接，您都需要重新构建应用程序。 适用于 C\+\+ 的 AWS SDK

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

V3 引入了该`S3EncryptionClientV3`类并`CryptoConfigurationV3`取代了 V2 的等效项。V3 的主要区别在于：
+ V3 使用`KMSWithContextEncryptionMaterials`（与 V2 相同），但需要在中进行显式配置。`CryptoConfigurationV3`
+ 所有`PutObject`操作都需要加密上下文映射（可以为空）。
+ V3 引入了承诺策略来控制加密和解密行为。
+ 默认情况下，V3 使用该`ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY`算法使用密钥承诺进行加密。
+ 旧版算法解密配置 API 从`config.SetSecurityProfile(SecurityProfile::V2_AND_LEGACY);`变为。`config.AllowLegacy();`

 **示例：使用 KMS 加密从 V2 迁移到 V3** 

 *迁移前 (V2)* 

```
// Create encryption materials
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV2", CUSTOMER_MASTER_KEY_ID);

// Create V2 crypto configuration
CryptoConfigurationV2 cryptoConfig(materials);

// Create V2 encryption client
S3EncryptionClientV2 encryptionClient(cryptoConfig);

// Put object with encryption context
Aws::Map<Aws::String, Aws::String> encryptionContext;
encryptionContext.emplace("client", "aws-sdk-cpp");
encryptionContext.emplace("version", "1.11.0");

PutObjectRequest putObjectRequest;
putObjectRequest.SetBucket(BUCKET_NAME);
putObjectRequest.SetKey(OBJECT_KEY);
// Set object body...

auto putOutcome = encryptionClient.PutObject(putObjectRequest, encryptionContext);

// Get object with encryption context
GetObjectRequest getObjectRequest;
getObjectRequest.SetBucket(BUCKET_NAME);
getObjectRequest.SetKey(OBJECT_KEY);

auto getOutcome = encryptionClient.GetObject(getObjectRequest, encryptionContext);
```

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

```
// Create encryption materials
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV3", CUSTOMER_MASTER_KEY_ID);

// Create V3 crypto configuration with materials
CryptoConfigurationV3 cryptoConfig(materials);

// Set commitment policy to maintain compatibility with V2 encrypted objects
// This allows V3 clients to decrypt objects encrypted by the V2 client
cryptoConfig.SetCommitmentPolicy(CommitmentPolicy::REQUIRE_ENCRYPT_ALLOW_DECRYPT);

// Create V3 encryption client
S3EncryptionClientV3 encryptionClient(cryptoConfig);

// Put object with encryption context
Aws::Map<Aws::String, Aws::String> encryptionContext;
encryptionContext.emplace("client", "aws-sdk-cpp");
encryptionContext.emplace("version", "1.11.0");

PutObjectRequest putObjectRequest;
putObjectRequest.SetBucket(BUCKET_NAME);
putObjectRequest.SetKey(OBJECT_KEY);
// Set object body...

auto putOutcome = encryptionClient.PutObject(putObjectRequest, encryptionContext);

// Get object with encryption context
GetObjectRequest getObjectRequest;
getObjectRequest.SetBucket(BUCKET_NAME);
getObjectRequest.SetKey(OBJECT_KEY);

auto getOutcome = encryptionClient.GetObject(getObjectRequest, encryptionContext);
```

 *迁移后（带有关键承诺的 V3）* 

```
// Create encryption materials
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV3", CUSTOMER_MASTER_KEY_ID);

// Create V3 crypto configuration with materials
CryptoConfigurationV3 cryptoConfig(materials);

// Use the default commitment policy (REQUIRE_ENCRYPT_REQUIRE_DECRYPT)
// This encrypts with key commitment and does not decrypt V2 objects
// cryptoConfig.SetCommitmentPolicy(CommitmentPolicy::REQUIRE_ENCRYPT_ALLOW_DECRYPT);

// Create V3 encryption client
S3EncryptionClientV3 encryptionClient(cryptoConfig);

// Put object with encryption context
Aws::Map<Aws::String, Aws::String> encryptionContext;
encryptionContext.emplace("client", "aws-sdk-cpp");
encryptionContext.emplace("version", "1.11.0");

PutObjectRequest putObjectRequest;
putObjectRequest.SetBucket(BUCKET_NAME);
putObjectRequest.SetKey(OBJECT_KEY);
// Set object body...

auto putOutcome = encryptionClient.PutObject(putObjectRequest, encryptionContext);

// Get object with encryption context
GetObjectRequest getObjectRequest;
getObjectRequest.SetBucket(BUCKET_NAME);
getObjectRequest.SetKey(OBJECT_KEY);

auto getOutcome = encryptionClient.GetObject(getObjectRequest, encryptionContext);
```

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

本节提供了其他示例，说明如何配置 V3 加密客户端选项以支持各种迁移场景和要求。

### 启用旧版 Support
<a name="s3-encryption-migration-v2-v3-examples-legacy-support"></a>

只有在使用`REQUIRE_ENCRYPT_ALLOW_DECRYPT`或`FORBID_ENCRYPT_ALLOW_DECRYPT`承诺策略时，V3 客户端才能解密由 V2 客户端加密的对象。但是，如果您需要解密由 V1 客户端加密的对象，则必须使用该方法显式启用旧版支持。`AllowLegacy()`

**何时使用传统支持：**
+ 您的 S3 中有使用 S3 加密客户端的 V1 加密的对象。
+ 在迁移过程中，您需要使用 V3 客户端读取这些 V1 加密的对象。
+ 您正在使用`REQUIRE_ENCRYPT_ALLOW_DECRYPT`或`FORBID_ENCRYPT_ALLOW_DECRYPT`承诺政策。

**警告**  
只能在迁移期间临时启用旧版支持。使用 V2 或 V3 重新加密所有 V1 对象后，请禁用旧版支持以确保最大的安全性。

**示例：启用旧版 Support**

```
// Create encryption materials
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV3", CUSTOMER_MASTER_KEY_ID);

// Create V3 crypto configuration
CryptoConfigurationV3 cryptoConfig(materials);

// Enable legacy support to read V1 encrypted objects
cryptoConfig.AllowLegacy();

// Set commitment policy (default is REQUIRE_ENCRYPT_REQUIRE_DECRYPT but we need to allow decryption)
cryptoConfig.SetCommitmentPolicy(CommitmentPolicy::REQUIRE_ENCRYPT_ALLOW_DECRYPT);

// Create V3 encryption client with legacy support enabled
S3EncryptionClientV3 encryptionClient(cryptoConfig);

// Now you can decrypt objects encrypted by V1, V2, and V3 clients
GetObjectRequest getObjectRequest;
getObjectRequest.SetBucket(BUCKET_NAME);
getObjectRequest.SetKey(LEGACY_OBJECT_KEY);

Aws::Map<Aws::String, Aws::String> encryptionContext;
auto getOutcome = encryptionClient.GetObject(getObjectRequest, encryptionContext);
```

### 配置存储方法
<a name="s3-encryption-migration-v2-v3-examples-storage-method"></a>

S3 Encryption Client 可以通过两种方式存储加密元数据：作为对象元数据（默认）或存储在单独的指令文件中。您可以使用上的方法配置存储`SetStorageMethod()`方法`CryptoConfigurationV3`。

**存储方法选项：**

**`METADATA`（默认）**  
加密元数据存储在对象的元数据标头中。这是最常见、最方便的方法，因为所有加密信息都与对象本身一起存储。  
**何时使用：**在大多数情况下使用此方法。它简化了对象管理，因为加密元数据会随对象一起传输。

**`INSTRUCTION_FILE`**  
加密元数据存储在带有后缀`.instruction`的单独的 S3 对象（指令文件）中。  
**何时使用：当需要**考虑对象元数据大小或需要将加密元数据与加密对象分开时，请使用此方法。请注意，使用指令文件需要管理两个 S3 对象（加密对象及其指令文件），而不是一个。

**示例：配置存储方法**

```
// Create encryption materials
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV3", CUSTOMER_MASTER_KEY_ID);

// Create V3 crypto configuration
CryptoConfigurationV3 cryptoConfig(materials);

// Option 1: Use metadata storage (default, can be omitted)
cryptoConfig.SetStorageMethod(StorageMethod::METADATA);

// Option 2: Use instruction file storage
cryptoConfig.SetStorageMethod(StorageMethod::INSTRUCTION_FILE);

// Create V3 encryption client with the configured storage method
S3EncryptionClientV3 encryptionClient(cryptoConfig);

// Put object - encryption metadata will be stored according to the configured method
Aws::Map<Aws::String, Aws::String> encryptionContext;
encryptionContext.emplace("client", "aws-sdk-cpp");

PutObjectRequest putObjectRequest;
putObjectRequest.SetBucket(BUCKET_NAME);
putObjectRequest.SetKey(OBJECT_KEY);
// Set object body...

auto putOutcome = encryptionClient.PutObject(putObjectRequest, encryptionContext);

// If using INSTRUCTION_FILE, a separate object with key "OBJECT_KEY.instruction" will be created
```

**注意**  
使用`INSTRUCTION_FILE`存储方法时，请记住，删除加密对象并不会自动删除指令文件。必须分别管理两个对象。