Skip to content

Commit 32915be

Browse files
committed
chore(python): examples for keyrings with EncryptedClient
1 parent 33c173f commit 32915be

34 files changed

+3651
-10
lines changed

Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/keyring/SharedCacheAcrossHierarchicalKeyringsExample.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public static void SharedCacheAcrossHierarchicalKeyringsGetItemPutItem(
180180
final IKeyring hierarchicalKeyring1 =
181181
matProv.CreateAwsKmsHierarchicalKeyring(keyringInput1);
182182

183-
// 4. Configure which attributes are encrypted and/or signed when writing new items.
183+
// 5. Configure which attributes are encrypted and/or signed when writing new items.
184184
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
185185
// we must explicitly configure how they should be treated during item encryption:
186186
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
@@ -194,14 +194,14 @@ public static void SharedCacheAcrossHierarchicalKeyringsGetItemPutItem(
194194
CryptoAction.ENCRYPT_AND_SIGN
195195
);
196196

197-
// 5. Get the DDB Client for Hierarchical Keyring 1.
197+
// 6. Get the DDB Client for Hierarchical Keyring 1.
198198
final DynamoDbClient ddbClient1 = GetDdbClient(
199199
ddbTableName,
200200
hierarchicalKeyring1,
201201
attributeActionsOnEncrypt
202202
);
203203

204-
// 6. Encrypt Decrypt roundtrip with ddbClient1
204+
// 7. Encrypt Decrypt roundtrip with ddbClient1
205205
PutGetItems(ddbTableName, ddbClient1);
206206

207207
// Through the above encrypt and decrypt roundtrip, the cache will be populated and
@@ -210,7 +210,7 @@ public static void SharedCacheAcrossHierarchicalKeyringsGetItemPutItem(
210210
// - Same Logical Key Store Name of the Key Store for the Hierarchical Keyring
211211
// - Same Branch Key ID
212212

213-
// 7. Configure your KeyStore resource keystore2.
213+
// 8. Configure your KeyStore resource keystore2.
214214
// This SHOULD be the same configuration that you used
215215
// to initially create and populate your physical KeyStore.
216216
// Note that keyStoreTableName is the physical Key Store,
@@ -243,7 +243,7 @@ public static void SharedCacheAcrossHierarchicalKeyringsGetItemPutItem(
243243
)
244244
.build();
245245

246-
// 8. Create the Hierarchical Keyring HK2 with Key Store instance K2, the shared Cache
246+
// 9. Create the Hierarchical Keyring HK2 with Key Store instance K2, the shared Cache
247247
// and the same partitionId and BranchKeyId used in HK1 because we want to share cache entries
248248
// (and experience cache HITS).
249249

@@ -262,14 +262,14 @@ public static void SharedCacheAcrossHierarchicalKeyringsGetItemPutItem(
262262
final IKeyring hierarchicalKeyring2 =
263263
matProv.CreateAwsKmsHierarchicalKeyring(keyringInput2);
264264

265-
// 9. Get the DDB Client for Hierarchical Keyring 2.
265+
// 10. Get the DDB Client for Hierarchical Keyring 2.
266266
final DynamoDbClient ddbClient2 = GetDdbClient(
267267
ddbTableName,
268268
hierarchicalKeyring2,
269269
attributeActionsOnEncrypt
270270
);
271271

272-
// 10. Encrypt Decrypt roundtrip with ddbClient2
272+
// 11. Encrypt Decrypt roundtrip with ddbClient2
273273
PutGetItems(ddbTableName, ddbClient2);
274274
}
275275

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Example for creating a new key in a KeyStore.
5+
6+
The Hierarchical Keyring Example and Searchable Encryption Examples rely on the
7+
existence of a DDB-backed key store with pre-existing branch key material or
8+
beacon key material.
9+
10+
See the "Create KeyStore Table Example" for how to first set up the DDB Table
11+
that will back this KeyStore.
12+
13+
Demonstrates configuring a KeyStore and using a helper method to create a branch
14+
key and beacon key that share the same Id. A new beacon key is always created
15+
alongside a new branch key, even if searchable encryption is not being used.
16+
17+
Note: This key creation should occur within your control plane.
18+
"""
19+
20+
import boto3
21+
from aws_cryptographic_material_providers.keystore.client import KeyStore
22+
from aws_cryptographic_material_providers.keystore.config import KeyStoreConfig
23+
from aws_cryptographic_material_providers.keystore.models import (
24+
CreateKeyInput,
25+
KMSConfigurationKmsKeyArn,
26+
)
27+
28+
29+
def keystore_create_key(key_store_table_name: str, logical_key_store_name: str, kms_key_arn: str) -> str:
30+
"""Create a new branch key and beacon key in our KeyStore."""
31+
# 1. Configure your KeyStore resource.
32+
# This SHOULD be the same configuration that was used to create the DDB table
33+
# in the "Create KeyStore Table Example".
34+
keystore: KeyStore = KeyStore(
35+
KeyStoreConfig(
36+
ddb_table_name=key_store_table_name,
37+
kms_configuration=KMSConfigurationKmsKeyArn(kms_key_arn),
38+
logical_key_store_name=logical_key_store_name,
39+
kms_client=boto3.client("kms"),
40+
ddb_client=boto3.client("dynamodb"),
41+
)
42+
)
43+
44+
# 2. Create a new branch key and beacon key in our KeyStore.
45+
# Both the branch key and the beacon key will share an Id.
46+
# This creation is eventually consistent.
47+
branch_key_id = keystore.create_key(CreateKeyInput()).branch_key_identifier
48+
49+
return branch_key_id
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Example for creating a DynamoDB table for use as a KeyStore.
5+
6+
The Hierarchical Keyring Example and Searchable Encryption Examples rely on the
7+
existence of a DDB-backed key store with pre-existing branch key material or
8+
beacon key material.
9+
10+
Shows how to configure a KeyStore and use a helper method to create the DDB table
11+
that will be used to persist branch keys and beacons keys for this KeyStore.
12+
13+
This table creation should occur within your control plane and only needs to occur
14+
once. While not demonstrated in this example, you should additionally use the
15+
`VersionKey` API on the KeyStore to periodically rotate your branch key material.
16+
"""
17+
18+
import boto3
19+
from aws_cryptographic_material_providers.keystore.client import KeyStore
20+
from aws_cryptographic_material_providers.keystore.config import KeyStoreConfig
21+
from aws_cryptographic_material_providers.keystore.models import (
22+
CreateKeyStoreInput,
23+
KMSConfigurationKmsKeyArn,
24+
)
25+
26+
27+
def keystore_create_table(keystore_table_name: str, logical_keystore_name: str, kms_key_arn: str):
28+
"""
29+
Create KeyStore Table Example.
30+
31+
:param keystore_table_name: The name of the DynamoDB table to create
32+
:param logical_keystore_name: The logical name for this keystore
33+
:param kms_key_arn: The ARN of the KMS key to use for protecting branch keys
34+
"""
35+
# 1. Configure your KeyStore resource.
36+
# `ddb_table_name` is the name you want for the DDB table that
37+
# will back your keystore.
38+
# `kms_key_arn` is the KMS Key that will protect your branch keys and beacon keys
39+
# when they are stored in your DDB table.
40+
keystore = KeyStore(
41+
config=KeyStoreConfig(
42+
ddb_client=boto3.client("dynamodb"),
43+
ddb_table_name=keystore_table_name,
44+
logical_key_store_name=logical_keystore_name,
45+
kms_client=boto3.client("kms"),
46+
kms_configuration=KMSConfigurationKmsKeyArn(kms_key_arn),
47+
)
48+
)
49+
50+
# 2. Create the DynamoDb table that will store the branch keys and beacon keys.
51+
# This checks if the correct table already exists at `ddb_table_name`
52+
# by using the DescribeTable API. If no table exists,
53+
# it will create one. If a table exists, it will verify
54+
# the table's configuration and will error if the configuration is incorrect.
55+
keystore.create_key_store(input=CreateKeyStoreInput())
56+
# It may take a couple of minutes for the table to become ACTIVE,
57+
# at which point it is ready to store branch and beacon keys.
58+
# See the Create KeyStore Key Example for how to populate
59+
# this table.

Examples/runtimes/python/DynamoDBEncryption/src/item_encryptor/encrypt_decrypt_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
)
4646

4747

48-
def encrypt_decrypt_example(kms_key_id: str, ddb_table_name: str) -> None:
48+
def encrypt_decrypt_example(kms_key_id: str, ddb_table_name: str):
4949
"""Encrypt and decrypt an item with an ItemEncryptor."""
5050
# 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
5151
# For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use.
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."""
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Example implementation of a branch key ID supplier.
5+
6+
Used in the 'HierarchicalKeyringExample'.
7+
In that example, we have a table where we distinguish multiple tenants
8+
by a tenant ID that is stored in our partition attribute.
9+
The expectation is that this does not produce a confused deputy
10+
because the tenants are separated by partition.
11+
In order to create a Hierarchical Keyring that is capable of encrypting or
12+
decrypting data for either tenant, we implement this interface
13+
to map the correct branch key ID to the correct tenant ID.
14+
"""
15+
from typing import Dict
16+
17+
from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references import (
18+
IDynamoDbKeyBranchKeyIdSupplier,
19+
)
20+
from aws_dbesdk_dynamodb.structures.dynamodb import GetBranchKeyIdFromDdbKeyInput, GetBranchKeyIdFromDdbKeyOutput
21+
22+
23+
class ExampleBranchKeyIdSupplier(IDynamoDbKeyBranchKeyIdSupplier):
24+
"""Example implementation of a branch key ID supplier."""
25+
26+
branch_key_id_for_tenant1: str
27+
branch_key_id_for_tenant2: str
28+
29+
def __init__(self, tenant1_id: str, tenant2_id: str):
30+
"""
31+
Initialize a branch key ID supplier.
32+
33+
:param tenant1_id: Branch key ID for tenant 1
34+
:param tenant2_id: Branch key ID for tenant 2
35+
"""
36+
self.branch_key_id_for_tenant1 = tenant1_id
37+
self.branch_key_id_for_tenant2 = tenant2_id
38+
39+
def get_branch_key_id_from_ddb_key(self, param: GetBranchKeyIdFromDdbKeyInput) -> GetBranchKeyIdFromDdbKeyOutput:
40+
"""
41+
Get branch key ID from the tenant ID in input's DDB key.
42+
43+
:param param: Input containing DDB key
44+
:return: Output containing branch key ID
45+
:raises ValueError: If DDB key is invalid or contains invalid tenant ID
46+
"""
47+
key: Dict[str, Dict] = param.ddb_key
48+
49+
if "partition_key" not in key:
50+
raise ValueError("Item invalid, does not contain expected partition key attribute.")
51+
52+
tenant_key_id = key["partition_key"]["S"]
53+
54+
if tenant_key_id == "tenant1Id":
55+
branch_key_id = self.branch_key_id_for_tenant1
56+
elif tenant_key_id == "tenant2Id":
57+
branch_key_id = self.branch_key_id_for_tenant2
58+
else:
59+
raise ValueError("Item does not contain valid tenant ID")
60+
61+
return GetBranchKeyIdFromDdbKeyOutput(branch_key_id=branch_key_id)

0 commit comments

Comments
 (0)