DbEsdkInterceptor

Struct DbEsdkInterceptor 

Source
pub struct DbEsdkInterceptor { /* private fields */ }

Implementations§

Source§

impl DbEsdkInterceptor

Source

pub fn new(config: DynamoDbTablesEncryptionConfig) -> Result<Self, Error>

Examples found in repository?
examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_2.rs (line 60)
36pub 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}
More examples
Hide additional examples
examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_1.rs (line 58)
34pub async fn migration_step_1_example(
35    kms_key_id: &str,
36    ddb_table_name: &str,
37    partition_key_value: &str,
38    sort_key_write_value: &str,
39    sort_key_read_value: &str,
40) -> Result<bool, Box<dyn std::error::Error>> {
41    // 1. Create table configurations
42    // In this step of migration we will use PlaintextOverride::ForcePlaintextWriteAllowPlaintextRead
43    // which means:
44    //     - Write: Items are forced to be written as plaintext.
45    //              Items may not be written as encrypted items.
46    //     - Read: Items are allowed to be read as plaintext.
47    //             Items are allowed to be read as encrypted items.
48    let table_configs = create_table_configs(
49        kms_key_id,
50        ddb_table_name,
51        PlaintextOverride::ForcePlaintextWriteAllowPlaintextRead,
52    )
53    .await?;
54
55    // 2. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs
56    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
57    let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
58        .interceptor(DbEsdkInterceptor::new(table_configs)?)
59        .build();
60    let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
61
62    // 3. Put an item into our table using the above client.
63    //    This item will be stored in plaintext due to our PlaintextOverride configuration.
64    let partition_key_name = "partition_key";
65    let sort_key_name = "sort_key";
66    let encrypted_and_signed_value = ENCRYPTED_AND_SIGNED_VALUE;
67    let sign_only_value = SIGN_ONLY_VALUE;
68    let do_nothing_value = DO_NOTHING_VALUE;
69    let item = HashMap::from([
70        (
71            partition_key_name.to_string(),
72            AttributeValue::S(partition_key_value.to_string()),
73        ),
74        (
75            sort_key_name.to_string(),
76            AttributeValue::N(sort_key_write_value.to_string()),
77        ),
78        (
79            "attribute1".to_string(),
80            AttributeValue::S(encrypted_and_signed_value.to_string()),
81        ),
82        (
83            "attribute2".to_string(),
84            AttributeValue::S(sign_only_value.to_string()),
85        ),
86        (
87            "attribute3".to_string(),
88            AttributeValue::S(do_nothing_value.to_string()),
89        ),
90    ]);
91
92    ddb.put_item()
93        .table_name(ddb_table_name)
94        .set_item(Some(item))
95        .send()
96        .await?;
97
98    // 4. Get an item back from the table using the same client.
99    //    If this is an item written in plaintext (i.e. any item written
100    //    during Step 0 or 1), then the item will still be in plaintext.
101    //    If this is an item that was encrypted client-side (i.e. any item written
102    //    during Step 2 or after), then the item will be decrypted client-side
103    //    and surfaced as a plaintext item.
104    let key = HashMap::from([
105        (
106            partition_key_name.to_string(),
107            AttributeValue::S(partition_key_value.to_string()),
108        ),
109        (
110            sort_key_name.to_string(),
111            AttributeValue::N(sort_key_read_value.to_string()),
112        ),
113    ]);
114
115    let response = ddb
116        .get_item()
117        .table_name(ddb_table_name)
118        .set_key(Some(key))
119        // In this example we configure a strongly consistent read
120        // because we perform a read immediately after a write (for demonstrative purposes).
121        // By default, reads are only eventually consistent.
122        .consistent_read(true)
123        .send()
124        .await?;
125
126    // 5. Verify we get the expected item back
127    if let Some(item) = response.item {
128        let success = verify_returned_item(&item, partition_key_value, sort_key_read_value)?;
129        if success {
130            println!("MigrationStep1 completed successfully");
131        }
132        Ok(success)
133    } else {
134        Err("No item found".into())
135    }
136}
examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_3.rs (line 60)
33pub async fn migration_step_3_example(
34    kms_key_id: &str,
35    ddb_table_name: &str,
36    partition_key_value: &str,
37    sort_key_write_value: &str,
38    sort_key_read_value: &str,
39) -> Result<bool, Box<dyn std::error::Error>> {
40    // 1. Create table configurations
41    // In this step of migration we will use PlaintextOverride::ForbidPlaintextWriteForbidPlaintextRead
42    // which means:
43    //     - Write: Items are forbidden to be written as plaintext.
44    //              Items will be written as encrypted items.
45    //     - Read: Items are forbidden to be read as plaintext.
46    //             Items will be read as encrypted items.
47    // Note: If you do not specify a PlaintextOverride, it defaults to
48    //       ForbidPlaintextWriteForbidPlaintextRead, which is the desired
49    //       behavior for a client interacting with a fully encrypted database.
50    let table_configs = create_table_configs(
51        kms_key_id,
52        ddb_table_name,
53        PlaintextOverride::ForbidPlaintextWriteForbidPlaintextRead,
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 read will fail, as we have
103    //    configured our client to forbid reading plaintext items.
104    //    If this is an item that was encrypted client-side (i.e. any item written
105    //    during Step 2 or after), then the item will be decrypted client-side
106    //    and surfaced as a plaintext item.
107    let key = HashMap::from([
108        (
109            partition_key_name.to_string(),
110            AttributeValue::S(partition_key_value.to_string()),
111        ),
112        (
113            sort_key_name.to_string(),
114            AttributeValue::N(sort_key_read_value.to_string()),
115        ),
116    ]);
117
118    let response = ddb
119        .get_item()
120        .table_name(ddb_table_name)
121        .set_key(Some(key))
122        // In this example we configure a strongly consistent read
123        // because we perform a read immediately after a write (for demonstrative purposes).
124        // By default, reads are only eventually consistent.
125        .consistent_read(true)
126        .send()
127        .await?;
128
129    // Verify we get the expected item back
130    if let Some(item) = response.item {
131        let success = verify_returned_item(&item, partition_key_value, sort_key_read_value)?;
132        if success {
133            println!("MigrationStep3 completed successfully");
134        }
135        Ok(success)
136    } else {
137        Err("No item found".into())
138    }
139}
examples/keyring/raw_aes_keyring.rs (line 116)
40pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
41    let ddb_table_name = test_utils::TEST_DDB_TABLE_NAME;
42    let aes_key_bytes = generate_aes_key_bytes();
43
44    // 1. Create the keyring.
45    //    The DynamoDb encryption client uses this to encrypt and decrypt items.
46    let mpl_config = MaterialProvidersConfig::builder().build()?;
47    let mpl = mpl_client::Client::from_conf(mpl_config)?;
48    let raw_aes_keyring = mpl
49        .create_raw_aes_keyring()
50        .key_name("my-aes-key-name")
51        .key_namespace("my-key-namespace")
52        .wrapping_key(aes_key_bytes)
53        .wrapping_alg(AesWrappingAlg::AlgAes256GcmIv12Tag16)
54        .send()
55        .await?;
56
57    // 2. Configure which attributes are encrypted and/or signed when writing new items.
58    //    For each attribute that may exist on the items we plan to write to our DynamoDbTable,
59    //    we must explicitly configure how they should be treated during item encryption:
60    //      - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
61    //      - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
62    //      - DO_NOTHING: The attribute is not encrypted and not included in the signature
63    let attribute_actions_on_encrypt = HashMap::from([
64        ("partition_key".to_string(), CryptoAction::SignOnly), // Our partition attribute must be SIGN_ONLY
65        ("sort_key".to_string(), CryptoAction::SignOnly), // Our sort attribute must be SIGN_ONLY
66        ("sensitive_data".to_string(), CryptoAction::EncryptAndSign),
67    ]);
68
69    // 3. Configure which attributes we expect to be included in the signature
70    //    when reading items. There are two options for configuring this:
71    //
72    //    - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
73    //      When defining your DynamoDb schema and deciding on attribute names,
74    //      choose a distinguishing prefix (such as ":") for all attributes that
75    //      you do not want to include in the signature.
76    //      This has two main benefits:
77    //      - It is easier to reason about the security and authenticity of data within your item
78    //        when all unauthenticated data is easily distinguishable by their attribute name.
79    //      - If you need to add new unauthenticated attributes in the future,
80    //        you can easily make the corresponding update to your `attributeActionsOnEncrypt`
81    //        and immediately start writing to that new attribute, without
82    //        any other configuration update needed.
83    //      Once you configure this field, it is not safe to update it.
84    //
85    //    - Configure `allowedUnsignedAttributes`: You may also explicitly list
86    //      a set of attributes that should be considered unauthenticated when encountered
87    //      on read. Be careful if you use this configuration. Do not remove an attribute
88    //      name from this configuration, even if you are no longer writing with that attribute,
89    //      as old items may still include this attribute, and our configuration needs to know
90    //      to continue to exclude this attribute from the signature scope.
91    //      If you add new attribute names to this field, you must first deploy the update to this
92    //      field to all readers in your host fleet before deploying the update to start writing
93    //      with that new attribute.
94    //
95    //   For this example, we currently authenticate all attributes. To make it easier to
96    //   add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
97    const UNSIGNED_ATTR_PREFIX: &str = ":";
98
99    // 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
100    let table_config = DynamoDbTableEncryptionConfig::builder()
101        .logical_table_name(ddb_table_name)
102        .partition_key_name("partition_key")
103        .sort_key_name("sort_key")
104        .attribute_actions_on_encrypt(attribute_actions_on_encrypt)
105        .keyring(raw_aes_keyring)
106        .allowed_unsigned_attribute_prefix(UNSIGNED_ATTR_PREFIX)
107        .build()?;
108
109    let table_configs = DynamoDbTablesEncryptionConfig::builder()
110        .table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
111        .build()?;
112
113    // 5. Create a new AWS SDK DynamoDb client using the Config above
114    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
115    let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
116        .interceptor(DbEsdkInterceptor::new(table_configs)?)
117        .build();
118    let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
119
120    // 6. Put an item into our table using the above client.
121    //    Before the item gets sent to DynamoDb, it will be encrypted
122    //    client-side, according to our configuration.
123    let item = HashMap::from([
124        (
125            "partition_key".to_string(),
126            AttributeValue::S("rawAesKeyringItem".to_string()),
127        ),
128        ("sort_key".to_string(), AttributeValue::N("0".to_string())),
129        (
130            "sensitive_data".to_string(),
131            AttributeValue::S("encrypt and sign me!".to_string()),
132        ),
133    ]);
134
135    ddb.put_item()
136        .table_name(ddb_table_name)
137        .set_item(Some(item.clone()))
138        .send()
139        .await?;
140
141    // 7. Get the item back from our table using the same client.
142    //    The client will decrypt the item client-side, and return
143    //    back the original item.
144    let key_to_get = HashMap::from([
145        (
146            "partition_key".to_string(),
147            AttributeValue::S("rawAesKeyringItem".to_string()),
148        ),
149        ("sort_key".to_string(), AttributeValue::N("0".to_string())),
150    ]);
151
152    let resp = ddb
153        .get_item()
154        .table_name(ddb_table_name)
155        .set_key(Some(key_to_get))
156        // In this example we configure a strongly consistent read
157        // because we perform a read immediately after a write (for demonstrative purposes).
158        // By default, reads are only eventually consistent.
159        // Read our docs to determine which read consistency to use for your application:
160        // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html
161        .consistent_read(true)
162        .send()
163        .await?;
164
165    assert_eq!(resp.item, Some(item));
166
167    println!("raw_aes_keyring successful.");
168    Ok(())
169}
examples/keyring/raw_rsa_keyring.rs (line 154)
57pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
58    let ddb_table_name = test_utils::TEST_DDB_TABLE_NAME;
59
60    // You may provide your own RSA key pair in the files located at
61    //  - EXAMPLE_RSA_PRIVATE_KEY_FILENAME
62    //  - EXAMPLE_RSA_PUBLIC_KEY_FILENAME
63    // If these files are not present, this will generate a pair for you
64    if should_generate_new_rsa_key_pair()? {
65        generate_rsa_key_pair()?;
66    }
67
68    // 1. Load key pair from UTF-8 encoded PEM files.
69    //    You may provide your own PEM files to use here.
70    //    If you do not, the main method in this class will generate PEM
71    //    files for example use. Do not use these files for any other purpose.
72
73    let mut file = File::open(Path::new(EXAMPLE_RSA_PUBLIC_KEY_FILENAME))?;
74    let mut public_key_utf8_bytes = Vec::new();
75    file.read_to_end(&mut public_key_utf8_bytes)?;
76
77    let mut file = File::open(Path::new(EXAMPLE_RSA_PRIVATE_KEY_FILENAME))?;
78    let mut private_key_utf8_bytes = Vec::new();
79    file.read_to_end(&mut private_key_utf8_bytes)?;
80
81    // 2. Create the keyring.
82    //    The DynamoDb encryption client uses this to encrypt and decrypt items.
83    let mpl_config = MaterialProvidersConfig::builder().build()?;
84    let mpl = mpl_client::Client::from_conf(mpl_config)?;
85    let raw_rsa_keyring = mpl
86        .create_raw_rsa_keyring()
87        .key_name("my-rsa-key-name")
88        .key_namespace("my-key-namespace")
89        .padding_scheme(PaddingScheme::OaepSha256Mgf1)
90        .public_key(public_key_utf8_bytes)
91        .private_key(private_key_utf8_bytes)
92        .send()
93        .await?;
94
95    // 3. Configure which attributes are encrypted and/or signed when writing new items.
96    //    For each attribute that may exist on the items we plan to write to our DynamoDbTable,
97    //    we must explicitly configure how they should be treated during item encryption:
98    //      - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
99    //      - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
100    //      - DO_NOTHING: The attribute is not encrypted and not included in the signature
101    let attribute_actions_on_encrypt = HashMap::from([
102        ("partition_key".to_string(), CryptoAction::SignOnly), // Our partition attribute must be SIGN_ONLY
103        ("sort_key".to_string(), CryptoAction::SignOnly), // Our sort attribute must be SIGN_ONLY
104        ("sensitive_data".to_string(), CryptoAction::EncryptAndSign),
105    ]);
106
107    // 4. Configure which attributes we expect to be included in the signature
108    //    when reading items. There are two options for configuring this:
109    //
110    //    - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
111    //      When defining your DynamoDb schema and deciding on attribute names,
112    //      choose a distinguishing prefix (such as ":") for all attributes that
113    //      you do not want to include in the signature.
114    //      This has two main benefits:
115    //      - It is easier to reason about the security and authenticity of data within your item
116    //        when all unauthenticated data is easily distinguishable by their attribute name.
117    //      - If you need to add new unauthenticated attributes in the future,
118    //        you can easily make the corresponding update to your `attributeActionsOnEncrypt`
119    //        and immediately start writing to that new attribute, without
120    //        any other configuration update needed.
121    //      Once you configure this field, it is not safe to update it.
122    //
123    //    - Configure `allowedUnsignedAttributes`: You may also explicitly list
124    //      a set of attributes that should be considered unauthenticated when encountered
125    //      on read. Be careful if you use this configuration. Do not remove an attribute
126    //      name from this configuration, even if you are no longer writing with that attribute,
127    //      as old items may still include this attribute, and our configuration needs to know
128    //      to continue to exclude this attribute from the signature scope.
129    //      If you add new attribute names to this field, you must first deploy the update to this
130    //      field to all readers in your host fleet before deploying the update to start writing
131    //      with that new attribute.
132    //
133    //   For this example, we currently authenticate all attributes. To make it easier to
134    //   add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
135    const UNSIGNED_ATTR_PREFIX: &str = ":";
136
137    // 5. Create the DynamoDb Encryption configuration for the table we will be writing to.
138    let table_config = DynamoDbTableEncryptionConfig::builder()
139        .logical_table_name(ddb_table_name)
140        .partition_key_name("partition_key")
141        .sort_key_name("sort_key")
142        .attribute_actions_on_encrypt(attribute_actions_on_encrypt)
143        .keyring(raw_rsa_keyring)
144        .allowed_unsigned_attribute_prefix(UNSIGNED_ATTR_PREFIX)
145        .build()?;
146
147    let table_configs = DynamoDbTablesEncryptionConfig::builder()
148        .table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
149        .build()?;
150
151    // 6. Create a new AWS SDK DynamoDb client using the config above
152    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
153    let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
154        .interceptor(DbEsdkInterceptor::new(table_configs)?)
155        .build();
156    let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
157
158    // 7. Put an item into our table using the above client.
159    //    Before the item gets sent to DynamoDb, it will be encrypted
160    //    client-side, according to our configuration.
161    let item = HashMap::from([
162        (
163            "partition_key".to_string(),
164            AttributeValue::S("rawRsaKeyringItem".to_string()),
165        ),
166        ("sort_key".to_string(), AttributeValue::N("0".to_string())),
167        (
168            "sensitive_data".to_string(),
169            AttributeValue::S("encrypt and sign me!".to_string()),
170        ),
171    ]);
172
173    ddb.put_item()
174        .table_name(ddb_table_name)
175        .set_item(Some(item.clone()))
176        .send()
177        .await?;
178
179    // 8. Get the item back from our table using the same client.
180    //    The client will decrypt the item client-side, and return
181    //    back the original item.
182
183    let key_to_get = HashMap::from([
184        (
185            "partition_key".to_string(),
186            AttributeValue::S("rawRsaKeyringItem".to_string()),
187        ),
188        ("sort_key".to_string(), AttributeValue::N("0".to_string())),
189    ]);
190
191    let resp = ddb
192        .get_item()
193        .table_name(ddb_table_name)
194        .set_key(Some(key_to_get))
195        // In this example we configure a strongly consistent read
196        // because we perform a read immediately after a write (for demonstrative purposes).
197        // By default, reads are only eventually consistent.
198        // Read our docs to determine which read consistency to use for your application:
199        // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html
200        .consistent_read(true)
201        .send()
202        .await?;
203
204    assert_eq!(resp.item, Some(item));
205    println!("raw_rsa_keyring successful.");
206    Ok(())
207}
examples/basic_get_put_example.rs (line 119)
31pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
32    let kms_key_id = test_utils::TEST_KMS_KEY_ID;
33    let ddb_table_name = test_utils::TEST_DDB_TABLE_NAME;
34
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    let provider_config = MaterialProvidersConfig::builder().build()?;
40    let mat_prov = client::Client::from_conf(provider_config)?;
41    let kms_keyring = mat_prov
42        .create_aws_kms_mrk_multi_keyring()
43        .generator(kms_key_id)
44        .send()
45        .await?;
46
47    // 2. Configure which attributes are encrypted and/or signed when writing new items.
48    //    For each attribute that may exist on the items we plan to write to our DynamoDbTable,
49    //    we must explicitly configure how they should be treated during item encryption:
50    //      - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
51    //      - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
52    //      - DO_NOTHING: The attribute is not encrypted and not included in the signature
53    let attribute_actions_on_encrypt = HashMap::from([
54        ("partition_key".to_string(), CryptoAction::SignOnly),
55        ("sort_key".to_string(), CryptoAction::SignOnly),
56        ("attribute1".to_string(), CryptoAction::EncryptAndSign),
57        ("attribute2".to_string(), CryptoAction::SignOnly),
58        (":attribute3".to_string(), CryptoAction::DoNothing),
59    ]);
60
61    // 3. Configure which attributes we expect to be included in the signature
62    //    when reading items. There are two options for configuring this:
63    //
64    //    - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
65    //      When defining your DynamoDb schema and deciding on attribute names,
66    //      choose a distinguishing prefix (such as ":") for all attributes that
67    //      you do not want to include in the signature.
68    //      This has two main benefits:
69    //      - It is easier to reason about the security and authenticity of data within your item
70    //        when all unauthenticated data is easily distinguishable by their attribute name.
71    //      - If you need to add new unauthenticated attributes in the future,
72    //        you can easily make the corresponding update to your `attributeActionsOnEncrypt`
73    //        and immediately start writing to that new attribute, without
74    //        any other configuration update needed.
75    //      Once you configure this field, it is not safe to update it.
76    //
77    //    - Configure `allowedUnsignedAttributes`: You may also explicitly list
78    //      a set of attributes that should be considered unauthenticated when encountered
79    //      on read. Be careful if you use this configuration. Do not remove an attribute
80    //      name from this configuration, even if you are no longer writing with that attribute,
81    //      as old items may still include this attribute, and our configuration needs to know
82    //      to continue to exclude this attribute from the signature scope.
83    //      If you add new attribute names to this field, you must first deploy the update to this
84    //      field to all readers in your host fleet before deploying the update to start writing
85    //      with that new attribute.
86    //
87    //   For this example, we have designed our DynamoDb table such that any attribute name with
88    //   the ":" prefix should be considered unauthenticated.
89    const UNSIGNED_ATTR_PREFIX: &str = ":";
90
91    // 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
92    let table_config = DynamoDbTableEncryptionConfig::builder()
93        .logical_table_name(ddb_table_name)
94        .partition_key_name("partition_key")
95        .sort_key_name("sort_key")
96        .attribute_actions_on_encrypt(attribute_actions_on_encrypt)
97        .keyring(kms_keyring)
98        .allowed_unsigned_attribute_prefix(UNSIGNED_ATTR_PREFIX)
99        // Specifying an algorithm suite is not required,
100        // but is done here to demonstrate how to do so.
101        // We suggest using the
102        // `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite,
103        // which includes AES-GCM with key derivation, signing, and key commitment.
104        // This is also the default algorithm suite if one is not specified in this config.
105        // For more information on supported algorithm suites, see:
106        //   https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html
107        .algorithm_suite_id(
108            DbeAlgorithmSuiteId::AlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384,
109        )
110        .build()?;
111
112    let table_configs = DynamoDbTablesEncryptionConfig::builder()
113        .table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
114        .build()?;
115
116    // 5. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs
117    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
118    let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
119        .interceptor(DbEsdkInterceptor::new(table_configs)?)
120        .build();
121    let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
122
123    // 6. Put an item into our table using the above client.
124    //    Before the item gets sent to DynamoDb, it will be encrypted
125    //    client-side, according to our configuration.
126    let item = HashMap::from([
127        (
128            "partition_key".to_string(),
129            AttributeValue::S("BasicPutGetExample".to_string()),
130        ),
131        ("sort_key".to_string(), AttributeValue::N("0".to_string())),
132        (
133            "attribute1".to_string(),
134            AttributeValue::S("encrypt and sign me!".to_string()),
135        ),
136        (
137            "attribute2".to_string(),
138            AttributeValue::S("sign me!".to_string()),
139        ),
140        (
141            ":attribute3".to_string(),
142            AttributeValue::S("ignore me!".to_string()),
143        ),
144    ]);
145
146    ddb.put_item()
147        .table_name(ddb_table_name)
148        .set_item(Some(item.clone()))
149        .send()
150        .await?;
151
152    // 7. Get the item back from our table using the same client.
153    //    The client will decrypt the item client-side, and return
154    //    back the original item.
155    let key_to_get = HashMap::from([
156        (
157            "partition_key".to_string(),
158            AttributeValue::S("BasicPutGetExample".to_string()),
159        ),
160        ("sort_key".to_string(), AttributeValue::N("0".to_string())),
161    ]);
162
163    let resp = ddb
164        .get_item()
165        .table_name(ddb_table_name)
166        .set_key(Some(key_to_get))
167        // In this example we configure a strongly consistent read
168        // because we perform a read immediately after a write (for demonstrative purposes).
169        // By default, reads are only eventually consistent.
170        // Read our docs to determine which read consistency to use for your application:
171        // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html
172        .consistent_read(true)
173        .send()
174        .await?;
175
176    assert_eq!(resp.item, Some(item));
177    println!("put_item_get_item successful.");
178    Ok(())
179}

Trait Implementations§

Source§

impl Debug for DbEsdkInterceptor

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Intercept for DbEsdkInterceptor

Source§

fn name(&self) -> &'static str

The name of this interceptor, used in error messages for debugging.
Source§

fn modify_before_serialization( &self, context: &mut BeforeSerializationInterceptorContextMut<'_>, _rc: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), BoxError>

A hook called before the input message is marshalled into a transport message. This method has the ability to modify and return a new request message of the same type. Read more
Source§

fn modify_before_attempt_completion( &self, context: &mut FinalizerInterceptorContextMut<'_>, _rc: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), BoxError>

A hook called when an attempt is completed. This method has the ability to modify and return a new output message or error matching the currently-executing operation. Read more
Source§

fn read_before_execution( &self, context: &BeforeSerializationInterceptorContextRef<'_>, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called at the start of an execution, before the SDK does anything else. Read more
Source§

fn read_before_serialization( &self, context: &BeforeSerializationInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the input message is marshalled into a transport message. Read more
Source§

fn read_after_serialization( &self, context: &BeforeTransmitInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called after the input message is marshalled into a transport message. Read more
Source§

fn modify_before_retry_loop( &self, context: &mut BeforeTransmitInterceptorContextMut<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the retry loop is entered. This method has the ability to modify and return a new transport request message of the same type, except when a failure occurs earlier in the request pipeline. Read more
Source§

fn read_before_attempt( &self, context: &BeforeTransmitInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before each attempt at sending the transmission request message to the service. Read more
Source§

fn modify_before_signing( &self, context: &mut BeforeTransmitInterceptorContextMut<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the transport request message is signed. This method has the ability to modify and return a new transport request message of the same type. Read more
Source§

fn read_before_signing( &self, context: &BeforeTransmitInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the transport request message is signed. Read more
Source§

fn read_after_signing( &self, context: &BeforeTransmitInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called after the transport request message is signed. Read more
Source§

fn modify_before_transmit( &self, context: &mut BeforeTransmitInterceptorContextMut<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the transport request message is sent to the service. This method has the ability to modify and return a new transport request message of the same type. Read more
Source§

fn read_before_transmit( &self, context: &BeforeTransmitInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the transport request message is sent to the service. Read more
Source§

fn read_after_transmit( &self, context: &BeforeDeserializationInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called after the transport request message is sent to the service and a transport response message is received. Read more
Source§

fn modify_before_deserialization( &self, context: &mut BeforeDeserializationInterceptorContextMut<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the transport response message is unmarshalled. This method has the ability to modify and return a new transport response message of the same type. Read more
Source§

fn read_before_deserialization( &self, context: &BeforeDeserializationInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called before the transport response message is unmarshalled Read more
Source§

fn read_after_deserialization( &self, context: &AfterDeserializationInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called after the transport response message is unmarshalled. Read more
Source§

fn read_after_attempt( &self, context: &FinalizerInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called when an attempt is completed. Read more
Source§

fn modify_before_completion( &self, context: &mut FinalizerInterceptorContextMut<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called when an execution is completed. This method has the ability to modify and return a new output message or error matching the currently - executing operation. Read more
Source§

fn read_after_execution( &self, context: &FinalizerInterceptorContextRef<'_>, runtime_components: &RuntimeComponents, cfg: &mut ConfigBag, ) -> Result<(), Box<dyn Error + Send + Sync>>

A hook called when an execution is completed. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AnyRef for T
where T: 'static,

Source§

fn as_any_ref(&self) -> &(dyn Any + 'static)

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

Source§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T
where T: ?Sized,

Source§

fn upcast(&self) -> Ptr<T>

Source§

impl<T> UpcastObject<T> for T
where T: ?Sized,

Source§

fn upcast(&self) -> Object<T>

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more