|
| 1 | +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +use aws_sdk_dynamodb::types::AttributeValue; |
| 5 | +use std::collections::HashMap; |
| 6 | +use aws_db_esdk::intercept::DbEsdkInterceptor; |
| 7 | +use aws_db_esdk::PlaintextOverride; |
| 8 | +use crate::migration::plaintext_to_awsdbe::migration_utils::{ |
| 9 | + verify_returned_item, ENCRYPTED_AND_SIGNED_VALUE, SIGN_ONLY_VALUE, DO_NOTHING_VALUE, |
| 10 | +}; |
| 11 | +use crate::migration::plaintext_to_awsdbe::awsdbe::common::create_table_configs; |
| 12 | + |
| 13 | +/* |
| 14 | +Migration Step 2: This is the second step in the migration process from |
| 15 | +plaintext to encrypted DynamoDB using the AWS Database Encryption SDK. |
| 16 | +
|
| 17 | +In this example, we configure a DynamoDB Encryption client to do the following: |
| 18 | +1. Write items with encryption (no longer writing plaintext) |
| 19 | +2. Read both plaintext items and encrypted items |
| 20 | +
|
| 21 | +Once you deploy this change to your system, you will have a dataset |
| 22 | +containing both encrypted and plaintext items. |
| 23 | +Because the changes in Step 1 have been deployed to all readers, |
| 24 | +we can be sure that our entire system is ready to read this new data. |
| 25 | +
|
| 26 | +Before you move onto the next step, you will need to encrypt all plaintext items in your dataset. |
| 27 | +How you will want to do this depends on your system. |
| 28 | +
|
| 29 | +Running this example requires access to the DDB Table whose name |
| 30 | +is provided in the function parameter. |
| 31 | +This table must be configured with the following |
| 32 | +primary key configuration: |
| 33 | + - Partition key is named "partition_key" with type (S) |
| 34 | + - Sort key is named "sort_key" with type (N) |
| 35 | +*/ |
| 36 | +pub async fn migration_step_2_example( |
| 37 | + kms_key_id: &str, |
| 38 | + ddb_table_name: &str, |
| 39 | + partition_key_value: &str, |
| 40 | + sort_key_write_value: &str, |
| 41 | + sort_key_read_value: &str, |
| 42 | +) -> Result<bool, Box<dyn std::error::Error>> { |
| 43 | + // 1. Create table configurations |
| 44 | + // In this step of migration we will use PlaintextOverride::ForbidPlaintextWriteAllowPlaintextRead |
| 45 | + // which means: |
| 46 | + // - Write: Items are forbidden to be written as plaintext. |
| 47 | + // Items will be written as encrypted items. |
| 48 | + // - Read: Items are allowed to be read as plaintext. |
| 49 | + // Items are allowed to be read as encrypted items. |
| 50 | + let table_configs = create_table_configs( |
| 51 | + kms_key_id, |
| 52 | + ddb_table_name, |
| 53 | + PlaintextOverride::ForbidPlaintextWriteAllowPlaintextRead, |
| 54 | + ) |
| 55 | + .await?; |
| 56 | + |
| 57 | + // 2. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs |
| 58 | + let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await; |
| 59 | + let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config) |
| 60 | + .interceptor(DbEsdkInterceptor::new(table_configs)?) |
| 61 | + .build(); |
| 62 | + let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config); |
| 63 | + |
| 64 | + // 3. Put an item into our table using the above client. |
| 65 | + // This item will be encrypted due to our PlaintextOverride configuration. |
| 66 | + let partition_key_name = "partition_key"; |
| 67 | + let sort_key_name = "sort_key"; |
| 68 | + let encrypted_and_signed_value = ENCRYPTED_AND_SIGNED_VALUE; |
| 69 | + let sign_only_value = SIGN_ONLY_VALUE; |
| 70 | + let do_nothing_value = DO_NOTHING_VALUE; |
| 71 | + let item = HashMap::from([ |
| 72 | + ( |
| 73 | + partition_key_name.to_string(), |
| 74 | + AttributeValue::S(partition_key_value.to_string()), |
| 75 | + ), |
| 76 | + ( |
| 77 | + sort_key_name.to_string(), |
| 78 | + AttributeValue::N(sort_key_write_value.to_string()), |
| 79 | + ), |
| 80 | + ( |
| 81 | + "attribute1".to_string(), |
| 82 | + AttributeValue::S(encrypted_and_signed_value.to_string()), |
| 83 | + ), |
| 84 | + ( |
| 85 | + "attribute2".to_string(), |
| 86 | + AttributeValue::S(sign_only_value.to_string()), |
| 87 | + ), |
| 88 | + ( |
| 89 | + "attribute3".to_string(), |
| 90 | + AttributeValue::S(do_nothing_value.to_string()), |
| 91 | + ), |
| 92 | + ]); |
| 93 | + |
| 94 | + ddb.put_item() |
| 95 | + .table_name(ddb_table_name) |
| 96 | + .set_item(Some(item)) |
| 97 | + .send() |
| 98 | + .await?; |
| 99 | + |
| 100 | + // 4. Get an item back from the table using the same client. |
| 101 | + // If this is an item written in plaintext (i.e. any item written |
| 102 | + // during Step 0 or 1), then the item will still be in plaintext. |
| 103 | + // If this is an item that was encrypted client-side (i.e. any item written |
| 104 | + // during Step 2 or after), then the item will be decrypted client-side |
| 105 | + // and surfaced as a plaintext item. |
| 106 | + let key = HashMap::from([ |
| 107 | + ( |
| 108 | + partition_key_name.to_string(), |
| 109 | + AttributeValue::S(partition_key_value.to_string()), |
| 110 | + ), |
| 111 | + ( |
| 112 | + sort_key_name.to_string(), |
| 113 | + AttributeValue::N(sort_key_read_value.to_string()), |
| 114 | + ), |
| 115 | + ]); |
| 116 | + |
| 117 | + let response = ddb |
| 118 | + .get_item() |
| 119 | + .table_name(ddb_table_name) |
| 120 | + .set_key(Some(key)) |
| 121 | + // In this example we configure a strongly consistent read |
| 122 | + // because we perform a read immediately after a write (for demonstrative purposes). |
| 123 | + // By default, reads are only eventually consistent. |
| 124 | + .consistent_read(true) |
| 125 | + .send() |
| 126 | + .await?; |
| 127 | + |
| 128 | + // 5. Verify we get the expected item back |
| 129 | + if let Some(item) = response.item { |
| 130 | + let success = verify_returned_item(&item, partition_key_value, sort_key_read_value)?; |
| 131 | + if success { |
| 132 | + println!("MigrationStep2 completed successfully"); |
| 133 | + } |
| 134 | + Ok(success) |
| 135 | + } else { |
| 136 | + Err("No item found".into()) |
| 137 | + } |
| 138 | +} |
0 commit comments