2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
4
use crate :: test_utils;
5
- use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_dynamoDb :: types:: DynamoDbTableEncryptionConfig ;
6
- use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_structuredEncryption :: types:: CryptoAction ;
5
+ use aws_db_esdk:: aws_cryptography_keyStore :: types:: KmsConfiguration ;
6
+ use aws_db_esdk:: aws_cryptography_keyStore :: types:: key_store_config :: KeyStoreConfig ;
7
7
use aws_db_esdk:: aws_cryptography_materialProviders:: client as mpl_client;
8
+ use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_dynamoDb:: client as dbesdk_client;
9
+ use aws_db_esdk:: aws_cryptography_keyStore:: client as keystore_client;
10
+ use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_dynamoDb:: types:: dynamo_db_encryption_config:: DynamoDbEncryptionConfig ;
11
+ use super :: branch_key_id_supplier:: ExampleBranchKeyIdSupplier ;
8
12
use aws_db_esdk:: aws_cryptography_materialProviders:: types:: material_providers_config:: MaterialProvidersConfig ;
9
- use aws_db_esdk:: aws_cryptography_materialProviders:: types:: PaddingScheme ;
10
- use aws_db_esdk:: intercept:: DbEsdkInterceptor ;
13
+ use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_dynamoDb:: types:: dynamo_db_key_branch_key_id_supplier:: DynamoDbKeyBranchKeyIdSupplierRef ;
14
+ use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_structuredEncryption:: types:: CryptoAction ;
15
+ use std:: collections:: HashMap ;
16
+ use aws_db_esdk:: aws_cryptography_dbEncryptionSdk_dynamoDb:: types:: DynamoDbTableEncryptionConfig ;
11
17
use aws_db_esdk:: DynamoDbTablesEncryptionConfig ;
18
+ use aws_db_esdk:: intercept:: DbEsdkInterceptor ;
12
19
use aws_sdk_dynamodb:: types:: AttributeValue ;
13
- use std:: collections:: HashMap ;
14
- use std:: fs:: File ;
15
- use std:: io:: Read ;
16
- use std:: io:: Write ;
17
- use std:: path:: Path ;
18
20
19
21
/*
20
22
This example sets up DynamoDb Encryption for the AWS SDK client
@@ -59,13 +61,13 @@ use std::path::Path;
59
61
- GenerateDataKeyWithoutPlaintext
60
62
- Decrypt
61
63
*/
62
- pub async fn HierarchicalKeyringGetItemPutItem ( String tenant1BranchKeyId , String tenant2BranchKeyId )
64
+ pub async fn put_item_get_item ( tenant1_branch_key_id : & str , tenant2_branch_key_id : & str )
63
65
{
64
- /*
65
- var ddbTableName = TestUtils.TEST_DDB_TABLE_NAME;
66
- var keyStoreTableName = TestUtils. TEST_KEYSTORE_NAME;
67
- var logicalKeyStoreName = TestUtils. TEST_LOGICAL_KEYSTORE_NAME;
68
- var kmsKeyId = TestUtils. TEST_KEYSTORE_KMS_KEY_ID;
66
+ let ddb_table_name = test_utils :: TEST_DDB_TABLE_NAME ;
67
+
68
+ let keystore_table_name = test_utils :: TEST_KEYSTORE_NAME ;
69
+ let logical_keystore_name = test_utils :: TEST_LOGICAL_KEYSTORE_NAME ;
70
+ let kms_key_id = test_utils :: TEST_KEYSTORE_KMS_KEY_ID ;
69
71
70
72
// Initial KeyStore Setup: This example requires that you have already
71
73
// created your KeyStore, and have populated it with two new branch keys.
@@ -75,55 +77,64 @@ use std::path::Path;
75
77
// 1. Configure your KeyStore resource.
76
78
// This SHOULD be the same configuration that you used
77
79
// to initially create and populate your KeyStore.
78
- var keystore = new KeyStore(new KeyStoreConfig
79
- {
80
- DdbClient = new AmazonDynamoDBClient(),
81
- DdbTableName = keyStoreTableName,
82
- LogicalKeyStoreName = logicalKeyStoreName,
83
- KmsClient = new AmazonKeyManagementServiceClient(),
84
- KmsConfiguration = new KMSConfiguration { KmsKeyArn = kmsKeyId }
85
- });
86
-
80
+ let sdk_config = aws_config:: load_defaults ( aws_config:: BehaviorVersion :: latest ( ) ) . await ;
81
+ let key_store_config = KeyStoreConfig :: builder ( )
82
+ . kms_client ( aws_sdk_kms:: Client :: new ( & sdk_config) )
83
+ . ddb_client ( aws_sdk_dynamodb:: Client :: new ( & sdk_config) )
84
+ . ddb_table_name ( keystore_table_name)
85
+ . logical_key_store_name ( logical_keystore_name)
86
+ . kms_configuration ( KmsConfiguration :: KmsKeyArn (
87
+ kms_key_id. to_string ( ) ,
88
+ ) )
89
+ . build ( )
90
+ . unwrap ( ) ;
91
+
92
+ let key_store = keystore_client:: Client :: from_conf ( key_store_config) . unwrap ( ) ;
87
93
88
94
// 2. Create a Branch Key ID Supplier. See ExampleBranchKeyIdSupplier in this directory.
89
- var ddbEnc = new DynamoDbEncryption(new DynamoDbEncryptionConfig());
90
- var branchKeyIdSupplier = ddbEnc.CreateDynamoDbEncryptionBranchKeyIdSupplier(
91
- new CreateDynamoDbEncryptionBranchKeyIdSupplierInput
92
- {
93
- DdbKeyBranchKeyIdSupplier = new ExampleBranchKeyIdSupplier(tenant1BranchKeyId, tenant2BranchKeyId)
94
- }).BranchKeyIdSupplier;
95
+ let dbesdk_config = DynamoDbEncryptionConfig :: builder ( ) . build ( ) . unwrap ( ) ;
96
+ let dbesdk = dbesdk_client:: Client :: from_conf ( dbesdk_config) . unwrap ( ) ;
97
+ let supplier = ExampleBranchKeyIdSupplier :: new ( tenant1_branch_key_id, tenant2_branch_key_id) ;
98
+ let supplier_ref = DynamoDbKeyBranchKeyIdSupplierRef {
99
+ inner : :: std:: rc:: Rc :: new ( std:: cell:: RefCell :: new ( supplier) )
100
+ } ;
101
+ let branch_key_id_supplier = dbesdk. create_dynamo_db_encryption_branch_key_id_supplier ( )
102
+ . ddb_key_branch_key_id_supplier ( supplier_ref)
103
+ . send ( )
104
+ . await
105
+ . unwrap ( )
106
+ . branch_key_id_supplier . unwrap ( ) ;
107
+
95
108
96
109
// 3. Create the Hierarchical Keyring, using the Branch Key ID Supplier above.
97
110
// With this configuration, the AWS SDK Client ultimately configured will be capable
98
111
// of encrypting or decrypting items for either tenant (assuming correct KMS access).
99
112
// If you want to restrict the client to only encrypt or decrypt for a single tenant,
100
113
// configure this Hierarchical Keyring using `.branchKeyId(tenant1BranchKeyId)` instead
101
114
// of `.branchKeyIdSupplier(branchKeyIdSupplier)`.
102
- var matProv = new MaterialProviders(new MaterialProvidersConfig());
103
- var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
104
- {
105
- KeyStore = keystore,
106
- BranchKeyIdSupplier = branchKeyIdSupplier,
107
- TtlSeconds = 600, // This dictates how often we call back to KMS to authorize use of the branch keys
108
- Cache = new CacheType
109
- {
110
- Default = new DefaultCache { EntryCapacity = 100 }
111
- }
112
- };
113
- var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
115
+ let mpl_config = MaterialProvidersConfig :: builder ( ) . build ( ) . unwrap ( ) ;
116
+ let mpl = mpl_client:: Client :: from_conf ( mpl_config) . unwrap ( ) ;
117
+
118
+ let hierarchical_keyring = mpl
119
+ . create_aws_kms_hierarchical_keyring ( )
120
+ . branch_key_id_supplier ( branch_key_id_supplier)
121
+ . key_store ( key_store)
122
+ . ttl_seconds ( 600 )
123
+ . send ( )
124
+ . await
125
+ . unwrap ( ) ;
114
126
115
127
// 4. Configure which attributes are encrypted and/or signed when writing new items.
116
128
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
117
129
// we must explicitly configure how they should be treated during item encryption:
118
130
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
119
131
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
120
132
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
121
- var attributeActionsOnEncrypt = new Dictionary<String, CryptoAction>
122
- {
123
- ["partition_key"] = CryptoAction.SIGN_ONLY, // Our partition attribute must be SIGN_ONLY
124
- ["sort_key"] = CryptoAction.SIGN_ONLY, // Our sort attribute must be SIGN_ONLY
125
- ["tenant_sensitive_data"] = CryptoAction.ENCRYPT_AND_SIGN
126
- };
133
+ let attribute_actions_on_encrypt = HashMap :: from ( [
134
+ ( "partition_key" . to_string ( ) , CryptoAction :: SignOnly ) , // Our partition attribute must be SIGN_ONLY
135
+ ( "sort_key" . to_string ( ) , CryptoAction :: SignOnly ) , // Our sort attribute must be SIGN_ONLY
136
+ ( "tenant_sensitive_data" . to_string ( ) , CryptoAction :: EncryptAndSign ) ,
137
+ ] ) ;
127
138
128
139
// 5. Configure which attributes we expect to be included in the signature
129
140
// when reading items. There are two options for configuring this:
@@ -153,72 +164,82 @@ use std::path::Path;
153
164
//
154
165
// For this example, we currently authenticate all attributes. To make it easier to
155
166
// add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
156
- const String unsignAttrPrefix = ":";
167
+ const UNSIGNED_ATTR_PREFIX : & str = ":" ;
157
168
158
169
// 6. Create the DynamoDb Encryption configuration for the table we will be writing to.
159
- var tableConfigs = new Dictionary<String, DynamoDbTableEncryptionConfig>
160
- {
161
- [ddbTableName] = new DynamoDbTableEncryptionConfig
162
- {
163
- LogicalTableName = ddbTableName,
164
- PartitionKeyName = "partition_key",
165
- SortKeyName = "sort_key",
166
- AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
167
- Keyring = hierarchicalKeyring,
168
- AllowedUnsignedAttributePrefix = unsignAttrPrefix
169
- }
170
- };
170
+ let table_config = DynamoDbTableEncryptionConfig :: builder ( )
171
+ . logical_table_name ( ddb_table_name)
172
+ . partition_key_name ( "partition_key" )
173
+ . sort_key_name ( "sort_key" )
174
+ . attribute_actions_on_encrypt ( attribute_actions_on_encrypt)
175
+ . keyring ( hierarchical_keyring)
176
+ . allowed_unsigned_attribute_prefix ( UNSIGNED_ATTR_PREFIX )
177
+ . build ( )
178
+ . unwrap ( ) ;
179
+
180
+ let table_configs = DynamoDbTablesEncryptionConfig :: builder ( )
181
+ . table_encryption_configs ( HashMap :: from ( [ ( ddb_table_name. to_string ( ) , table_config) ] ) )
182
+ . build ( )
183
+ . unwrap ( ) ;
171
184
172
185
// 7. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above
173
- var ddb = new Client.DynamoDbClient(
174
- new DynamoDbTablesEncryptionConfig { TableEncryptionConfigs = tableConfigs });
186
+ let sdk_config = aws_config:: load_defaults ( aws_config:: BehaviorVersion :: latest ( ) ) . await ;
187
+ let dynamo_config = aws_sdk_dynamodb:: config:: Builder :: from ( & sdk_config)
188
+ . interceptor ( DbEsdkInterceptor :: new ( table_configs) )
189
+ . build ( ) ;
190
+ let ddb = aws_sdk_dynamodb:: Client :: from_conf ( dynamo_config) ;
175
191
176
192
// 8. Put an item into our table using the above client.
177
193
// Before the item gets sent to DynamoDb, it will be encrypted
178
194
// client-side, according to our configuration.
179
195
// Because the item we are writing uses "tenantId1" as our partition value,
180
196
// based on the code we wrote in the ExampleBranchKeySupplier,
181
197
// `tenant1BranchKeyId` will be used to encrypt this item.
182
- var item = new Dictionary<String, AttributeValue>
183
- {
184
- ["partition_key"] = new AttributeValue("tenant1Id"),
185
- ["sort_key"] = new AttributeValue { N = "0" },
186
- ["tenant_sensitive_data"] = new AttributeValue("encrypt and sign me!")
187
- };
188
- var putRequest = new PutItemRequest
189
- {
190
- TableName = ddbTableName,
191
- Item = item
192
- };
193
-
194
- var putResponse = await ddb.PutItemAsync(putRequest);
198
+ let item = HashMap :: from ( [
199
+ (
200
+ "partition_key" . to_string ( ) ,
201
+ AttributeValue :: S ( "tenant1Id" . to_string ( ) ) ,
202
+ ) ,
203
+ ( "sort_key" . to_string ( ) , AttributeValue :: N ( "0" . to_string ( ) ) ) ,
204
+ (
205
+ "tenant_sensitive_data" . to_string ( ) ,
206
+ AttributeValue :: S ( "encrypt and sign me!" . to_string ( ) ) ,
207
+ ) ,
208
+ ] ) ;
209
+
210
+ let _resp = ddb
211
+ . put_item ( )
212
+ . table_name ( ddb_table_name)
213
+ . set_item ( Some ( item. clone ( ) ) )
214
+ . send ( )
215
+ . await
216
+ . unwrap ( ) ;
195
217
196
- // Demonstrate that PutItem succeeded
197
- Debug.Assert(putResponse.HttpStatusCode == HttpStatusCode.OK);
198
218
199
219
// 10. Get the item back from our table using the same client.
200
220
// The client will decrypt the item client-side, and return
201
221
// back the original item.
202
222
// Because the returned item's partition value is "tenantId1",
203
223
// based on the code we wrote in the ExampleBranchKeySupplier,
204
224
// `tenant1BranchKeyId` will be used to decrypt this item.
205
- var keyToGet = new Dictionary<String, AttributeValue>
206
- {
207
- ["partition_key"] = new AttributeValue("tenant1Id"),
208
- ["sort_key"] = new AttributeValue { N = "0" }
209
- };
210
- var getRequest = new GetItemRequest
211
- {
212
- Key = keyToGet,
213
- TableName = ddbTableName
214
- };
215
- var getResponse = await ddb.GetItemAsync(getRequest);
216
-
217
- // Demonstrate that GetItem succeeded and returned the decrypted item
218
- Debug.Assert(getResponse.HttpStatusCode == HttpStatusCode.OK);
219
- var returnedItem = getResponse.Item;
220
- Debug.Assert(returnedItem["tenant_sensitive_data"].S.Equals("encrypt and sign me!"));
221
- */
225
+ let key_to_get = HashMap :: from ( [
226
+ (
227
+ "partition_key" . to_string ( ) ,
228
+ AttributeValue :: S ( "tenant1Id" . to_string ( ) ) ,
229
+ ) ,
230
+ ( "sort_key" . to_string ( ) , AttributeValue :: N ( "0" . to_string ( ) ) ) ,
231
+ ] ) ;
232
+
233
+ let resp = ddb
234
+ . get_item ( )
235
+ . table_name ( ddb_table_name)
236
+ . set_key ( Some ( key_to_get) )
237
+ . consistent_read ( true )
238
+ . send ( )
239
+ . await
240
+ . unwrap ( ) ;
241
+
242
+ assert_eq ! ( resp. item, Some ( item) ) ;
222
243
println ! ( "hierarchical_keyring successful." ) ;
223
244
224
245
}
0 commit comments