main/migration/plaintext_to_awsdbe/awsdbe/
common.rs

1// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig;
5use aws_db_esdk::dynamodb::types::PlaintextOverride;
6use aws_db_esdk::material_providers::client;
7use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
8use aws_db_esdk::types::dynamo_db_tables_encryption_config::DynamoDbTablesEncryptionConfig;
9use aws_db_esdk::CryptoAction;
10use std::collections::HashMap;
11
12pub async fn create_table_configs(
13    kms_key_id: &str,
14    ddb_table_name: &str,
15    plaintext_override: PlaintextOverride,
16) -> Result<DynamoDbTablesEncryptionConfig, Box<dyn std::error::Error>> {
17    // Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
18    // For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use.
19    // We will use the `CreateMrkMultiKeyring` method to create this keyring,
20    // as it will correctly handle both single region and Multi-Region KMS Keys.
21    let provider_config = MaterialProvidersConfig::builder().build()?;
22    let mat_prov = client::Client::from_conf(provider_config)?;
23    let kms_keyring = mat_prov
24        .create_aws_kms_mrk_multi_keyring()
25        .generator(kms_key_id)
26        .send()
27        .await?;
28
29    // Configure which attributes are encrypted and/or signed when writing new items.
30    // For each attribute that may exist on the items we plan to write to our DynamoDbTable,
31    // we must explicitly configure how they should be treated during item encryption:
32    //  - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
33    //  - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
34    //  - DO_NOTHING: The attribute is not encrypted and not included in the signature
35    let partition_key_name = "partition_key";
36    let sort_key_name = "sort_key";
37    let attribute_actions_on_encrypt = HashMap::from([
38        (partition_key_name.to_string(), CryptoAction::SignOnly),
39        (sort_key_name.to_string(), CryptoAction::SignOnly),
40        ("attribute1".to_string(), CryptoAction::EncryptAndSign),
41        ("attribute2".to_string(), CryptoAction::SignOnly),
42        ("attribute3".to_string(), CryptoAction::DoNothing),
43    ]);
44
45    // Configure which attributes we expect to be excluded in the signature
46    // when reading items. There are two options for configuring this:
47    //
48    //    - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
49    //      When defining your DynamoDb schema and deciding on attribute names,
50    //      choose a distinguishing prefix (such as ":") for all attributes that
51    //      you do not want to include in the signature.
52    //      This has two main benefits:
53    //      - It is easier to reason about the security and authenticity of data within your item
54    //        when all unauthenticated data is easily distinguishable by their attribute name.
55    //      - If you need to add new unauthenticated attributes in the future,
56    //        you can easily make the corresponding update to your `attributeActionsOnEncrypt`
57    //        and immediately start writing to that new attribute, without
58    //        any other configuration update needed.
59    //      Once you configure this field, it is not safe to update it.
60    //
61    //    - Configure `allowedUnsignedAttributes`: You may also explicitly list
62    //      a set of attributes that should be considered unauthenticated when encountered
63    //      on read. Be careful if you use this configuration. Do not remove an attribute
64    //      name from this configuration, even if you are no longer writing with that attribute,
65    //      as old items may still include this attribute, and our configuration needs to know
66    //      to continue to exclude this attribute from the signature scope.
67    //      If you add new attribute names to this field, you must first deploy the update to this
68    //      field to all readers in your host fleet before deploying the update to start writing
69    //      with that new attribute.
70    //
71    //   For this example, we will explicitly list the attributes that are not signed.
72    let unsigned_attributes = vec!["attribute3".to_string()];
73
74    // Create the DynamoDb Encryption configuration for the table we will be writing to.
75    let table_config = DynamoDbTableEncryptionConfig::builder()
76        .logical_table_name(ddb_table_name)
77        .partition_key_name(partition_key_name)
78        .sort_key_name(sort_key_name)
79        .attribute_actions_on_encrypt(attribute_actions_on_encrypt)
80        .keyring(kms_keyring)
81        .allowed_unsigned_attributes(unsigned_attributes)
82        .plaintext_override(plaintext_override)
83        .build()?;
84
85    let table_configs = DynamoDbTablesEncryptionConfig::builder()
86        .table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
87        .build()?;
88
89    Ok(table_configs)
90}