|
| 1 | +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +use aws_db_esdk::material_providers::client; |
| 5 | +use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig; |
| 6 | +use aws_db_esdk::CryptoAction; |
| 7 | +use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig; |
| 8 | +use aws_db_esdk::types::dynamo_db_tables_encryption_config::DynamoDbTablesEncryptionConfig; |
| 9 | +use aws_db_esdk::dynamodb::types::PlaintextOverride; |
| 10 | +use std::collections::HashMap; |
| 11 | + |
| 12 | +pub 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 | +} |
0 commit comments