Amazon S3 Encryption Client Migration (V2 to V3)
Note
If you are using V1 of the Amazon S3 encryption client, you must first migrate to V2 before migrating to V3. See Amazon S3 Encryption Client Migration (V1 to V2).
This topic shows how to migrate your applications from Version 2 (V2) to Version 3 (V3) of the Amazon Simple Storage Service (Amazon S3) encryption client
and ensure application availability throughout the migration process. V3 introduces the ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm and Commitment Policies
to enhance security by protecting against data key tampering in Instruction Files.
Migration Overview
This migration happens in two phases:
1. Update existing clients to read new formats. First, deploy an updated version of the Amazon SDK for C++ to your application. This allows existing V2 encryption clients to decrypt objects written by the new V3 clients. If your application uses multiple Amazon SDKs, you must upgrade each SDK separately.
2. Migrate encryption and decryption clients to V3. Once all of your V2 encryption clients can read new formats, you can migrate your existing encryption and decryption clients to their respective V3 versions.
Understanding V3 Concepts
Version 3 of the Amazon S3 encryption client introduces new security features that enhance protection against data key tampering. Understanding these concepts is essential for a successful migration.
Commitment Policy
Commitment Policies control how the encryption client handles key commitment during encryption and decryption operations. V3 provides three policy options to support different migration scenarios and security requirements:
FORBID_ENCRYPT_ALLOW_DECRYPT-
Encryption behavior: Encrypts objects without key commitment, using the same algorithms as V2.
Decryption behavior: Allows decryption of objects encrypted with and without key commitment.
Security implications: This policy does not enforce key commitment and may allow tampering with the encrypted data key in Instruction Files. Use this policy only during the initial migration phase when you need V2 clients to read newly encrypted objects.
Version compatibility: Objects encrypted with this policy can be read by all V2 and V3 implementations.
REQUIRE_ENCRYPT_ALLOW_DECRYPT(Default)-
Encryption behavior: Encrypts objects with key commitment using the
ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEYalgorithm.Decryption behavior: Allows decryption of both objects encrypted with key commitment and objects encrypted without key commitment.
Security implications: This policy provides strong security for newly encrypted objects while maintaining backward compatibility for reading older objects. This is the recommended policy for most migration scenarios.
Version compatibility: Objects encrypted with this policy can only be read by V3 and the latest V2 implementations. V2 clients cannot decrypt these objects. However, V3 clients using this policy can still decrypt objects encrypted by V2 clients.
REQUIRE_ENCRYPT_REQUIRE_DECRYPT-
Encryption behavior: Encrypts objects with key commitment using the
ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEYalgorithm.Decryption behavior: Only allows decryption of objects encrypted with key commitment. Rejects objects encrypted without key commitment.
Security implications: This policy provides the highest level of security by enforcing key commitment for all operations. Use this policy only after all objects have been re-encrypted with key commitment and you no longer need to read legacy V1 or V2 encrypted objects.
Version compatibility: Objects encrypted with this policy can only be read by V3 and the latest V2 implementations. Additionally, clients using this policy cannot decrypt objects encrypted by V1 or V2 clients.
Migration considerations: During migration, start with FORBID_ENCRYPT_ALLOW_DECRYPT if you
need V2 clients to read new objects, then move to REQUIRE_ENCRYPT_ALLOW_DECRYPT once all clients are upgraded
to V3. Finally, consider REQUIRE_ENCRYPT_REQUIRE_DECRYPT only after all legacy objects have been re-encrypted.
ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY Algorithm
The ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm is a new encryption algorithm introduced in V3 that provides enhanced
security for encrypted data keys stored in Instruction Files.
Instruction File impact: The ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm only impacts Instruction Files, which are separate
S3 objects that store encryption metadata including the encrypted data key. Objects that store encryption metadata in object metadata
(the default storage method) are not affected by this algorithm change.
Protection against tampering: The ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm protects against data key tampering by cryptographically
binding the encrypted data key to the encryption context. This prevents attackers from substituting a different encrypted data key
in the Instruction File, which could potentially lead to decryption with an unintended key.
Version compatibility: Objects encrypted with the ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm can only be decrypted by
V3 implementations and the latest V2 transition versions of the SDK that include V3 decryption support.
Warning
Important: Before enabling encryption with the ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm (by using
REQUIRE_ENCRYPT_ALLOW_DECRYPT or REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policies), you must
ensure that all clients that will read these objects have been upgraded to V3 or the latest V2 transition version that supports V3 decryption.
Failure to upgrade all readers first will result in decryption failures for newly encrypted objects.
Update Existing Clients to Read New Formats
You must first update your existing clients to the latest SDK release. After completing this step, your application's V2 clients will be able to decrypt objects encrypted by V3 encryption clients without updating your application's code base.
Build and Install the Latest Version of the Amazon SDK for C++
Applications Consuming the SDK from Source
If you build and install the Amazon SDK for C++ from source, download or clone the SDK source from aws/aws-sdk-cpp
If you are upgrading Amazon SDK for C++ from a version earlier than 1.11.x, see this CHANGELOG
Applications Consuming the SDK from Vcpkg
If your application uses Vcpkg
You can run the following command to upgrade package aws-sdk-cpp:
vcpkg upgrade aws-sdk-cpp
And verify the version of package aws-sdk-cpp:
vcpkg list aws-sdk-cpp
The version should be at least 1.11.x to support decryption of V3-encrypted objects.
For more information on using Vcpkg with the Amazon SDK for C++, see Getting the Amazon SDK for C++ from a package manager.
Build, Install, and Deploy Your Applications
If your application is statically linking against the Amazon SDK for C++, code changes are not required in your application, but you must build your application again to consume the latest SDK changes. This step is not necessary for dynamic linking.
After upgrading your application's dependency version and verifying application functionality, proceed to deploying your application to your fleet. Once application deployment is complete, you can proceed with the next phase for migrating your application to use the V3 encryption and decryption clients.
Migrate Encryption and Decryption Clients to V3
The following steps show you how to successfully migrate your code from V2 to V3 of the Amazon S3 encryption client. Since code changes are required, you will need to rebuild your application regardless of whether it's statically or dynamically linking against the Amazon SDK for C++.
Using V3 Encryption Clients
V3 introduces the S3EncryptionClientV3 class and CryptoConfigurationV3 to replace the V2 equivalents.
The key differences in V3 are:
-
V3 uses
KMSWithContextEncryptionMaterials(same as V2) but requires explicit configuration inCryptoConfigurationV3. -
All
PutObjectoperations require an encryption context map (can be empty). -
V3 introduces Commitment Policies to control encryption and decryption behavior.
-
By default, V3 encrypts with key commitment using the
ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEYalgorithm. -
The legacy algorithm decryption configuration API changes from
config.SetSecurityProfile(SecurityProfile::V2_AND_LEGACY);toconfig.AllowLegacy();.
Example: Migrating from V2 to V3 with KMS Encryption
Pre-migration (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);
During migration (V3 with backward compatibility)
// 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);
Post-migration (V3 with key commitment)
// 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);
Additional Examples
This section provides additional examples for configuring V3 encryption client options to support various migration scenarios and requirements.
Enabling Legacy Support
V3 clients can decrypt objects encrypted by V2 clients only when using the REQUIRE_ENCRYPT_ALLOW_DECRYPT or
FORBID_ENCRYPT_ALLOW_DECRYPT commitment policies. However, if you need to decrypt objects encrypted by V1 clients,
you must explicitly enable legacy support using the AllowLegacy() method.
When to use legacy support:
-
You have objects in S3 that were encrypted using V1 of the S3 Encryption Client.
-
You need to read these V1-encrypted objects with your V3 client during the migration process.
-
You are using the
REQUIRE_ENCRYPT_ALLOW_DECRYPTorFORBID_ENCRYPT_ALLOW_DECRYPTcommitment policy.
Warning
Legacy support should only be enabled temporarily during migration. Once all V1 objects have been re-encrypted with V2 or V3, disable legacy support to ensure maximum security.
Example: Enabling Legacy 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);
Configuring Storage Method
The S3 Encryption Client can store encryption metadata in two ways: as object metadata (the default) or in a separate Instruction File.
You can configure the storage method using the SetStorageMethod() method on CryptoConfigurationV3.
Storage method options:
METADATA(Default)-
Encryption metadata is stored in the object's metadata headers. This is the most common and convenient method as all encryption information is stored with the object itself.
When to use: Use this method for most scenarios. It simplifies object management since encryption metadata travels with the object.
INSTRUCTION_FILE-
Encryption metadata is stored in a separate S3 object (the Instruction File) with the suffix
.instruction.When to use: Use this method when object metadata size is a concern or when you need to separate encryption metadata from the encrypted object. Note that using Instruction Files requires managing two S3 objects (the encrypted object and its instruction file) instead of one.
Example: Configuring Storage Method
// 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
Note
When using the INSTRUCTION_FILE storage method, remember that deleting the encrypted object does not automatically
delete the instruction file. You must manage both objects separately.