Skip to content

Commit d3d03b5

Browse files
kms example
1 parent cd75126 commit d3d03b5

File tree

5 files changed

+210
-137
lines changed

5 files changed

+210
-137
lines changed

Examples/runtimes/go/BasicPutGetExample.go

-131
This file was deleted.

Examples/runtimes/go/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module examples
1+
module github.com/aws/aws-database-encryption-sdk-dynamodb/examples
22

33
go 1.23.2
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package keyring
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"reflect"
7+
8+
dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes"
9+
dbesdkstructuredencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/awscryptographydbencryptionsdkstructuredencryptionsmithygeneratedtypes"
10+
"github.com/aws/aws-sdk-go-v2/aws"
11+
"github.com/aws/aws-sdk-go-v2/config"
12+
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
13+
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
14+
"github.com/aws/aws-sdk-go-v2/service/kms"
15+
16+
mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated"
17+
mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes"
18+
"github.com/aws/aws-database-encryption-sdk-dynamodb/dbesdkmiddleware"
19+
)
20+
21+
/*
22+
This example sets up DynamoDb Encryption for the AWS SDK client
23+
and uses the low level PutItem and GetItem DDB APIs to demonstrate
24+
putting a client-side encrypted item into DynamoDb
25+
and then retrieving and decrypting that item from DynamoDb.
26+
27+
Running this example requires access to the DDB Table whose name
28+
is provided in CLI arguments.
29+
This table must be configured with the following
30+
primary key configuration:
31+
- Partition key is named "partition_key" with type (S)
32+
- Sort key is named "sort_key" with type (N)
33+
*/
34+
func AwsKmsKeyringExample(kmsKeyID, ddbTableName string) {
35+
// 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
36+
// For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use.
37+
// We will use the `CreateMrkMultiKeyring` method to create this keyring,
38+
// as it will correctly handle both single region and Multi-Region KMS Keys.
39+
cfg, err := config.LoadDefaultConfig(context.TODO())
40+
if err != nil {
41+
panic(err)
42+
}
43+
// Create KMS client
44+
kmsClient := kms.NewFromConfig(cfg, func(o *kms.Options) {
45+
o.Region = "us-west-2"
46+
})
47+
// Initialize the mpl client
48+
matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{})
49+
if err != nil {
50+
panic(err)
51+
}
52+
// Create the Aws Kms Keyring
53+
awsKmsKeyringInput := mpltypes.CreateAwsKmsKeyringInput{
54+
KmsClient: kmsClient,
55+
KmsKeyId: kmsKeyID,
56+
}
57+
keyring, err := matProv.CreateAwsKmsKeyring(context.Background(), awsKmsKeyringInput)
58+
if err != nil {
59+
panic(err)
60+
}
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+
// - EncryptAndSign: The attribute is encrypted and included in the signature
66+
// - SignOnly: The attribute not encrypted, but is still included in the signature
67+
// - DoNothing: 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+
sortKeyName := "sort_key"
108+
algorithmSuiteId := mpltypes.DBEAlgorithmSuiteIdAlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384
109+
tableConfig := dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig{
110+
LogicalTableName: ddbTableName,
111+
PartitionKeyName: "partition_key",
112+
SortKeyName: &sortKeyName,
113+
AttributeActionsOnEncrypt: attributeActions,
114+
Keyring: keyring,
115+
AllowedUnsignedAttributePrefix: &allowedUnsignedAttributePrefix,
116+
AlgorithmSuiteId: &algorithmSuiteId,
117+
}
118+
tableConfigsMap := make(map[string]dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig)
119+
tableConfigsMap[ddbTableName] = tableConfig
120+
listOfTableConfigs := dbesdkdynamodbencryptiontypes.DynamoDbTablesEncryptionConfig{
121+
TableEncryptionConfigs: tableConfigsMap,
122+
}
123+
// 5. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs
124+
dbEsdkMiddleware, err := dbesdkmiddleware.NewDBEsdkMiddleware(listOfTableConfigs)
125+
if err != nil {
126+
panic(err)
127+
}
128+
ddb := dynamodb.NewFromConfig(cfg, dbEsdkMiddleware.CreateMiddleware())
129+
130+
// 6. Put an item into our table using the above client.
131+
// Before the item gets sent to DynamoDb, it will be encrypted
132+
// client-side, according to our configuration.
133+
item := map[string]types.AttributeValue{
134+
"partition_key": &types.AttributeValueMemberS{Value: "BasicPutGetExample"},
135+
"sort_key": &types.AttributeValueMemberN{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+
putInput := &dynamodb.PutItemInput{
141+
TableName: aws.String(ddbTableName),
142+
Item: item,
143+
}
144+
_, err = ddb.PutItem(context.TODO(), putInput)
145+
if err != nil {
146+
panic(err)
147+
}
148+
149+
// 7. Get the item back from our table using the same client.
150+
// The client will decrypt the item client-side, and return
151+
// back the original item.
152+
key := map[string]types.AttributeValue{
153+
"partition_key": &types.AttributeValueMemberS{Value: "BasicPutGetExample"},
154+
"sort_key": &types.AttributeValueMemberN{Value: "0"},
155+
}
156+
getInput := &dynamodb.GetItemInput{
157+
TableName: aws.String(ddbTableName),
158+
Key: key,
159+
// In this example we configure a strongly consistent read
160+
// because we perform a read immediately after a write (for demonstrative purposes).
161+
// By default, reads are only eventually consistent.
162+
// Read our docs to determine which read consistency to use for your application:
163+
// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html
164+
ConsistentRead: aws.Bool(true),
165+
}
166+
result, err := ddb.GetItem(context.TODO(), getInput)
167+
if err != nil {
168+
panic(err)
169+
}
170+
// Verify the decrypted item
171+
if !reflect.DeepEqual(item, result.Item) {
172+
panic("Decrypted item does not match original item")
173+
}
174+
fmt.Println("Aws Kms Keyring Example successful.")
175+
}

Examples/runtimes/go/main.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package main
22

33
import (
4-
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dbesdk/examples/keyring"
5-
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dbesdk/examples/misc"
6-
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dbesdk/examples/utils"
4+
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/keyring"
5+
"github.com/aws/aws-database-encryption-sdk-dynamodb/examples/utils"
76
)
87

98
func main() {
10-
misc.PutItemGetItem()
11-
keyring.PutItemGetItem(utils.TestKmsRsaKeyID(), utils.RsaPublicKeyFilename())
9+
keyring.AwsKmsKeyringExample(utils.KmsKeyID(), utils.DdbTableName())
1210
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package utils
5+
6+
const (
7+
kmsKeyID = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f"
8+
ddbTableName = "DynamoDbEncryptionInterceptorTestTableCS"
9+
)
10+
11+
func KmsKeyID() string {
12+
return kmsKeyID
13+
}
14+
15+
func DdbTableName() string {
16+
return ddbTableName
17+
}
18+
19+
func AreMapsEqual(map1, map2 map[string]string) bool {
20+
if len(map1) != len(map2) {
21+
return false
22+
}
23+
24+
for key, value1 := range map1 {
25+
value2, exists := map2[key]
26+
if !exists || value1 != value2 {
27+
return false
28+
}
29+
}
30+
return true
31+
}

0 commit comments

Comments
 (0)