亚马逊 S3 加密客户端迁移(V2 到 V3) - 适用于 C++ 的 AWS SDK

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

亚马逊 S3 加密客户端迁移(V2 到 V3)

注意

如果您使用的是 Amazon S3 加密客户端的 V1,则必须先迁移到 V2,然后才能迁移到 V3。请参阅 亚马逊 S3 加密客户端迁移(从 V1 到 V2)

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

迁移概述

此迁移分为两个阶段:

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

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

理解 V3 概念

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

承诺政策

承诺策略控制加密客户端在加密和解密操作期间如何处理密钥承诺。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 算法

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_DECRYPTREQUIRE_ENCRYPT_REQUIRE_DECRYPT承诺策略)之前,必须确保将读取这些对象的所有客户端都已升级到 V3 或支持 V3 解密的最新 V2 过渡版本。未能先升级所有读取器将导致新加密对象的解密失败。

更新现有客户端以读取新格式

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

生成并安装最新版本的 适用于 C++ 的 AWS SDK

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

如果您 适用于 C++ 的 AWS SDK 从源代码构建和安装,请从aws/aws-sdk-cpp上下载或克隆 SDK 源代码 GitHub。然后重复正常的构建和安装步骤。

如果您要 适用于 C++ 的 AWS SDK 从 1.11.x 之前的版本升级,请参阅此变更日志,了解每个主要版本中引入的重大更改。有关如何构建和安装的更多信息 适用于 C++ 的 AWS SDK,请参阅 从源代码获取适用于 C++ 的 AWS SDK

从 Vcpkg 使用 SDK 的应用程序

如果您的应用程序使用 Vcpkg 来跟踪 SDK 更新,只需使用现有的 Vcpkg 升级方法将 SDK 升级到最新版本即可。请记住,在版本发布和通过程序包管理器提供该版本之间会有延迟。最新版本始终可以通过从源代码安装获得。

您可以运行以下命令来升级程序包 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

构建、安装和部署您的应用程序

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

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

将加密和解密客户端迁移到 V3

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

使用 V3 加密客户端

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);

其他示例

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

启用旧版 Support

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

何时使用传统支持:

  • 您的 S3 中有使用 S3 加密客户端的 V1 加密的对象。

  • 在迁移过程中,您需要使用 V3 客户端读取这些 V1 加密的对象。

  • 您正在使用REQUIRE_ENCRYPT_ALLOW_DECRYPTFORBID_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);

配置存储方法

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存储方法时,请记住,删除加密对象并不会自动删除指令文件。必须分别管理两个对象。