|
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