Skip to content

Commit 64869a8

Browse files
author
Lucas McDonald
committed
m
1 parent f525e92 commit 64869a8

File tree

8 files changed

+390
-4
lines changed

8 files changed

+390
-4
lines changed

DynamoDbEncryption/runtimes/python/test/unit/internal/test_client_to_resource.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
simple_key_dict,
1515
)
1616
from ...requests import (
17-
basic_execute_statement_request_encrypted_table,
18-
basic_execute_transaction_request_encrypted_table,
1917
basic_batch_execute_statement_request_encrypted_table,
2018
basic_batch_get_item_request_ddb,
2119
basic_batch_get_item_request_dict,
@@ -25,6 +23,8 @@
2523
basic_batch_write_item_put_request_dict,
2624
basic_delete_item_request_ddb,
2725
basic_delete_item_request_dict,
26+
basic_execute_statement_request_encrypted_table,
27+
basic_execute_transaction_request_encrypted_table,
2828
basic_get_item_request_ddb,
2929
basic_get_item_request_dict,
3030
basic_put_item_request_ddb,

DynamoDbEncryption/runtimes/python/test/unit/internal/test_resource_to_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
)
1717
from ...requests import (
1818
basic_batch_execute_statement_request_encrypted_table,
19-
basic_execute_statement_request_encrypted_table,
20-
basic_execute_transaction_request_encrypted_table,
2119
basic_batch_get_item_request_ddb,
2220
basic_batch_get_item_request_dict,
2321
basic_batch_write_item_delete_request_ddb,
@@ -26,6 +24,8 @@
2624
basic_batch_write_item_put_request_dict,
2725
basic_delete_item_request_ddb,
2826
basic_delete_item_request_dict,
27+
basic_execute_statement_request_encrypted_table,
28+
basic_execute_transaction_request_encrypted_table,
2929
basic_get_item_request_ddb,
3030
basic_get_item_request_dict,
3131
basic_put_item_request_ddb,

Examples/runtimes/python/DynamoDBEncryption/src/encrypted_paginator/encrypted_paginator_example.py

Whitespace-only changes.
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Example for using an EncryptedResource to batch read and write items.
5+
6+
Running this example requires access to the DDB Table whose name
7+
is provided in the function arguments.
8+
This table must be configured with the following
9+
primary key configuration:
10+
- Partition key is named "partition_key" with type (S)
11+
- Sort key is named "sort_key" with type (N)
12+
"""
13+
14+
import boto3
15+
from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders
16+
from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig
17+
from aws_cryptographic_material_providers.mpl.models import (
18+
CreateAwsKmsMrkMultiKeyringInput,
19+
DBEAlgorithmSuiteId,
20+
)
21+
from aws_cryptographic_material_providers.mpl.references import IKeyring
22+
from aws_dbesdk_dynamodb.encrypted.resource import EncryptedResource
23+
from aws_dbesdk_dynamodb.structures.dynamodb import (
24+
DynamoDbTableEncryptionConfig,
25+
DynamoDbTablesEncryptionConfig,
26+
)
27+
from aws_dbesdk_dynamodb.structures.structured_encryption import (
28+
CryptoAction,
29+
)
30+
31+
def encrypted_resource_batch_read_write_example(
32+
kms_key_id: str,
33+
dynamodb_table_name: str,
34+
):
35+
"""Use an EncryptedResource to batch read and write items."""
36+
# 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
37+
# For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use.
38+
# We will use the `CreateMrkMultiKeyring` method to create this keyring,
39+
# as it will correctly handle both single region and Multi-Region KMS Keys.
40+
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(config=MaterialProvidersConfig())
41+
kms_mrk_multi_keyring_input: CreateAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput(
42+
generator=kms_key_id,
43+
)
44+
kms_mrk_multi_keyring: IKeyring = mat_prov.create_aws_kms_mrk_multi_keyring(input=kms_mrk_multi_keyring_input)
45+
46+
# 2. Configure which attributes are encrypted and/or signed when writing new items.
47+
# For each attribute that may exist on the items we plan to write to our DynamoDbTable,
48+
# we must explicitly configure how they should be treated during item encryption:
49+
# - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
50+
# - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
51+
# - DO_NOTHING: The attribute is not encrypted and not included in the signature
52+
attribute_actions_on_encrypt = {
53+
"partition_key": CryptoAction.SIGN_ONLY,
54+
"sort_key": CryptoAction.SIGN_ONLY,
55+
"attribute1": CryptoAction.ENCRYPT_AND_SIGN,
56+
"attribute2": CryptoAction.SIGN_ONLY,
57+
":attribute3": CryptoAction.DO_NOTHING,
58+
}
59+
60+
# 3. Configure which attributes we expect to be included in the signature
61+
# when reading items. There are two options for configuring this:
62+
#
63+
# - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
64+
# When defining your DynamoDb schema and deciding on attribute names,
65+
# choose a distinguishing prefix (such as ":") for all attributes that
66+
# you do not want to include in the signature.
67+
# This has two main benefits:
68+
# - It is easier to reason about the security and authenticity of data within your item
69+
# when all unauthenticated data is easily distinguishable by their attribute name.
70+
# - If you need to add new unauthenticated attributes in the future,
71+
# you can easily make the corresponding update to your `attributeActionsOnEncrypt`
72+
# and immediately start writing to that new attribute, without
73+
# any other configuration update needed.
74+
# Once you configure this field, it is not safe to update it.
75+
#
76+
# - Configure `allowedUnsignedAttributes`: You may also explicitly list
77+
# a set of attributes that should be considered unauthenticated when encountered
78+
# on read. Be careful if you use this configuration. Do not remove an attribute
79+
# name from this configuration, even if you are no longer writing with that attribute,
80+
# as old items may still include this attribute, and our configuration needs to know
81+
# to continue to exclude this attribute from the signature scope.
82+
# If you add new attribute names to this field, you must first deploy the update to this
83+
# field to all readers in your host fleet before deploying the update to start writing
84+
# with that new attribute.
85+
#
86+
# For this example, we have designed our DynamoDb table such that any attribute name with
87+
# the ":" prefix should be considered unauthenticated.
88+
unsignAttrPrefix: str = ":"
89+
90+
# 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
91+
table_configs = {}
92+
table_config = DynamoDbTableEncryptionConfig(
93+
logical_table_name=dynamodb_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_mrk_multi_keyring,
98+
allowed_unsigned_attribute_prefix=unsignAttrPrefix,
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=DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384,
108+
)
109+
table_configs[dynamodb_table_name] = table_config
110+
tables_config = DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs)
111+
112+
# 5. Create the EncryptedResource
113+
encrypted_resource = EncryptedResource(
114+
resource=boto3.resource("dynamodb"),
115+
encryption_config=tables_config,
116+
)
117+
118+
# 6. Write a batch of items to the table.
119+
# Before the items get sent to DynamoDb, they will be encrypted
120+
# client-side, according to our configuration.
121+
items = [
122+
{
123+
"partition_key": "PythonEncryptedResourceBatchReadWriteExample1",
124+
"sort_key": 0,
125+
"attribute1": "encrypt and sign me!",
126+
"attribute2": "sign me!",
127+
":attribute3": "ignore me!",
128+
},
129+
{
130+
"partition_key": "PythonEncryptedResourceBatchReadWriteExample2",
131+
"sort_key": 0,
132+
"attribute1": "encrypt and sign me!",
133+
"attribute2": "sign me!",
134+
":attribute3": "ignore me!",
135+
},
136+
]
137+
138+
batch_write_items_put_request = {
139+
"RequestItems": {
140+
dynamodb_table_name: [
141+
{"PutRequest": {"Item": item}} for item in items
142+
],
143+
},
144+
}
145+
146+
batch_write_items_put_response = encrypted_resource.batch_write_item(**batch_write_items_put_request)
147+
148+
# Demonstrate that BatchWriteItem succeeded
149+
assert batch_write_items_put_response["ResponseMetadata"]["HTTPStatusCode"] == 200
150+
151+
# 7. Read the items back from the table.
152+
# After the items are retrieved from DynamoDb, but before the EncryptedResource
153+
# returns them to the caller, they will be decrypted client-side according to our configuration.
154+
batch_get_items_request = {
155+
"RequestItems": {
156+
dynamodb_table_name:
157+
{
158+
"Keys": [{"partition_key": item["partition_key"], "sort_key": item["sort_key"]} for item in items],
159+
}
160+
},
161+
}
162+
163+
batch_get_items_response = encrypted_resource.batch_get_item(**batch_get_items_request)
164+
165+
# Demonstrate that BatchGetItem succeeded with the expected result
166+
assert batch_get_items_response["ResponseMetadata"]["HTTPStatusCode"] == 200
167+
for item in batch_get_items_response["Responses"][dynamodb_table_name]:
168+
assert item["attribute1"] == "encrypt and sign me!"
169+
assert item["attribute2"] == "sign me!"
170+
assert item[":attribute3"] == "ignore me!"
171+
172+
# 8. Delete the items from the table.
173+
batch_write_items_delete_request = {
174+
"RequestItems": {
175+
dynamodb_table_name: [
176+
{"DeleteRequest": {"Key": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}}} for item in items
177+
],
178+
},
179+
}
180+
181+
batch_write_items_delete_response = encrypted_resource.batch_write_item(**batch_write_items_delete_request)
182+
183+
# Demonstrate that BatchWriteItem succeeded
184+
assert batch_write_items_delete_response["ResponseMetadata"]["HTTPStatusCode"] == 200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""Example for using the EncryptedTablesCollectionManager provided by EncryptedResource
4+
5+
Running this example requires access to the DDB Tables whose names
6+
are provided in the function arguments.
7+
These tables must be configured with the following primary key configuration:
8+
- Partition key is named "partition_key" with type (S)
9+
- Sort key is named "sort_key" with type (N)
10+
"""
11+
12+
import boto3
13+
from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders
14+
from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig
15+
from aws_cryptographic_material_providers.mpl.models import (
16+
CreateAwsKmsMrkMultiKeyringInput,
17+
DBEAlgorithmSuiteId,
18+
)
19+
from aws_cryptographic_material_providers.mpl.references import IKeyring
20+
from aws_dbesdk_dynamodb.encrypted.resource import (
21+
EncryptedResource,
22+
EncryptedTablesCollectionManager,
23+
)
24+
from aws_dbesdk_dynamodb.structures.dynamodb import (
25+
DynamoDbTableEncryptionConfig,
26+
DynamoDbTablesEncryptionConfig,
27+
)
28+
from aws_dbesdk_dynamodb.structures.structured_encryption import (
29+
CryptoAction,
30+
)
31+
32+
def encrypted_tables_collection_manager_example(
33+
kms_key_id: str,
34+
dynamodb_table_names: list[str],
35+
):
36+
"""Use an EncryptedTablesCollectionManager to write and read to multiple tables."""
37+
# 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
38+
# For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use.
39+
# We will use the `CreateMrkMultiKeyring` method to create this keyring,
40+
# as it will correctly handle both single region and Multi-Region KMS Keys.
41+
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(config=MaterialProvidersConfig())
42+
kms_mrk_multi_keyring_input: CreateAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput(
43+
generator=kms_key_id,
44+
)
45+
kms_mrk_multi_keyring: IKeyring = mat_prov.create_aws_kms_mrk_multi_keyring(input=kms_mrk_multi_keyring_input)
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+
attribute_actions_on_encrypt = {
54+
"partition_key": CryptoAction.SIGN_ONLY,
55+
"sort_key": CryptoAction.SIGN_ONLY,
56+
"attribute1": CryptoAction.ENCRYPT_AND_SIGN,
57+
"attribute2": CryptoAction.SIGN_ONLY,
58+
":attribute3": CryptoAction.DO_NOTHING,
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+
unsignAttrPrefix: str = ":"
90+
91+
# 4. Create the DynamoDb Encryption configuration for the tables we will be writing to.
92+
# For each table, we create a DynamoDbTableEncryptionConfig and add it to a dictionary.
93+
# This dictionary is then added to a DynamoDbTablesEncryptionConfig, which is used to create the EncryptedResource.
94+
table_configs = {}
95+
for dynamodb_table_name in dynamodb_table_names:
96+
table_config = DynamoDbTableEncryptionConfig(
97+
logical_table_name=dynamodb_table_name,
98+
partition_key_name="partition_key",
99+
sort_key_name="sort_key",
100+
attribute_actions_on_encrypt=attribute_actions_on_encrypt,
101+
keyring=kms_mrk_multi_keyring,
102+
allowed_unsigned_attribute_prefix=unsignAttrPrefix,
103+
# Specifying an algorithm suite is not required,
104+
# but is done here to demonstrate how to do so.
105+
# We suggest using the
106+
# `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite,
107+
# which includes AES-GCM with key derivation, signing, and key commitment.
108+
# This is also the default algorithm suite if one is not specified in this config.
109+
# For more information on supported algorithm suites, see:
110+
# https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html
111+
algorithm_suite_id=DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384,
112+
)
113+
table_configs[dynamodb_table_name] = table_config
114+
tables_config = DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs)
115+
116+
# 5. Create the EncryptedResource
117+
encrypted_resource = EncryptedResource(
118+
resource=boto3.resource("dynamodb"),
119+
encryption_config=tables_config,
120+
)
121+
122+
# 6. Retrieve the EncryptedTablesCollectionManager from the EncryptedResource
123+
encrypted_tables_collection_manager = encrypted_resource.tables
124+
125+
# 7. Use the EncryptedTablesCollectionManager to get EncryptedTables to write to.
126+
# **IMPORTANT**: This will return all tables in the collection, not just the ones you want to write to.
127+
# This will include all tables that are associated with the current account and endpoint.
128+
# You should consider filtering the tables you write to based on the table name.
129+
encrypted_tables = encrypted_tables_collection_manager.all()
130+
131+
# 8. Write a batch of items to the table.
132+
# Before the items get sent to DynamoDb, they will be encrypted
133+
# client-side, according to our configuration.
134+
items = []
135+
for encrypted_table in encrypted_tables:
136+
# Here, you should consider filtering the tables you write.
137+
# If you do not, you will write to all tables in the collection.
138+
# This may include tables with incompatible schemas, or tables that you do not have permission to write to.
139+
if encrypted_table.table_name in dynamodb_table_names:
140+
encrypted_table.put_item(Item={
141+
"partition_key": "PythonEncryptedTablesCollectionManagerExample",
142+
"sort_key": 0,
143+
"attribute1": "encrypt and sign me!",
144+
"attribute2": "sign me!",
145+
":attribute3": "ignore me!",
146+
})
147+
148+
# 9. Read the items back from the table.
149+
# After the items are retrieved from DynamoDb, but before the EncryptedResource
150+
# returns them to the caller, they will be decrypted client-side according to our configuration.
151+
items = []
152+
for encrypted_table in encrypted_tables:
153+
# Here, you should consider filtering the tables you read from.
154+
# If you do not, you will read from all tables in the collection.
155+
# This may include tables with incompatible schemas, or tables that you do not have permission to read from.
156+
if encrypted_table.table_name in dynamodb_table_names:
157+
get_item_response = encrypted_table.get_item(Key={
158+
"partition_key": "PythonEncryptedTablesCollectionManagerExample",
159+
"sort_key": 0,
160+
})
161+
162+
item = get_item_response["Item"]
163+
items.append(item)
164+
165+
# 10. Assert the items are as expected.
166+
for item in items:
167+
assert item["attribute1"] == "encrypt and sign me!"
168+
assert item["attribute2"] == "sign me!"
169+
assert item[":attribute3"] == "ignore me!"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""Stub to allow relative imports of examples from tests."""

0 commit comments

Comments
 (0)