Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 45ec157

Browse files
chore(go): add item encryptor and misc examples (#1873)
1 parent b532564 commit 45ec157

File tree

6 files changed

+544
-5
lines changed

6 files changed

+544
-5
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package itemencryptor
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"reflect"
10+
11+
mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated"
12+
mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes"
13+
itemencryptor "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbitemencryptorsmithygenerated"
14+
dbesdkitemencryptortypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbitemencryptorsmithygeneratedtypes"
15+
dbesdkstructuredencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkstructuredencryptionsmithygeneratedtypes"
16+
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils"
17+
"github.com/aws/aws-sdk-go-v2/config"
18+
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
19+
"github.com/aws/aws-sdk-go-v2/service/kms"
20+
)
21+
22+
/*
23+
This example sets up a DynamoDb Item Encryptor and uses
24+
the EncryptItem and DecryptItem APIs to directly encrypt and
25+
decrypt an existing DynamoDb item.
26+
You should use the DynamoDb Item Encryptor
27+
if you already have a DynamoDb Item to encrypt or decrypt,
28+
and do not need to make a Put or Get call to DynamoDb.
29+
For example, if you are using DynamoDb Streams,
30+
you may already be working with an encrypted item obtained from
31+
DynamoDb, and want to directly decrypt the item.
32+
33+
Running this example requires access to the DDB Table whose name
34+
is provided in CLI arguments.
35+
This table must be configured with the following
36+
primary key configuration:
37+
- Partition key is named "partition_key" with type (S)
38+
- Sort key is named "sort_key" with type (S)
39+
*/
40+
41+
func ItemEncryptDecryptExample(kmsKeyID, ddbTableName string) {
42+
// 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
43+
// For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use.
44+
// We will use the `CreateMrkMultiKeyring` method to create this keyring,
45+
// as it will correctly handle both single region and Multi-Region KMS Keys.
46+
47+
cfg, err := config.LoadDefaultConfig(context.TODO())
48+
utils.HandleError(err)
49+
// Create KMS client
50+
kmsClient := kms.NewFromConfig(cfg)
51+
// Initialize the mpl client
52+
matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{})
53+
utils.HandleError(err)
54+
// Create the Aws Kms Keyring
55+
awsKmsKeyringInput := mpltypes.CreateAwsKmsKeyringInput{
56+
KmsClient: kmsClient,
57+
KmsKeyId: kmsKeyID,
58+
}
59+
keyring, err := matProv.CreateAwsKmsKeyring(context.Background(), awsKmsKeyringInput)
60+
utils.HandleError(err)
61+
62+
// 2. Configure which attributes are encrypted and/or signed when writing new items.
63+
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
64+
// we must explicitly configure how they should be treated during item encryption:
65+
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
66+
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
67+
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
68+
attributeActions := map[string]dbesdkstructuredencryptiontypes.CryptoAction{
69+
"partition_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Partition key must be SIGN_ONLY
70+
"sort_key": dbesdkstructuredencryptiontypes.CryptoActionSignOnly, // Sort key must be SIGN_ONLY
71+
"attribute1": dbesdkstructuredencryptiontypes.CryptoActionEncryptAndSign,
72+
"attribute2": dbesdkstructuredencryptiontypes.CryptoActionSignOnly,
73+
":attribute3": dbesdkstructuredencryptiontypes.CryptoActionDoNothing,
74+
}
75+
76+
// 3. Configure which attributes we expect to be included in the signature
77+
// when reading items. There are two options for configuring this:
78+
//
79+
// - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
80+
// When defining your DynamoDb schema and deciding on attribute names,
81+
// choose a distinguishing prefix (such as ":") for all attributes that
82+
// you do not want to include in the signature.
83+
// This has two main benefits:
84+
// - It is easier to reason about the security and authenticity of data within your item
85+
// when all unauthenticated data is easily distinguishable by their attribute name.
86+
// - If you need to add new unauthenticated attributes in the future,
87+
// you can easily make the corresponding update to your `attributeActionsOnEncrypt`
88+
// and immediately start writing to that new attribute, without
89+
// any other configuration update needed.
90+
// Once you configure this field, it is not safe to update it.
91+
//
92+
// - Configure `allowedUnsignedAttributes`: You may also explicitly list
93+
// a set of attributes that should be considered unauthenticated when encountered
94+
// on read. Be careful if you use this configuration. Do not remove an attribute
95+
// name from this configuration, even if you are no longer writing with that attribute,
96+
// as old items may still include this attribute, and our configuration needs to know
97+
// to continue to exclude this attribute from the signature scope.
98+
// If you add new attribute names to this field, you must first deploy the update to this
99+
// field to all readers in your host fleet before deploying the update to start writing
100+
// with that new attribute.
101+
//
102+
// For this example, we have designed our DynamoDb table such that any attribute name with
103+
// the ":" prefix should be considered unauthenticated.
104+
allowedUnsignedAttributePrefix := ":"
105+
106+
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
107+
partitionKey := "partition_key"
108+
sortKeyName := "sort_key"
109+
algorithmSuiteID := mpltypes.DBEAlgorithmSuiteIdAlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384
110+
itemEncryptorConfig := dbesdkitemencryptortypes.DynamoDbItemEncryptorConfig{
111+
LogicalTableName: ddbTableName,
112+
PartitionKeyName: partitionKey,
113+
SortKeyName: &sortKeyName,
114+
AttributeActionsOnEncrypt: attributeActions,
115+
Keyring: keyring,
116+
AllowedUnsignedAttributePrefix: &allowedUnsignedAttributePrefix,
117+
// Specifying an algorithm suite is not required,
118+
// but is done here to demonstrate how to do so.
119+
// We suggest using the
120+
// `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite,
121+
// which includes AES-GCM with key derivation, signing, and key commitment.
122+
// This is also the default algorithm suite if one is not specified in this config.
123+
// For more information on supported algorithm suites, see:
124+
// https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html
125+
AlgorithmSuiteId: &algorithmSuiteID,
126+
}
127+
128+
// 5. Create the DynamoDb Item Encryptor
129+
itemEncryptorClient, err := itemencryptor.NewClient(itemEncryptorConfig)
130+
utils.HandleError(err)
131+
132+
// 6. Directly encrypt a DynamoDb item using the DynamoDb Item Encryptor
133+
item := map[string]types.AttributeValue{
134+
"partition_key": &types.AttributeValueMemberS{Value: "ItemEncryptDecryptExample"},
135+
"sort_key": &types.AttributeValueMemberS{Value: "0"},
136+
"attribute1": &types.AttributeValueMemberS{Value: "encrypt and sign me!"},
137+
"attribute2": &types.AttributeValueMemberS{Value: "sign me!"},
138+
":attribute3": &types.AttributeValueMemberS{Value: "ignore me!"},
139+
}
140+
encryptItemInput := &dbesdkitemencryptortypes.EncryptItemInput{
141+
PlaintextItem: item,
142+
}
143+
encryptItemOutput, err := itemEncryptorClient.EncryptItem(context.Background(), *encryptItemInput)
144+
utils.HandleError(err)
145+
146+
// Demonstrate that the item has been encrypted
147+
encryptedItem := encryptItemOutput.EncryptedItem
148+
// Check partition_key is still a string and equals "ItemEncryptDecryptExample"
149+
if partitionKeyAttr, ok := encryptedItem["partition_key"].(*types.AttributeValueMemberS); ok {
150+
if partitionKeyAttr.Value != "ItemEncryptDecryptExample" {
151+
panic("Partition key is not 'ItemEncryptDecryptExample'")
152+
}
153+
} else {
154+
panic("Partition key is not a string attribute or doesn't exist")
155+
}
156+
// Check sort_key is a string and equals "0"
157+
if sortKeyAttr, ok := encryptedItem["sort_key"].(*types.AttributeValueMemberS); ok {
158+
if sortKeyAttr.Value != "0" {
159+
panic("Sort key is not '0'")
160+
}
161+
} else {
162+
panic("Sort key is not a string attribute or doesn't exist")
163+
}
164+
// Check attribute1 is binary (encrypted) and not a string anymore
165+
if _, ok := encryptedItem["attribute1"].(*types.AttributeValueMemberB); !ok {
166+
panic("attribute1 is not binary. It might not be encrypted.")
167+
}
168+
169+
// 7. Directly decrypt the encrypted item using the DynamoDb Item Encryptor
170+
decryptItemInput := &dbesdkitemencryptortypes.DecryptItemInput{
171+
EncryptedItem: encryptedItem,
172+
}
173+
decryptedItem, err := itemEncryptorClient.DecryptItem(context.Background(), *decryptItemInput)
174+
utils.HandleError(err)
175+
176+
if !reflect.DeepEqual(item, decryptedItem.PlaintextItem) {
177+
panic("Decrypted item does not match original item")
178+
}
179+
fmt.Println("Item Encryptor example successful")
180+
}

‎Examples/runtimes/go/main.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
14
package main
25

36
import (
7+
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/itemencryptor"
48
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/keyring"
9+
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/misc"
510
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils"
611
)
712

813
func main() {
914
keyring.AwsKmsKeyringExample(utils.KmsKeyID(), utils.DdbTableName())
1015
keyring.RawAesExample(utils.DdbTableName(), utils.KeyNamespace(), utils.KeyName(), utils.GenerateAes256KeyBytes())
16+
itemencryptor.ItemEncryptDecryptExample(utils.KmsKeyID(), utils.DdbTableName())
17+
misc.GetEncryptedDataKeyDescriptionExample(utils.KmsKeyID(), utils.DdbTableName())
18+
misc.MultiPutGetExample(utils.KmsKeyID(), utils.DdbTableName())
19+
misc.CreateBranchKeyIDExample(utils.TestKeystoreName(), utils.TestLogicalKeystoreName(), utils.TestKeystoreKmsKeyId())
1120
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package misc
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
keystore "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographykeystoresmithygenerated"
11+
keystoretypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographykeystoresmithygeneratedtypes"
12+
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils"
13+
"github.com/aws/aws-sdk-go-v2/config"
14+
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
15+
"github.com/aws/aws-sdk-go-v2/service/kms"
16+
)
17+
18+
/*
19+
The Hierarchical Keyring Example and Searchable Encryption Examples
20+
rely on the existence of a DDB-backed key store with pre-existing
21+
branch key material or beacon key material.
22+
23+
See the "Create KeyStore Table Example" for how to first set up
24+
the DDB Table that will back this KeyStore.
25+
26+
This example demonstrates configuring a KeyStore and then
27+
using a helper method to create a branch key and beacon key
28+
that share the same Id, then return that Id.
29+
We will always create a new beacon key alongside a new branch key,
30+
even if you are not using searchable encryption.
31+
32+
This key creation should occur within your control plane.
33+
*/
34+
35+
func CreateBranchKeyIDExample(
36+
keyStoreTableName,
37+
logicalKeyStoreName,
38+
kmsKeyArn string) {
39+
cfg, err := config.LoadDefaultConfig(context.TODO())
40+
utils.HandleError(err)
41+
ddbClient := dynamodb.NewFromConfig(cfg)
42+
kmsClient := kms.NewFromConfig(cfg)
43+
// 1. Configure your KeyStore resource.
44+
// This SHOULD be the same configuration that was used to create the DDB table
45+
// in the "Create KeyStore Table Example".
46+
kmsConfig := keystoretypes.KMSConfigurationMemberkmsKeyArn{
47+
Value: kmsKeyArn,
48+
}
49+
keyStore, err := keystore.NewClient(keystoretypes.KeyStoreConfig{
50+
DdbTableName: keyStoreTableName,
51+
KmsConfiguration: &kmsConfig,
52+
LogicalKeyStoreName: logicalKeyStoreName,
53+
DdbClient: ddbClient,
54+
KmsClient: kmsClient,
55+
})
56+
utils.HandleError(err)
57+
// 2. Create a new branch key and beacon key in our KeyStore.
58+
// Both the branch key and the beacon key will share an Id.
59+
// This creation is eventually consistent.
60+
branchKey, err := keyStore.CreateKey(context.Background(), keystoretypes.CreateKeyInput{})
61+
utils.HandleError(err)
62+
63+
fmt.Println("Branch Key ID " + branchKey.BranchKeyIdentifier + " created in Create Branch Key ID Example.")
64+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package misc
4+
5+
import (
6+
"context"
7+
"fmt"
8+
9+
dbesdkdynamodbencryption "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygenerated"
10+
dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes"
11+
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils"
12+
"github.com/aws/aws-sdk-go-v2/aws"
13+
"github.com/aws/aws-sdk-go-v2/config"
14+
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
15+
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
16+
)
17+
18+
func GetEncryptedDataKeyDescriptionExample(kmsKeyID, ddbTableName string) {
19+
cfg, err := config.LoadDefaultConfig(context.TODO())
20+
utils.HandleError(err)
21+
ddbec, err := dbesdkdynamodbencryption.NewClient(dbesdkdynamodbencryptiontypes.DynamoDbEncryptionConfig{})
22+
utils.HandleError(err)
23+
// 1. Define keys that will be used to retrieve item from the DynamoDB table.
24+
keyToGet := map[string]types.AttributeValue{
25+
"partition_key": &types.AttributeValueMemberS{Value: "BasicPutGetExample"},
26+
"sort_key": &types.AttributeValueMemberN{Value: "0"},
27+
}
28+
29+
// 2. Create a Amazon DynamoDB Client and retrieve item from DynamoDB table
30+
ddb := dynamodb.NewFromConfig(cfg)
31+
32+
// 3. Extract the item from the dynamoDB table and prepare input for the GetEncryptedDataKeyDescription method.
33+
// Here, we are sending dynamodb item but you can also input the header itself by extracting the header from
34+
// "aws_dbe_head" attribute in the dynamoDB item. The part of the code where we send input as the header is commented.
35+
getInput := &dynamodb.GetItemInput{
36+
TableName: aws.String(ddbTableName),
37+
Key: keyToGet,
38+
// In this example we configure a strongly consistent read
39+
// because we perform a read immediately after a write (for demonstrative purposes).
40+
// By default, reads are only eventually consistent.
41+
// Read our docs to determine which read consistency to use for your application:
42+
// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html
43+
ConsistentRead: aws.Bool(true),
44+
}
45+
returnedItem, err := ddb.GetItem(context.TODO(), getInput)
46+
utils.HandleError(err)
47+
inputUnion := dbesdkdynamodbencryptiontypes.GetEncryptedDataKeyDescriptionUnionMemberitem{
48+
Value: returnedItem.Item,
49+
}
50+
51+
// The code below shows how we can send header as the input to the DynamoDB. This code is written to demo the
52+
// alternative approach. So, it is commented.
53+
// headerAttribute := "aws_dbe_head"
54+
// headerBytes, ok := returnedItem.Item[headerAttribute].(*types.AttributeValueMemberB)
55+
// if !ok {
56+
// panic("attribute1 is not binary. It might not be encrypted.")
57+
// }
58+
// inputUnion := dbesdkdynamodbencryptiontypes.GetEncryptedDataKeyDescriptionUnionMemberheader{
59+
// Value: headerBytes.Value,
60+
// }
61+
62+
encryptedDataKeyDescriptionInput := dbesdkdynamodbencryptiontypes.GetEncryptedDataKeyDescriptionInput{
63+
Input: &inputUnion,
64+
}
65+
encryptedDataKeyDescription, err := ddbec.GetEncryptedDataKeyDescription(context.TODO(), encryptedDataKeyDescriptionInput)
66+
utils.HandleError(err)
67+
68+
if encryptedDataKeyDescription.EncryptedDataKeyDescriptionOutput[0].KeyProviderId != "aws-kms" {
69+
panic("Key provider should have been aws-kms")
70+
}
71+
if *encryptedDataKeyDescription.EncryptedDataKeyDescriptionOutput[0].KeyProviderInfo != kmsKeyID {
72+
panic("Key provider info should have been " + kmsKeyID)
73+
}
74+
fmt.Println("Get encrypted data Key description example successful.")
75+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /