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 c8796d9

Browse files
chore(go): add plain text migration examples (#1966)
1 parent 4017a97 commit c8796d9

File tree

15 files changed

+903
-4
lines changed

15 files changed

+903
-4
lines changed

‎.github/workflows/ci_test_go.yml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,9 @@ jobs:
140140
run: |
141141
make test_go
142142
143-
- name: Test Examples
143+
- name: Run and Test Examples
144144
if: matrix.library == 'DynamoDbEncryption'
145145
working-directory: ./Examples/runtimes/go
146146
run: |
147147
go run main.go
148+
go test ./...
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Plaintext DynamoDB Table to AWS Database Encryption SDK Encrypted Table Migration
2+
3+
This projects demonstrates the steps necessary
4+
to migrate to the AWS Database Encryption SDK for DynamoDb
5+
from a plaintext database.
6+
7+
[Step 0](plaintext/step0.go) demonstrates the starting state for your system.
8+
9+
## Step 1
10+
11+
In Step 1, you update your system to do the following:
12+
13+
- continue to read plaintext items
14+
- continue to write plaintext items
15+
- prepare to read encrypted items
16+
17+
When you deploy changes in Step 1,
18+
you should not expect any behavior change in your system,
19+
and your dataset still consists of plaintext data.
20+
21+
You must ensure that the changes in Step 1 make it to all your readers before you proceed to Step 2.
22+
23+
## Step 2
24+
25+
In Step 2, you update your system to do the following:
26+
27+
- continue to read plaintext items
28+
- start writing encrypted items
29+
- continue to read encrypted items
30+
31+
When you deploy changes in Step 2,
32+
you are introducing encrypted items to your system,
33+
and must make sure that all your readers are updated with the changes from Step 1.
34+
35+
Before you move onto the next step, you will need to encrypt all plaintext items in your dataset.
36+
Once you have completed this step,
37+
while new items are being encrypted using the new format and will be authenticated on read,
38+
your system will still accept reading plaintext, unauthenticated items.
39+
In order to complete migration to a system where you always authenticate your items,
40+
you should prioritize moving on to Step 3.
41+
42+
## Step 3
43+
44+
Once all old items are encrypted,
45+
update your system to do the following:
46+
47+
- continue to write encrypted items
48+
- continue to read encrypted items
49+
- do not accept reading plaintext items
50+
51+
Once you have deployed these changes to your system, you have completed migration.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package awsdbe
2+
3+
import (
4+
"context"
5+
6+
mpl "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated"
7+
mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes"
8+
dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes"
9+
dbesdkstructuredencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/awscryptographydbencryptionsdkstructuredencryptionsmithygeneratedtypes"
10+
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/examples/utils"
11+
)
12+
13+
func configureTable(kmsKeyID, ddbTableName string, plaintextOverride dbesdkdynamodbencryptiontypes.PlaintextOverride) dbesdkdynamodbencryptiontypes.DynamoDbTablesEncryptionConfig {
14+
15+
// Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
16+
// We will use the `CreateMrkMultiKeyring` method to create this keyring,
17+
// as it will correctly handle both single region and Multi-Region KMS Keys.
18+
matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{})
19+
utils.HandleError(err)
20+
21+
keyringInput := mpltypes.CreateAwsKmsMrkMultiKeyringInput{
22+
Generator: &kmsKeyID,
23+
}
24+
kmsKeyring, err := matProv.CreateAwsKmsMrkMultiKeyring(context.Background(), keyringInput)
25+
utils.HandleError(err)
26+
27+
// Configure which attributes are encrypted and/or signed when writing new items.
28+
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
29+
// we must explicitly configure how they should be treated during item encryption:
30+
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
31+
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
32+
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
33+
partitionKeyName := "partition_key"
34+
sortKeyName := "sort_key"
35+
36+
attributeActions := map[string]dbesdkstructuredencryptiontypes.CryptoAction{
37+
partitionKeyName: dbesdkstructuredencryptiontypes.CryptoActionSignOnly,
38+
sortKeyName: dbesdkstructuredencryptiontypes.CryptoActionSignOnly,
39+
"attribute1": dbesdkstructuredencryptiontypes.CryptoActionEncryptAndSign,
40+
"attribute2": dbesdkstructuredencryptiontypes.CryptoActionSignOnly,
41+
"attribute3": dbesdkstructuredencryptiontypes.CryptoActionDoNothing,
42+
}
43+
44+
// Configure which attributes we expect to be excluded in the signature
45+
// when reading items. This value represents all unsigned attributes
46+
// across our entire dataset. If you ever want to add new unsigned attributes
47+
// in the future, you must make an update to this field to all your readers
48+
// before deploying any change to start writing that new data. It is not safe
49+
// to remove attributes from this field.
50+
unsignedAttributes := []string{"attribute3"}
51+
52+
// Create encryption configuration for table.
53+
tableConfig := dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig{
54+
LogicalTableName: ddbTableName,
55+
PartitionKeyName: partitionKeyName,
56+
SortKeyName: &sortKeyName,
57+
AttributeActionsOnEncrypt: attributeActions,
58+
Keyring: kmsKeyring,
59+
AllowedUnsignedAttributes: unsignedAttributes,
60+
PlaintextOverride: &plaintextOverride,
61+
}
62+
63+
tableConfigsMap := make(map[string]dbesdkdynamodbencryptiontypes.DynamoDbTableEncryptionConfig)
64+
tableConfigsMap[ddbTableName] = tableConfig
65+
66+
listOfTableConfigs := dbesdkdynamodbencryptiontypes.DynamoDbTablesEncryptionConfig{
67+
TableEncryptionConfigs: tableConfigsMap,
68+
}
69+
70+
return listOfTableConfigs
71+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package awsdbe
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/aws/aws-sdk-go-v2/aws"
8+
"github.com/aws/aws-sdk-go-v2/config"
9+
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
10+
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
11+
12+
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/dbesdkmiddleware"
13+
plaintexttoawsdbe "github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/examples/migration/PlaintextToAWSDBE"
14+
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/examples/utils"
15+
16+
dbesdkdynamodbencryptiontypes "github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/awscryptographydbencryptionsdkdynamodbsmithygeneratedtypes"
17+
)
18+
19+
/*
20+
Migration Step 1: This is an example demonstrating how to start using the
21+
AWS Database Encryption SDK with a pre-existing table with plaintext items.
22+
In this example, we configure a DynamoDb Encryption Interceptor to do the following:
23+
- Write items only in plaintext
24+
- Read items in plaintext or, if the item is encrypted, decrypt with our encryption configuration
25+
26+
While this step configures your client to be ready to start reading encrypted items,
27+
we do not yet expect to be reading any encrypted items,
28+
as our client still writes plaintext items.
29+
Before you move on to step 2, ensure that these changes have successfully been deployed
30+
to all of your readers.
31+
32+
Running this example requires access to the DDB Table whose name
33+
is provided in the function parameter.
34+
This table must be configured with the following
35+
primary key configuration:
36+
- Partition key is named "partition_key" with type (S)
37+
- Sort key is named "sort_key" with type (S)
38+
*/
39+
func MigrationStep1(kmsKeyID, ddbTableName, partitionKeyValue, sortKeyWriteValue, sortKeyReadValue string) error {
40+
cfg, err := config.LoadDefaultConfig(context.TODO())
41+
utils.HandleError(err)
42+
43+
// 1. Configure your Keyring, attribute actions,
44+
// allowedUnsignedAttributes, and encryption configuration for table.
45+
// This is common across all the steps.
46+
47+
// Note that while we still are not writing encrypted items,
48+
// and our key will not be used to encrypt items in this example,
49+
// our configuration specifies that we may read encrypted items,
50+
// and we should expect to be able to decrypt and process any encrypted items.
51+
// To that end, we must fully define our encryption configuration in
52+
// this step.
53+
54+
// This `PlaintextOverrideForcePlaintextWriteAllowPlaintextRead` means:
55+
// - Write: Items are forced to be written as plaintext.
56+
// Items may not be written as encrypted items.
57+
// - Read: Items are allowed to be read as plaintext.
58+
// Items are allowed to be read as encrypted items.
59+
listOfTableConfigs := configureTable(kmsKeyID, ddbTableName, dbesdkdynamodbencryptiontypes.PlaintextOverrideForcePlaintextWriteAllowPlaintextRead)
60+
61+
// 2. Create DynamoDB client with dbEsdkMiddleware
62+
dbEsdkMiddleware, err := dbesdkmiddleware.NewDBEsdkMiddleware(listOfTableConfigs)
63+
utils.HandleError(err)
64+
65+
ddb := dynamodb.NewFromConfig(cfg, dbEsdkMiddleware.CreateMiddleware())
66+
67+
// 3. Put an item into your table.
68+
// This item will be stored in plaintext.
69+
encryptedAndSignedValue := "this will be encrypted and signed"
70+
signOnlyValue := "this will never be encrypted, but it will be signed"
71+
doNothingValue := "this will never be encrypted nor signed"
72+
item := map[string]types.AttributeValue{
73+
"partition_key": &types.AttributeValueMemberS{Value: partitionKeyValue},
74+
"sort_key": &types.AttributeValueMemberN{Value: sortKeyWriteValue},
75+
"attribute1": &types.AttributeValueMemberS{Value: encryptedAndSignedValue},
76+
"attribute2": &types.AttributeValueMemberS{Value: signOnlyValue},
77+
"attribute3": &types.AttributeValueMemberS{Value: doNothingValue},
78+
}
79+
80+
putInput := dynamodb.PutItemInput{
81+
TableName: &ddbTableName,
82+
Item: item,
83+
}
84+
85+
_, err = ddb.PutItem(context.TODO(), &putInput)
86+
87+
// We return this error because we run test against the error.
88+
// When used in production code, you can decide how you want to handle errors.
89+
if err != nil {
90+
return err
91+
}
92+
93+
// 4. Get an item back from the table using the DynamoDb Client.
94+
// If this is an item written in plaintext (i.e. any item written
95+
// during Step 0 or 1), then the item will still be in plaintext.
96+
// If this is an item that was encrypted client-side (i.e. any item written
97+
// during Step 2 or after), then the item will be decrypted client-side
98+
// and surfaced as a plaintext item.
99+
key := map[string]types.AttributeValue{
100+
"partition_key": &types.AttributeValueMemberS{Value: partitionKeyValue},
101+
"sort_key": &types.AttributeValueMemberN{Value: sortKeyReadValue},
102+
}
103+
104+
getInput := &dynamodb.GetItemInput{
105+
TableName: &ddbTableName,
106+
Key: key,
107+
ConsistentRead: aws.Bool(true),
108+
}
109+
110+
result, err := ddb.GetItem(context.TODO(), getInput)
111+
// We return this error because we run test against the error.
112+
// When used in production code, you can decide how you want to handle errors.
113+
if err != nil {
114+
return err
115+
}
116+
117+
// Verify we got the expected item back
118+
err = plaintexttoawsdbe.VerifyReturnedItem(result, partitionKeyValue, sortKeyReadValue, encryptedAndSignedValue, signOnlyValue, doNothingValue)
119+
if err != nil {
120+
return err
121+
}
122+
fmt.Println("MigrationStep1 completed successfully")
123+
return nil
124+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package awsdbe
2+
3+
import (
4+
"testing"
5+
6+
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/examples/migration/PlaintextToAWSDBE/plaintext"
7+
"github.com/aws/aws-database-encryption-sdk-dynamodb/releases/go/dynamodb-esdk/examples/utils"
8+
"github.com/google/uuid"
9+
)
10+
11+
func TestMigrationStep1(t *testing.T) {
12+
kmsKeyID := utils.KmsKeyID()
13+
tableName := utils.DdbTableName()
14+
partitionKey := uuid.New().String()
15+
sortKeys := []string{"0", "1", "2", "3"}
16+
17+
// Successfully executes Step 1
18+
err := MigrationStep1(kmsKeyID, tableName, partitionKey, sortKeys[1], sortKeys[1])
19+
utils.HandleError(err)
20+
21+
// Given: Step 0 has succeeded
22+
err = plaintext.MigrationStep0(tableName, partitionKey, sortKeys[0], sortKeys[0])
23+
utils.HandleError(err)
24+
25+
// When: Execute Step 1 with sortReadValue=0, Then: Success (i.e. can read plaintext values)
26+
err = MigrationStep1(kmsKeyID, tableName, partitionKey, sortKeys[1], sortKeys[0])
27+
utils.HandleError(err)
28+
29+
// Given: Step 2 has succeeded
30+
err = MigrationStep2(kmsKeyID, tableName, partitionKey, sortKeys[2], sortKeys[2])
31+
utils.HandleError(err)
32+
33+
// When: Execute Step 1 with sortReadValue=2, Then: Success (i.e. can read encrypted values)
34+
err = MigrationStep1(kmsKeyID, tableName, partitionKey, sortKeys[1], sortKeys[2])
35+
utils.HandleError(err)
36+
37+
// Given: Step 3 has succeeded
38+
err = MigrationStep3(kmsKeyID, tableName, partitionKey, sortKeys[3], sortKeys[3])
39+
utils.HandleError(err)
40+
41+
// When: Execute Step 1 with sortReadValue=3, Then: Success (i.e. can read encrypted values)
42+
err = MigrationStep1(kmsKeyID, tableName, partitionKey, sortKeys[1], sortKeys[3])
43+
utils.HandleError(err)
44+
45+
// Cleanup
46+
for _, sortKey := range sortKeys {
47+
utils.DeleteItem(tableName, "partition_key", partitionKey, "sort_key", sortKey)
48+
}
49+
50+
}

0 commit comments

Comments
(0)

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