|
1 | 1 | # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. |
2 | 2 | # SPDX-License-Identifier: Apache-2.0 |
3 | 3 | """ |
4 | | -Example demonstrating DynamoDb Encryption using a Hierarchical Keyring. |
| 4 | +Configuration module for hierarchical keyring encryption setup. |
5 | 5 |
|
6 | | -This example sets up DynamoDb Encryption for the AWS SDK client |
7 | | -using the Hierarchical Keyring, which establishes a key hierarchy |
8 | | -where "branch" keys are persisted in DynamoDb. |
9 | | -These branch keys are used to protect your data keys, |
10 | | -and these branch keys are themselves protected by a root KMS Key. |
11 | | -
|
12 | | -Establishing a key hierarchy like this has two benefits: |
13 | | -
|
14 | | -First, by caching the branch key material, and only calling back |
15 | | -to KMS to re-establish authentication regularly according to your configured TTL, |
16 | | -you limit how often you need to call back to KMS to protect your data. |
17 | | -This is a performance/security tradeoff, where your authentication, audit, and |
18 | | -logging from KMS is no longer one-to-one with every encrypt or decrypt call. |
19 | | -However, the benefit is that you no longer have to make a |
20 | | -network call to KMS for every encrypt or decrypt. |
21 | | -
|
22 | | -Second, this key hierarchy makes it easy to hold multi-tenant data |
23 | | -that is isolated per branch key in a single DynamoDb table. |
24 | | -You can create a branch key for each tenant in your table, |
25 | | -and encrypt all that tenant's data under that distinct branch key. |
26 | | -On decrypt, you can either statically configure a single branch key |
27 | | -to ensure you are restricting decryption to a single tenant, |
28 | | -or you can implement an interface that lets you map the primary key on your items |
29 | | -to the branch key that should be responsible for decrypting that data. |
30 | | -
|
31 | | -This example then demonstrates configuring a Hierarchical Keyring |
32 | | -with a Branch Key ID Supplier to encrypt and decrypt data for |
33 | | -two separate tenants. |
34 | | -
|
35 | | -Running this example requires access to the DDB Table whose name |
36 | | -is provided in CLI arguments. |
37 | | -This table must be configured with the following |
38 | | -primary key configuration: |
39 | | - - Partition key is named "partition_key" with type (S) |
40 | | - - Sort key is named "sort_key" with type (S) |
41 | | -
|
42 | | -This example also requires using a KMS Key whose ARN |
43 | | -is provided in CLI arguments. You need the following access |
44 | | -on this key: |
45 | | - - GenerateDataKeyWithoutPlaintext |
46 | | - - Decrypt |
| 6 | +This module provides the common encryption configuration used by both |
| 7 | +EncryptedClient and EncryptedTable examples. |
47 | 8 | """ |
48 | 9 |
|
49 | 10 | import boto3 |
|
57 | 18 | CreateAwsKmsHierarchicalKeyringInput, |
58 | 19 | DefaultCache, |
59 | 20 | ) |
60 | | -from aws_dbesdk_dynamodb.encrypted.client import EncryptedClient |
61 | 21 | from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.client import DynamoDbEncryption |
62 | 22 | from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.config import ( |
63 | 23 | DynamoDbEncryptionConfig, |
|
71 | 31 | CryptoAction, |
72 | 32 | ) |
73 | 33 |
|
74 | | -from .example_branch_key_id_supplier import ExampleBranchKeyIdSupplier |
| 34 | +from ..example_branch_key_id_supplier import ExampleBranchKeyIdSupplier |
75 | 35 |
|
76 | 36 |
|
77 | | -def hierarchical_keyring_get_item_put_item( |
| 37 | +def create_encryption_config( |
78 | 38 | ddb_table_name: str, |
79 | 39 | tenant1_branch_key_id: str, |
80 | 40 | tenant2_branch_key_id: str, |
81 | 41 | keystore_table_name: str, |
82 | 42 | logical_keystore_name: str, |
83 | 43 | kms_key_id: str, |
84 | | -): |
| 44 | +) -> DynamoDbTablesEncryptionConfig: |
85 | 45 | """ |
86 | | - Demonstrate using a hierarchical keyring with multiple tenants. |
| 46 | + Create the encryption configuration for DynamoDB encryption. |
87 | 47 |
|
88 | 48 | :param ddb_table_name: The name of the DynamoDB table |
89 | 49 | :param tenant1_branch_key_id: Branch key ID for tenant 1 |
90 | 50 | :param tenant2_branch_key_id: Branch key ID for tenant 2 |
91 | 51 | :param keystore_table_name: The name of the KeyStore DynamoDB table |
92 | 52 | :param logical_keystore_name: The logical name for this keystore |
93 | 53 | :param kms_key_id: The ARN of the KMS key to use |
| 54 | + :return: The DynamoDB tables encryption configuration |
94 | 55 | """ |
95 | 56 | # Initial KeyStore Setup: This example requires that you have already |
96 | 57 | # created your KeyStore, and have populated it with two new branch keys. |
@@ -190,40 +151,4 @@ def hierarchical_keyring_get_item_put_item( |
190 | 151 | ) |
191 | 152 |
|
192 | 153 | table_configs = {ddb_table_name: table_config} |
193 | | - tables_config = DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs) |
194 | | - |
195 | | - # 7. Create the EncryptedClient |
196 | | - ddb_client = boto3.client("dynamodb") |
197 | | - encrypted_ddb_client = EncryptedClient(client=ddb_client, encryption_config=tables_config) |
198 | | - |
199 | | - # 8. Put an item into our table using the above client. |
200 | | - # Before the item gets sent to DynamoDb, it will be encrypted |
201 | | - # client-side, according to our configuration. |
202 | | - # Because the item we are writing uses "tenantId1" as our partition value, |
203 | | - # based on the code we wrote in the ExampleBranchKeySupplier, |
204 | | - # `tenant1_branch_key_id` will be used to encrypt this item. |
205 | | - item = { |
206 | | - "partition_key": {"S": "tenant1Id"}, |
207 | | - "sort_key": {"N": "0"}, |
208 | | - "tenant_sensitive_data": {"S": "encrypt and sign me!"}, |
209 | | - } |
210 | | - |
211 | | - put_response = encrypted_ddb_client.put_item(TableName=ddb_table_name, Item=item) |
212 | | - |
213 | | - # Demonstrate that PutItem succeeded |
214 | | - assert put_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
215 | | - |
216 | | - # 9. Get the item back from our table using the same client. |
217 | | - # The client will decrypt the item client-side, and return |
218 | | - # back the original item. |
219 | | - # Because the returned item's partition value is "tenantId1", |
220 | | - # based on the code we wrote in the ExampleBranchKeySupplier, |
221 | | - # `tenant1_branch_key_id` will be used to decrypt this item. |
222 | | - key_to_get = {"partition_key": {"S": "tenant1Id"}, "sort_key": {"N": "0"}} |
223 | | - |
224 | | - get_response = encrypted_ddb_client.get_item(TableName=ddb_table_name, Key=key_to_get) |
225 | | - |
226 | | - # Demonstrate that GetItem succeeded and returned the decrypted item |
227 | | - assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
228 | | - returned_item = get_response["Item"] |
229 | | - assert returned_item["tenant_sensitive_data"]["S"] == "encrypt and sign me!" |
| 154 | + return DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs) |
0 commit comments