From 3666a04a3930df65ad2ffcef4d715e926431ce5a Mon Sep 17 00:00:00 2001 From: rishav-karanjit Date: Tue, 10 Jun 2025 13:43:21 -0700 Subject: [PATCH 1/2] Preserve only changes in examples directory after rebase --- .../go/itemencryptor/itemencryptdecrypt.go | 180 ++++++++++++++++ Examples/runtimes/go/main.go | 9 + .../runtimes/go/misc/createBranchKeyID.go | 64 ++++++ .../go/misc/getEncryptedDataKeyDescription.go | 75 +++++++ Examples/runtimes/go/misc/multiPutGet.go | 196 ++++++++++++++++++ Examples/runtimes/go/utils/exampleUtils.go | 25 ++- 6 files changed, 544 insertions(+), 5 deletions(-) create mode 100644 Examples/runtimes/go/itemencryptor/itemencryptdecrypt.go create mode 100644 Examples/runtimes/go/misc/createBranchKeyID.go create mode 100644 Examples/runtimes/go/misc/getEncryptedDataKeyDescription.go create mode 100644 Examples/runtimes/go/misc/multiPutGet.go diff --git a/Examples/runtimes/go/itemencryptor/itemencryptdecrypt.go b/Examples/runtimes/go/itemencryptor/itemencryptdecrypt.go new file mode 100644 index 000000000..6bc9c0ebe --- /dev/null +++ b/Examples/runtimes/go/itemencryptor/itemencryptdecrypt.go @@ -0,0 +1,180 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package itemencryptor + +import ( + "context" + "fmt" + "reflect" + + mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated" + mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes" + itemencryptor "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbitemencryptorsmithygenerated" + dbesdkitemencryptortypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbitemencryptorsmithygeneratedtypes" + dbesdkstructuredencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkstructuredencryptionsmithygeneratedtypes" + "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/aws-sdk-go-v2/service/kms" +) + +/* +This example sets up a DynamoDb Item Encryptor and uses +the EncryptItem and DecryptItem APIs to directly encrypt and +decrypt an existing DynamoDb item. +You should use the DynamoDb Item Encryptor +if you already have a DynamoDb Item to encrypt or decrypt, +and do not need to make a Put or Get call to DynamoDb. +For example, if you are using DynamoDb Streams, +you may already be working with an encrypted item obtained from +DynamoDb, and want to directly decrypt the item. + +Running this example requires access to the DDB Table whose name +is provided in CLI arguments. +This table must be configured with the following +primary key configuration: +- Partition key is named "partition_key" with type (S) +- Sort key is named "sort_key" with type (S) +*/ + +func ItemEncryptDecryptExample(kmsKeyID, ddbTableName string) { + // 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data. + // For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use. + // We will use the `CreateMrkMultiKeyring` method to create this keyring, + // as it will correctly handle both single region and Multi-Region KMS Keys. + + cfg, err := config.LoadDefaultConfig(context.TODO()) + utils.HandleError(err) + // Create KMS client + kmsClient := kms.NewFromConfig(cfg) + // Initialize the mpl client + matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{}) + utils.HandleError(err) + // Create the Aws Kms Keyring + awsKmsKeyringInput := mpltypes.CreateAwsKmsKeyringInput{ + KmsClient: kmsClient, + KmsKeyId: kmsKeyID, + } + keyring, err := matProv.CreateAwsKmsKeyring(context.Background(), awsKmsKeyringInput) + utils.HandleError(err) + + // 2. Configure which attributes are encrypted and/or signed when writing new items. + // For each attribute that may exist on the items we plan to write to our DynamoDbTable, + // we must explicitly configure how they should be treated during item encryption: + // - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature + // - SIGN_ONLY: The attribute not encrypted, but is still included in the signature + // - DO_NOTHING: The attribute is not encrypted and not included in the signature + attributeActions := map[string]dbesdkstructuredencryptiontypes.CryptoAction{ + "partition_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Partition key must be SIGN_ONLY + "sort_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Sort key must be SIGN_ONLY + "attribute1": dbesdkstructuredencryptiontypes.CryptoActionEncryptAndSign, + "attribute2": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, + ":attribute3": dbesdkstructuredencryptiontypes.CryptoActionDoNothing, + } + + // 3. Configure which attributes we expect to be included in the signature + // when reading items. There are two options for configuring this: + // + // - (Recommended) Configure `allowedUnsignedAttributesPrefix`: + // When defining your DynamoDb schema and deciding on attribute names, + // choose a distinguishing prefix (such as ":") for all attributes that + // you do not want to include in the signature. + // This has two main benefits: + // - It is easier to reason about the security and authenticity of data within your item + // when all unauthenticated data is easily distinguishable by their attribute name. + // - If you need to add new unauthenticated attributes in the future, + // you can easily make the corresponding update to your `attributeActionsOnEncrypt` + // and immediately start writing to that new attribute, without + // any other configuration update needed. + // Once you configure this field, it is not safe to update it. + // + // - Configure `allowedUnsignedAttributes`: You may also explicitly list + // a set of attributes that should be considered unauthenticated when encountered + // on read. Be careful if you use this configuration. Do not remove an attribute + // name from this configuration, even if you are no longer writing with that attribute, + // as old items may still include this attribute, and our configuration needs to know + // to continue to exclude this attribute from the signature scope. + // If you add new attribute names to this field, you must first deploy the update to this + // field to all readers in your host fleet before deploying the update to start writing + // with that new attribute. + // + // For this example, we have designed our DynamoDb table such that any attribute name with + // the ":" prefix should be considered unauthenticated. + allowedUnsignedAttributePrefix := ":" + + // 4. Create the DynamoDb Encryption configuration for the table we will be writing to. + partitionKey := "partition_key" + sortKeyName := "sort_key" + algorithmSuiteID := mpltypes.DBEAlgorithmSuiteIdAlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384 + itemEncryptorConfig := dbesdkitemencryptortypes.DynamoDbItemEncryptorConfig{ + LogicalTableName: ddbTableName, + PartitionKeyName: partitionKey, + SortKeyName: &sortKeyName, + AttributeActionsOnEncrypt: attributeActions, + Keyring: keyring, + AllowedUnsignedAttributePrefix: &allowedUnsignedAttributePrefix, + // Specifying an algorithm suite is not required, + // but is done here to demonstrate how to do so. + // We suggest using the + // `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite, + // which includes AES-GCM with key derivation, signing, and key commitment. + // This is also the default algorithm suite if one is not specified in this config. + // For more information on supported algorithm suites, see: + // https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html + AlgorithmSuiteId: &algorithmSuiteID, + } + + // 5. Create the DynamoDb Item Encryptor + itemEncryptorClient, err := itemencryptor.NewClient(itemEncryptorConfig) + utils.HandleError(err) + + // 6. Directly encrypt a DynamoDb item using the DynamoDb Item Encryptor + item := map[string]types.AttributeValue{ + "partition_key": &types.AttributeValueMemberS{Value: "ItemEncryptDecryptExample"}, + "sort_key": &types.AttributeValueMemberS{Value: "0"}, + "attribute1": &types.AttributeValueMemberS{Value: "encrypt and sign me!"}, + "attribute2": &types.AttributeValueMemberS{Value: "sign me!"}, + ":attribute3": &types.AttributeValueMemberS{Value: "ignore me!"}, + } + encryptItemInput := &dbesdkitemencryptortypes.EncryptItemInput{ + PlaintextItem: item, + } + encryptItemOutput, err := itemEncryptorClient.EncryptItem(context.Background(), *encryptItemInput) + utils.HandleError(err) + + // Demonstrate that the item has been encrypted + encryptedItem := encryptItemOutput.EncryptedItem + // Check partition_key is still a string and equals "ItemEncryptDecryptExample" + if partitionKeyAttr, ok := encryptedItem["partition_key"].(*types.AttributeValueMemberS); ok { + if partitionKeyAttr.Value != "ItemEncryptDecryptExample" { + panic("Partition key is not 'ItemEncryptDecryptExample'") + } + } else { + panic("Partition key is not a string attribute or doesn't exist") + } + // Check sort_key is a string and equals "0" + if sortKeyAttr, ok := encryptedItem["sort_key"].(*types.AttributeValueMemberS); ok { + if sortKeyAttr.Value != "0" { + panic("Sort key is not '0'") + } + } else { + panic("Sort key is not a string attribute or doesn't exist") + } + // Check attribute1 is binary (encrypted) and not a string anymore + if _, ok := encryptedItem["attribute1"].(*types.AttributeValueMemberB); !ok { + panic("attribute1 is not binary. It might not be encrypted.") + } + + // 7. Directly decrypt the encrypted item using the DynamoDb Item Encryptor + decryptItemInput := &dbesdkitemencryptortypes.DecryptItemInput{ + EncryptedItem: encryptedItem, + } + decryptedItem, err := itemEncryptorClient.DecryptItem(context.Background(), *decryptItemInput) + utils.HandleError(err) + + if !reflect.DeepEqual(item, decryptedItem.PlaintextItem) { + panic("Decrypted item does not match original item") + } + fmt.Println("Item Encryptor example successful") +} diff --git a/Examples/runtimes/go/main.go b/Examples/runtimes/go/main.go index aa28f3d9d..b9e6b4fc9 100644 --- a/Examples/runtimes/go/main.go +++ b/Examples/runtimes/go/main.go @@ -1,11 +1,20 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + package main import ( + "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/itemencryptor" "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/keyring" + "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/misc" "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils" ) func main() { keyring.AwsKmsKeyringExample(utils.KmsKeyID(), utils.DdbTableName()) keyring.RawAesExample(utils.DdbTableName(), utils.KeyNamespace(), utils.KeyName(), utils.GenerateAes256KeyBytes()) + itemencryptor.ItemEncryptDecryptExample(utils.KmsKeyID(), utils.DdbTableName()) + misc.GetEncryptedDataKeyDescriptionExample(utils.KmsKeyID(), utils.DdbTableName()) + misc.MultiPutGetExample(utils.KmsKeyID(), utils.DdbTableName()) + misc.CreateBranchKeyIDExample(utils.TestKeystoreName(), utils.TestLogicalKeystoreName(), utils.TestKeystoreKmsKeyId()) } diff --git a/Examples/runtimes/go/misc/createBranchKeyID.go b/Examples/runtimes/go/misc/createBranchKeyID.go new file mode 100644 index 000000000..f05103291 --- /dev/null +++ b/Examples/runtimes/go/misc/createBranchKeyID.go @@ -0,0 +1,64 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package misc + +import ( + "context" + "fmt" + + keystore "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographykeystoresmithygenerated" + keystoretypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographykeystoresmithygeneratedtypes" + "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/kms" +) + +/* + The Hierarchical Keyring Example and Searchable Encryption Examples + rely on the existence of a DDB-backed key store with pre-existing + branch key material or beacon key material. + + See the "Create KeyStore Table Example" for how to first set up + the DDB Table that will back this KeyStore. + + This example demonstrates configuring a KeyStore and then + using a helper method to create a branch key and beacon key + that share the same Id, then return that Id. + We will always create a new beacon key alongside a new branch key, + even if you are not using searchable encryption. + + This key creation should occur within your control plane. +*/ + +func CreateBranchKeyIDExample( + keyStoreTableName, + logicalKeyStoreName, + kmsKeyArn string) { + cfg, err := config.LoadDefaultConfig(context.TODO()) + utils.HandleError(err) + ddbClient := dynamodb.NewFromConfig(cfg) + kmsClient := kms.NewFromConfig(cfg) + // 1. Configure your KeyStore resource. + // This SHOULD be the same configuration that was used to create the DDB table + // in the "Create KeyStore Table Example". + kmsConfig := keystoretypes.KMSConfigurationMemberkmsKeyArn{ + Value: kmsKeyArn, + } + keyStore, err := keystore.NewClient(keystoretypes.KeyStoreConfig{ + DdbTableName: keyStoreTableName, + KmsConfiguration: &kmsConfig, + LogicalKeyStoreName: logicalKeyStoreName, + DdbClient: ddbClient, + KmsClient: kmsClient, + }) + utils.HandleError(err) + // 2. Create a new branch key and beacon key in our KeyStore. + // Both the branch key and the beacon key will share an Id. + // This creation is eventually consistent. + branchKey, err := keyStore.CreateKey(context.Background(), keystoretypes.CreateKeyInput{}) + utils.HandleError(err) + + fmt.Println("Branch Key ID " + branchKey.BranchKeyIdentifier + " created in Create Branch Key ID Example.") +} diff --git a/Examples/runtimes/go/misc/getEncryptedDataKeyDescription.go b/Examples/runtimes/go/misc/getEncryptedDataKeyDescription.go new file mode 100644 index 000000000..3dbf85414 --- /dev/null +++ b/Examples/runtimes/go/misc/getEncryptedDataKeyDescription.go @@ -0,0 +1,75 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package misc + +import ( + "context" + "fmt" + + dbesdkdynamodbencryption "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygenerated" + dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes" + "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" +) + +func GetEncryptedDataKeyDescriptionExample(kmsKeyID, ddbTableName string) { + cfg, err := config.LoadDefaultConfig(context.TODO()) + utils.HandleError(err) + ddbec, err := dbesdkdynamodbencryption.NewClient(dbesdkdynamodbencryptiontypes.DynamoDbEncryptionConfig{}) + utils.HandleError(err) + // 1. Define keys that will be used to retrieve item from the DynamoDB table. + keyToGet := map[string]types.AttributeValue{ + "partition_key": &types.AttributeValueMemberS{Value: "BasicPutGetExample"}, + "sort_key": &types.AttributeValueMemberN{Value: "0"}, + } + + // 2. Create a Amazon DynamoDB Client and retrieve item from DynamoDB table + ddb := dynamodb.NewFromConfig(cfg) + + // 3. Extract the item from the dynamoDB table and prepare input for the GetEncryptedDataKeyDescription method. + // Here, we are sending dynamodb item but you can also input the header itself by extracting the header from + // "aws_dbe_head" attribute in the dynamoDB item. The part of the code where we send input as the header is commented. + getInput := &dynamodb.GetItemInput{ + TableName: aws.String(ddbTableName), + Key: keyToGet, + // In this example we configure a strongly consistent read + // because we perform a read immediately after a write (for demonstrative purposes). + // By default, reads are only eventually consistent. + // Read our docs to determine which read consistency to use for your application: + // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html + ConsistentRead: aws.Bool(true), + } + returnedItem, err := ddb.GetItem(context.TODO(), getInput) + utils.HandleError(err) + inputUnion := dbesdkdynamodbencryptiontypes.GetEncryptedDataKeyDescriptionUnionMemberitem{ + Value: returnedItem.Item, + } + + // The code below shows how we can send header as the input to the DynamoDB. This code is written to demo the + // alternative approach. So, it is commented. + // headerAttribute := "aws_dbe_head" + // headerBytes, ok := returnedItem.Item[headerAttribute].(*types.AttributeValueMemberB) + // if !ok { + // panic("attribute1 is not binary. It might not be encrypted.") + // } + // inputUnion := dbesdkdynamodbencryptiontypes.GetEncryptedDataKeyDescriptionUnionMemberheader{ + // Value: headerBytes.Value, + // } + + encryptedDataKeyDescriptionInput := dbesdkdynamodbencryptiontypes.GetEncryptedDataKeyDescriptionInput{ + Input: &inputUnion, + } + encryptedDataKeyDescription, err := ddbec.GetEncryptedDataKeyDescription(context.TODO(), encryptedDataKeyDescriptionInput) + utils.HandleError(err) + + if encryptedDataKeyDescription.EncryptedDataKeyDescriptionOutput[0].KeyProviderId != "aws-kms" { + panic("Key provider should have been aws-kms") + } + if *encryptedDataKeyDescription.EncryptedDataKeyDescriptionOutput[0].KeyProviderInfo != kmsKeyID { + panic("Key provider info should have been " + kmsKeyID) + } + fmt.Println("Get encrypted data Key description example successful.") +} diff --git a/Examples/runtimes/go/misc/multiPutGet.go b/Examples/runtimes/go/misc/multiPutGet.go new file mode 100644 index 000000000..91cf4579b --- /dev/null +++ b/Examples/runtimes/go/misc/multiPutGet.go @@ -0,0 +1,196 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package misc + +import ( + "context" + "fmt" + "reflect" + + mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated" + mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes" + dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes" + dbesdkstructuredencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkstructuredencryptionsmithygeneratedtypes" + "github.com/aws/aws-database-encryption-sdk-dynamodb/dbesdkmiddleware" + "github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" +) + +/* +This example sets up DynamoDb Encryption for the AWS SDK client +and uses the low level PutItem and GetItem DDB APIs to demonstrate +putting a client-side encrypted item into DynamoDb +and then retrieving and decrypting that item from DynamoDb. + +Running this example requires access to the DDB Table whose name +is provided in CLI arguments. +This table must be configured with the following +primary key configuration: + - Partition key is named "partition_key" with type (S) + - Sort key is named "sort_key" with type (N) +*/ +func MultiPutGetExample(kmsKeyID, ddbTableName string) { + cfg, err := config.LoadDefaultConfig(context.TODO()) + utils.HandleError(err) + // Initialize the mpl client + matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{}) + utils.HandleError(err) + // 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data. + // For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use. + // We will use the `CreateAwsKmsMultiKeyring` method to create this keyring, + // as it will correctly handle both single region and Multi-Region KMS Keys. + generatorKeyID := kmsKeyID + awsKmsMultiKeyringInput := mpltypes.CreateAwsKmsMultiKeyringInput{ + Generator: &generatorKeyID, + } + keyring, err := matProv.CreateAwsKmsMultiKeyring(context.Background(), awsKmsMultiKeyringInput) + utils.HandleError(err) + + // 2. Configure which attributes are encrypted and/or signed when writing new items. + // For each attribute that may exist on the items we plan to write to our DynamoDbTable, + // we must explicitly configure how they should be treated during item encryption: + // - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature + // - SIGN_ONLY: The attribute not encrypted, but is still included in the signature + // - DO_NOTHING: The attribute is not encrypted and not included in the signature + attributeActions := map[string]dbesdkstructuredencryptiontypes.CryptoAction{ + "partition_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Partition key must be SIGN_ONLY + "sort_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Sort key must be SIGN_ONLY + "attribute1": dbesdkstructuredencryptiontypes.CryptoActionEncryptAndSign, + "attribute2": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, + ":attribute3": dbesdkstructuredencryptiontypes.CryptoActionDoNothing, + } + + // 3. Configure which attributes we expect to be included in the signature + // when reading items. There are two options for configuring this: + // + // - (Recommended) Configure `allowedUnsignedAttributesPrefix`: + // When defining your DynamoDb schema and deciding on attribute names, + // choose a distinguishing prefix (such as ":") for all attributes that + // you do not want to include in the signature. + // This has two main benefits: + // - It is easier to reason about the security and authenticity of data within your item + // when all unauthenticated data is easily distinguishable by their attribute name. + // - If you need to add new unauthenticated attributes in the future, + // you can easily make the corresponding update to your `attributeActionsOnEncrypt` + // and immediately start writing to that new attribute, without + // any other configuration update needed. + // Once you configure this field, it is not safe to update it. + // + // - Configure `allowedUnsignedAttributes`: You may also explicitly list + // a set of attributes that should be considered unauthenticated when encountered + // on read. Be careful if you use this configuration. Do not remove an attribute + // name from this configuration, even if you are no longer writing with that attribute, + // as old items may still include this attribute, and our configuration needs to know + // to continue to exclude this attribute from the signature scope. + // If you add new attribute names to this field, you must first deploy the update to this + // field to all readers in your host fleet before deploying the update to start writing + // with that new attribute. + // + // For this example, we have designed our DynamoDb table such that any attribute name with + // the ":" prefix should be considered unauthenticated. + allowedUnsignedAttributePrefix := ":" + + // 4. Create the DynamoDb Encryption configuration for the table we will be writing to. + partitionKey := "partition_key" + sortKeyName := "sort_key" + algorithmSuiteID := mpltypes.DBEAlgorithmSuiteIdAlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384 + tableConfig := dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig{ + LogicalTableName: ddbTableName, + PartitionKeyName: partitionKey, + SortKeyName: &sortKeyName, + AttributeActionsOnEncrypt: attributeActions, + Keyring: keyring, + AllowedUnsignedAttributePrefix: &allowedUnsignedAttributePrefix, + // Specifying an algorithm suite is not required, + // but is done here to demonstrate how to do so. + // We suggest using the + // `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite, + // which includes AES-GCM with key derivation, signing, and key commitment. + // This is also the default algorithm suite if one is not specified in this config. + // For more information on supported algorithm suites, see: + // https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html + AlgorithmSuiteId: &algorithmSuiteID, + } + tableConfigsMap := make(map[string]dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig) + tableConfigsMap[ddbTableName] = tableConfig + listOfTableConfigs := dbesdkdynamodbencryptiontypes.DynamoDbTablesEncryptionConfig{ + TableEncryptionConfigs: tableConfigsMap, + } + // 5. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs + dbEsdkMiddleware, err := dbesdkmiddleware.NewDBEsdkMiddleware(listOfTableConfigs) + utils.HandleError(err) + ddb := dynamodb.NewFromConfig(cfg, dbEsdkMiddleware.CreateMiddleware()) + + // 6. Put an item into our table using the above client. + // Before the item gets sent to DynamoDb, it will be encrypted + // client-side, according to our configuration. + item := map[string]types.AttributeValue{ + "partition_key": &types.AttributeValueMemberS{Value: "WriteItemExample"}, + "sort_key": &types.AttributeValueMemberN{Value: "0"}, + "attribute1": &types.AttributeValueMemberS{Value: "encrypt and sign me!"}, + "attribute2": &types.AttributeValueMemberS{Value: "sign me!"}, + ":attribute3": &types.AttributeValueMemberS{Value: "ignore me!"}, + } + putbatchWriteItemInput := &dynamodb.PutItemInput{ + TableName: aws.String(ddbTableName), + Item: item, + } + _, err = ddb.PutItem(context.TODO(), putbatchWriteItemInput) + utils.HandleError(err) + + transactWriteItemsInput := &dynamodb.TransactWriteItemsInput{ + TransactItems: []types.TransactWriteItem{ + { + Put: &types.Put{ + TableName: aws.String(ddbTableName), + Item: item, + }, + }, + }, + } + _, err = ddb.TransactWriteItems(context.TODO(), transactWriteItemsInput) + utils.HandleError(err) + + // 7. Get the item back from our table using the same client. + // The client will decrypt the item client-side, and return + // back the original item. + key := map[string]types.AttributeValue{ + "partition_key": &types.AttributeValueMemberS{Value: "WriteItemExample"}, + "sort_key": &types.AttributeValueMemberN{Value: "0"}, + } + getInput := &dynamodb.GetItemInput{ + TableName: aws.String(ddbTableName), + Key: key, + // In this example we configure a strongly consistent read + // because we perform a read immediately after a write (for demonstrative purposes). + // By default, reads are only eventually consistent. + // Read our docs to determine which read consistency to use for your application: + // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html + ConsistentRead: aws.Bool(true), + } + result, err := ddb.GetItem(context.TODO(), getInput) + utils.HandleError(err) + // Verify the decrypted item + if !reflect.DeepEqual(item, result.Item) { + panic("Decrypted item does not match original item") + } + + transactGetItemsInput := &dynamodb.TransactGetItemsInput{ + TransactItems: []types.TransactGetItem{ + { + Get: &types.Get{ + Key: key, + TableName: aws.String(ddbTableName), + }, + }, + }, + } + _, err = ddb.TransactGetItems(context.TODO(), transactGetItemsInput) + utils.HandleError(err) + fmt.Println("MultiPutGetExample successful") +} diff --git a/Examples/runtimes/go/utils/exampleUtils.go b/Examples/runtimes/go/utils/exampleUtils.go index 0b9e01104..dbef8b63f 100644 --- a/Examples/runtimes/go/utils/exampleUtils.go +++ b/Examples/runtimes/go/utils/exampleUtils.go @@ -6,13 +6,28 @@ package utils import "crypto/rand" const ( - kmsKeyID = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" - ddbTableName = "DynamoDbEncryptionInterceptorTestTableCS" - keyNamespace = "my-key-namespace" - keyName = "my-key-name" - aesKeyBytes = 32 // 256 bits = 32 bytes + kmsKeyID = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" + ddbTableName = "DynamoDbEncryptionInterceptorTestTableCS" + keyNamespace = "my-key-namespace" + keyName = "my-key-name" + aesKeyBytes = 32 // 256 bits = 32 bytes + testKeystoreName = "KeyStoreDdbTable" + testLogicalKeystoreName = "KeyStoreDdbTable" + testKeystoreKmsKeyId = "arn:aws:kms:us-west-2:370957321024:key/9d989aa2-2f9c-438c-a745-cc57d3ad0126" ) +func TestKeystoreName() string { + return testKeystoreName +} + +func TestLogicalKeystoreName() string { + return testLogicalKeystoreName +} + +func TestKeystoreKmsKeyId() string { + return testKeystoreKmsKeyId +} + func KmsKeyID() string { return kmsKeyID } From ef88ab83e828386f22ecdf651fc6eb6ade7db66f Mon Sep 17 00:00:00 2001 From: rishav-karanjit Date: Tue, 10 Jun 2025 13:44:20 -0700 Subject: [PATCH 2/2] empty commit