1
1
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2
2
# SPDX-License-Identifier: Apache-2.0
3
3
"""
4
- This example sets up DynamoDb Encryption for the AWS SDK client
5
- using the KMS RSA Keyring. This keyring uses a KMS RSA key pair to
6
- encrypt and decrypt records. The client uses the downloaded public key
7
- to encrypt items it adds to the table.
8
- The keyring uses the private key to decrypt existing table items it retrieves,
9
- by calling KMS' decrypt API.
10
-
11
- Running this example requires access to the DDB Table whose name
12
- is provided in CLI arguments.
13
- This table must be configured with the following
14
- primary key configuration:
15
- - Partition key is named "partition_key" with type (S)
16
- - Sort key is named "sort_key" with type (S)
17
- This example also requires access to a KMS RSA key.
18
- Our tests provide a KMS RSA ARN that anyone can use, but you
19
- can also provide your own KMS RSA key.
20
- To use your own KMS RSA key, you must have either:
21
- - Its public key downloaded in a UTF-8 encoded PEM file
22
- - kms:GetPublicKey permissions on that key
23
- If you do not have the public key downloaded, running this example
24
- through its main method will download the public key for you
25
- by calling kms:GetPublicKey.
26
- You must also have kms:Decrypt permissions on the KMS RSA key.
4
+ Example demonstrating DynamoDb Encryption using a KMS RSA Keyring.
5
+
6
+ The KMS RSA Keyring uses a KMS RSA key pair to encrypt and decrypt records. The client
7
+ uses the downloaded public key to encrypt items it adds to the table. The keyring
8
+ uses the private key to decrypt existing table items it retrieves by calling
9
+ KMS' decrypt API.
10
+
11
+ Running this example requires access to the DDB Table whose name is provided
12
+ in CLI arguments. This table must be configured with the following primary key
13
+ configuration:
14
+ - Partition key is named "partition_key" with type (S)
15
+ - Sort key is named "sort_key" with type (S)
16
+
17
+ The example also requires access to a KMS RSA key. Our tests provide a KMS RSA
18
+ ARN that anyone can use, but you can also provide your own KMS RSA key.
19
+ To use your own KMS RSA key, you must have either:
20
+ - Its public key downloaded in a UTF-8 encoded PEM file
21
+ - kms:GetPublicKey permissions on that key
22
+
23
+ If you do not have the public key downloaded, running this example through its
24
+ main method will download the public key for you by calling kms:GetPublicKey.
25
+ You must also have kms:Decrypt permissions on the KMS RSA key.
27
26
"""
27
+
28
28
import os
29
29
30
30
import boto3
43
43
CryptoAction ,
44
44
)
45
45
from cryptography .hazmat .primitives import serialization
46
- from cryptography .hazmat .primitives .asymmetric import padding
47
46
48
47
DEFAULT_EXAMPLE_RSA_PUBLIC_KEY_FILENAME = "KmsRsaKeyringExamplePublicKey.pem"
49
48
49
+
50
50
def kms_rsa_keyring_example (
51
- ddb_table_name : str ,
52
- rsa_key_arn : str ,
53
- rsa_public_key_filename : str = DEFAULT_EXAMPLE_RSA_PUBLIC_KEY_FILENAME
51
+ ddb_table_name : str , rsa_key_arn : str , rsa_public_key_filename : str = DEFAULT_EXAMPLE_RSA_PUBLIC_KEY_FILENAME
54
52
):
55
53
"""
56
54
Create a KMS RSA keyring and use it to encrypt/decrypt DynamoDB items.
@@ -65,7 +63,7 @@ def kms_rsa_keyring_example(
65
63
# the KMS RSA key, retrieve its public key, and store it
66
64
# in a PEM file for example use.
67
65
try :
68
- with open (rsa_public_key_filename , 'rb' ) as f :
66
+ with open (rsa_public_key_filename , "rb" ) as f :
69
67
public_key_utf8_encoded = f .read ()
70
68
except IOError as e :
71
69
raise RuntimeError ("IOError while reading public key from file" ) from e
@@ -77,20 +75,16 @@ def kms_rsa_keyring_example(
77
75
# - public_key: A ByteBuffer of a UTF-8 encoded PEM file representing the public
78
76
# key for the key passed into kms_key_id
79
77
# - encryption_algorithm: Must be either RSAES_OAEP_SHA_256 or RSAES_OAEP_SHA_1
80
- mat_prov = AwsCryptographicMaterialProviders (
81
- config = MaterialProvidersConfig ()
82
- )
78
+ mat_prov = AwsCryptographicMaterialProviders (config = MaterialProvidersConfig ())
83
79
84
80
keyring_input = CreateAwsKmsRsaKeyringInput (
85
81
kms_key_id = rsa_key_arn ,
86
- kms_client = boto3 .client (' kms' ),
82
+ kms_client = boto3 .client (" kms" ),
87
83
public_key = public_key_utf8_encoded ,
88
- encryption_algorithm = "RSAES_OAEP_SHA_256"
84
+ encryption_algorithm = "RSAES_OAEP_SHA_256" ,
89
85
)
90
86
91
- kms_rsa_keyring = mat_prov .create_aws_kms_rsa_keyring (
92
- input = keyring_input
93
- )
87
+ kms_rsa_keyring = mat_prov .create_aws_kms_rsa_keyring (input = keyring_input )
94
88
95
89
# 3. Configure which attributes are encrypted and/or signed when writing new items.
96
90
# For each attribute that may exist on the items we plan to write to our DynamoDbTable,
@@ -101,7 +95,7 @@ def kms_rsa_keyring_example(
101
95
attribute_actions = {
102
96
"partition_key" : CryptoAction .SIGN_ONLY , # Our partition attribute must be SIGN_ONLY
103
97
"sort_key" : CryptoAction .SIGN_ONLY , # Our sort attribute must be SIGN_ONLY
104
- "sensitive_data" : CryptoAction .ENCRYPT_AND_SIGN
98
+ "sensitive_data" : CryptoAction .ENCRYPT_AND_SIGN ,
105
99
}
106
100
107
101
# 4. Configure which attributes we expect to be included in the signature
@@ -148,58 +142,47 @@ def kms_rsa_keyring_example(
148
142
# Specify algorithmSuite without asymmetric signing here
149
143
# As of v3.0.0, the only supported algorithmSuite without asymmetric signing is
150
144
# ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384.
151
- algorithm_suite_id = DBEAlgorithmSuiteId .ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384
145
+ algorithm_suite_id = DBEAlgorithmSuiteId .ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384 ,
152
146
)
153
147
154
148
table_configs = {ddb_table_name : table_config }
155
149
tables_config = DynamoDbTablesEncryptionConfig (table_encryption_configs = table_configs )
156
150
157
151
# 6. Create the EncryptedClient
158
- ddb_client = boto3 .client ('dynamodb' )
159
- encrypted_ddb_client = EncryptedClient (
160
- client = ddb_client ,
161
- encryption_config = tables_config
162
- )
152
+ ddb_client = boto3 .client ("dynamodb" )
153
+ encrypted_ddb_client = EncryptedClient (client = ddb_client , encryption_config = tables_config )
163
154
164
155
# 7. Put an item into our table using the above client.
165
156
# Before the item gets sent to DynamoDb, it will be encrypted
166
157
# client-side using the KMS RSA keyring.
167
158
item = {
168
159
"partition_key" : {"S" : "awsKmsRsaKeyringItem" },
169
160
"sort_key" : {"N" : "0" },
170
- "sensitive_data" : {"S" : "encrypt and sign me!" }
161
+ "sensitive_data" : {"S" : "encrypt and sign me!" },
171
162
}
172
163
173
- put_response = encrypted_ddb_client .put_item (
174
- TableName = ddb_table_name ,
175
- Item = item
176
- )
164
+ put_response = encrypted_ddb_client .put_item (TableName = ddb_table_name , Item = item )
177
165
178
166
# Demonstrate that PutItem succeeded
179
- assert put_response [' ResponseMetadata' ][ ' HTTPStatusCode' ] == 200
167
+ assert put_response [" ResponseMetadata" ][ " HTTPStatusCode" ] == 200
180
168
181
169
# 8. Get the item back from our table using the client.
182
170
# The client will decrypt the item client-side using the RSA keyring
183
171
# and return the original item.
184
- key_to_get = {
185
- "partition_key" : {"S" : "awsKmsRsaKeyringItem" },
186
- "sort_key" : {"N" : "0" }
187
- }
172
+ key_to_get = {"partition_key" : {"S" : "awsKmsRsaKeyringItem" }, "sort_key" : {"N" : "0" }}
188
173
189
- get_response = encrypted_ddb_client .get_item (
190
- TableName = ddb_table_name ,
191
- Key = key_to_get
192
- )
174
+ get_response = encrypted_ddb_client .get_item (TableName = ddb_table_name , Key = key_to_get )
193
175
194
176
# Demonstrate that GetItem succeeded and returned the decrypted item
195
- assert get_response [' ResponseMetadata' ][ ' HTTPStatusCode' ] == 200
196
- returned_item = get_response [' Item' ]
177
+ assert get_response [" ResponseMetadata" ][ " HTTPStatusCode" ] == 200
178
+ returned_item = get_response [" Item" ]
197
179
assert returned_item ["sensitive_data" ]["S" ] == "encrypt and sign me!"
198
180
199
181
200
182
def should_get_new_public_key (rsa_public_key_filename : str = DEFAULT_EXAMPLE_RSA_PUBLIC_KEY_FILENAME ) -> bool :
201
- """Check if we need to get a new public key.
202
-
183
+ """
184
+ Check if we need to get a new public key.
185
+
203
186
:param rsa_public_key_filename: Path to the public key PEM file
204
187
:return: True if we need to get a new public key, False otherwise
205
188
"""
@@ -215,11 +198,11 @@ def should_get_new_public_key(rsa_public_key_filename: str = DEFAULT_EXAMPLE_RSA
215
198
216
199
217
200
def write_public_key_pem_for_rsa_key (
218
- rsa_key_arn : str ,
219
- rsa_public_key_filename : str = DEFAULT_EXAMPLE_RSA_PUBLIC_KEY_FILENAME
201
+ rsa_key_arn : str , rsa_public_key_filename : str = DEFAULT_EXAMPLE_RSA_PUBLIC_KEY_FILENAME
220
202
):
221
- """Get the public key from KMS and write it to a PEM file.
222
-
203
+ """
204
+ Get the public key from KMS and write it to a PEM file.
205
+
223
206
:param rsa_key_arn: The ARN of the KMS RSA key
224
207
:param rsa_public_key_filename: Path to write the public key PEM file
225
208
"""
@@ -230,23 +213,19 @@ def write_public_key_pem_for_rsa_key(
230
213
# This code will call KMS to get the public key for the KMS RSA key.
231
214
# You must have kms:GetPublicKey permissions on the key for this to succeed.
232
215
# The public key will be written to the file EXAMPLE_RSA_PUBLIC_KEY_FILENAME.
233
- kms_client = boto3 .client ('kms' )
234
- response = kms_client .get_public_key (
235
- KeyId = rsa_key_arn
236
- )
237
- public_key_bytes = response ['PublicKey' ]
216
+ kms_client = boto3 .client ("kms" )
217
+ response = kms_client .get_public_key (KeyId = rsa_key_arn )
218
+ public_key_bytes = response ["PublicKey" ]
238
219
239
220
# Convert the public key to PEM format
240
221
public_key = serialization .load_der_public_key (public_key_bytes )
241
222
pem_data = public_key .public_bytes (
242
- encoding = serialization .Encoding .PEM ,
243
- format = serialization .PublicFormat .SubjectPublicKeyInfo
223
+ encoding = serialization .Encoding .PEM , format = serialization .PublicFormat .SubjectPublicKeyInfo
244
224
)
245
225
246
226
# Write the PEM file
247
227
try :
248
- with open (rsa_public_key_filename , 'wb' ) as f :
228
+ with open (rsa_public_key_filename , "wb" ) as f :
249
229
f .write (pem_data )
250
230
except IOError as e :
251
231
raise RuntimeError ("IOError while writing public key PEM" ) from e
252
-
0 commit comments