11# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
22# SPDX-License-Identifier: Apache-2.0
33"""
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.
2726"""
27+
2828import os
2929
3030import boto3
4343 CryptoAction ,
4444)
4545from cryptography .hazmat .primitives import serialization
46- from cryptography .hazmat .primitives .asymmetric import padding
4746
4847DEFAULT_EXAMPLE_RSA_PUBLIC_KEY_FILENAME = "KmsRsaKeyringExamplePublicKey.pem"
4948
49+
5050def 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
5452):
5553 """
5654 Create a KMS RSA keyring and use it to encrypt/decrypt DynamoDB items.
@@ -65,7 +63,7 @@ def kms_rsa_keyring_example(
6563 # the KMS RSA key, retrieve its public key, and store it
6664 # in a PEM file for example use.
6765 try :
68- with open (rsa_public_key_filename , 'rb' ) as f :
66+ with open (rsa_public_key_filename , "rb" ) as f :
6967 public_key_utf8_encoded = f .read ()
7068 except IOError as e :
7169 raise RuntimeError ("IOError while reading public key from file" ) from e
@@ -77,20 +75,16 @@ def kms_rsa_keyring_example(
7775 # - public_key: A ByteBuffer of a UTF-8 encoded PEM file representing the public
7876 # key for the key passed into kms_key_id
7977 # - 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 ())
8379
8480 keyring_input = CreateAwsKmsRsaKeyringInput (
8581 kms_key_id = rsa_key_arn ,
86- kms_client = boto3 .client (' kms' ),
82+ kms_client = boto3 .client (" kms" ),
8783 public_key = public_key_utf8_encoded ,
88- encryption_algorithm = "RSAES_OAEP_SHA_256"
84+ encryption_algorithm = "RSAES_OAEP_SHA_256" ,
8985 )
9086
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 )
9488
9589 # 3. Configure which attributes are encrypted and/or signed when writing new items.
9690 # 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(
10195 attribute_actions = {
10296 "partition_key" : CryptoAction .SIGN_ONLY , # Our partition attribute must be SIGN_ONLY
10397 "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 ,
10599 }
106100
107101 # 4. Configure which attributes we expect to be included in the signature
@@ -148,58 +142,47 @@ def kms_rsa_keyring_example(
148142 # Specify algorithmSuite without asymmetric signing here
149143 # As of v3.0.0, the only supported algorithmSuite without asymmetric signing is
150144 # 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 ,
152146 )
153147
154148 table_configs = {ddb_table_name : table_config }
155149 tables_config = DynamoDbTablesEncryptionConfig (table_encryption_configs = table_configs )
156150
157151 # 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 )
163154
164155 # 7. Put an item into our table using the above client.
165156 # Before the item gets sent to DynamoDb, it will be encrypted
166157 # client-side using the KMS RSA keyring.
167158 item = {
168159 "partition_key" : {"S" : "awsKmsRsaKeyringItem" },
169160 "sort_key" : {"N" : "0" },
170- "sensitive_data" : {"S" : "encrypt and sign me!" }
161+ "sensitive_data" : {"S" : "encrypt and sign me!" },
171162 }
172163
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 )
177165
178166 # Demonstrate that PutItem succeeded
179- assert put_response [' ResponseMetadata' ][ ' HTTPStatusCode' ] == 200
167+ assert put_response [" ResponseMetadata" ][ " HTTPStatusCode" ] == 200
180168
181169 # 8. Get the item back from our table using the client.
182170 # The client will decrypt the item client-side using the RSA keyring
183171 # 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" }}
188173
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 )
193175
194176 # 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" ]
197179 assert returned_item ["sensitive_data" ]["S" ] == "encrypt and sign me!"
198180
199181
200182def 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+
203186 :param rsa_public_key_filename: Path to the public key PEM file
204187 :return: True if we need to get a new public key, False otherwise
205188 """
@@ -215,11 +198,11 @@ def should_get_new_public_key(rsa_public_key_filename: str = DEFAULT_EXAMPLE_RSA
215198
216199
217200def 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
220202):
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+
223206 :param rsa_key_arn: The ARN of the KMS RSA key
224207 :param rsa_public_key_filename: Path to write the public key PEM file
225208 """
@@ -230,23 +213,19 @@ def write_public_key_pem_for_rsa_key(
230213 # This code will call KMS to get the public key for the KMS RSA key.
231214 # You must have kms:GetPublicKey permissions on the key for this to succeed.
232215 # 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" ]
238219
239220 # Convert the public key to PEM format
240221 public_key = serialization .load_der_public_key (public_key_bytes )
241222 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
244224 )
245225
246226 # Write the PEM file
247227 try :
248- with open (rsa_public_key_filename , 'wb' ) as f :
228+ with open (rsa_public_key_filename , "wb" ) as f :
249229 f .write (pem_data )
250230 except IOError as e :
251231 raise RuntimeError ("IOError while writing public key PEM" ) from e
252-
0 commit comments