@@ -147,99 +147,80 @@ version of the AWS Encryption SDK, we recommend using the default value.
147
147
148
148
You must then create an instance of either a keyring (with the MPL installed) or a CMM.
149
149
(You may also provide an instance of a legacy master key provider, but this is not recommended.)
150
- The examples in this README use the ``AwsKmsKeyring `` class.
150
+ The examples in this README use the ``AwsKmsMultiKeyring `` class.
151
151
Note: You must also install the `AWS Cryptographic Material Providers Library (MPL) `_ to use this class.
152
152
153
153
154
- AwsKmsKeyring
155
- =============================
156
- An ``AwsKmsKeyring `` is configured with an AWS KMS key ARN whose AWS KMS key
157
- will be used to generate, encrypt, and decrypt data keys.
158
- On encryption, it encrypts the plaintext with the data key.
159
- On decryption, it decrypts an encrypted version of the data key,
160
- then uses the decrypted data key to decrypt the ciphertext.
154
+ AwsKmsMultiKeyring
155
+ ==================
161
156
162
- To create an ``AwsKmsKeyring `` you must provide a AWS KMS key ARN.
157
+ An ``AwsKmsMultiKeyring `` is configured with a generator keyring and a list of
158
+ child keyrings of type ``AwsKmsKeyring ``. The effect is like using several keyrings
159
+ in a series. When you use a multi-keyring to encrypt data, any of the wrapping keys
160
+ in any of its keyrings can decrypt that data.
161
+
162
+ On encryption, the generator keyring generates and encrypts the plaintext data key.
163
+ Then, all of the wrapping keys in all of the child keyrings encrypt the same plaintext data key.
164
+ On decryption, the AWS Encryption SDK uses the keyrings to try to decrypt one of the encrypted data keys.
165
+ The keyrings are called in the order that they are specified in the multi-keyring.
166
+ Processing stops as soon as any key in any keyring can decrypt an encrypted data key.
167
+
168
+ An individual ``AwsKmsKeyring `` in an ``AwsKmsMultiKeyring `` is configured with an
169
+ AWS KMS key ARN.
163
170
For keyrings that will only be used for encryption,
164
171
you can use any valid `KMS key identifier `_.
165
172
For providers that will be used for decryption,
166
173
you must use the key ARN.
167
174
Key ids, alias names, and alias ARNs are not supported for decryption.
168
175
169
- Because the ``AwsKmsKeyring `` uses the `boto3 SDK `_ to interact with `AWS KMS `_,
176
+ Because the ``AwsKmsMultiKeyring `` uses the `boto3 SDK `_ to interact with `AWS KMS `_,
170
177
it requires AWS Credentials.
171
178
To provide these credentials, use the `standard means by which boto3 locates credentials `_ or provide a
172
- pre-existing instance of a ``botocore session `` to the ``AwsKmsKeyring ``.
179
+ pre-existing instance of a ``botocore session `` to the ``AwsKmsMultiKeyring ``.
173
180
This latter option can be useful if you have an alternate way to store your AWS credentials or
174
181
you want to reuse an existing instance of a botocore session in order to decrease startup costs.
175
182
176
183
.. code :: python
177
184
178
- import boto3
179
185
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
180
186
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
181
- from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsKeyringInput
187
+ from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsMultiKeyringInput
182
188
from aws_cryptographic_materialproviders.mpl.references import IKeyring
183
189
184
- import aws_encryption_sdk
185
- from aws_encryption_sdk import CommitmentPolicy
186
-
187
- # Instantiate the encryption SDK client.
188
- client = aws_encryption_sdk.EncryptionSDKClient(
189
- commitment_policy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
190
- )
191
-
192
- # Create a KMS keyring.
190
+ # Create an AwsKmsMultiKeyring that protects your data under two different KMS Keys.
191
+ # Either KMS Key individually is capable of decrypting data encrypted under this Multi Keyring.
193
192
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
194
193
config = MaterialProvidersConfig()
195
194
)
196
195
197
- keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput (
198
- kms_key_id = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
199
- kms_client = boto3.client( ' kms' , region_name = " us-east-1" )
196
+ kms_multi_keyring_input: CreateAwsKmsMultiKeyringInput = CreateAwsKmsMultiKeyringInput (
197
+ generator = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
198
+ kms_key_ids = [ ' arn:aws: kms: us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333 ' ]
200
199
)
201
200
202
- kms_keyring : IKeyring = mat_prov.create_aws_kms_keyring (
203
- input = keyring_input
201
+ kms_multi_keyring : IKeyring = mat_prov.create_aws_kms_multi_keyring (
202
+ input = kms_multi_keyring_input
204
203
)
205
204
206
-
207
- If you want to configure a keyring with multiple AWS KMS keys, see the multi-keyring.
208
-
209
- MultiKeyring
210
- ============
211
-
212
- A ``MultiKeyring `` is configured with an optional generator keyring and a list of
213
- child keyrings of the same or a different type.
214
-
215
- The effect is like using several keyrings in a series. When you use a multi-keyring to
216
- encrypt data, any of the wrapping keys in any of its keyrings can decrypt that data.
205
+ You can add KMS keys from multiple regions to the ``AwsKmsMultiKeyring ``.
217
206
218
207
.. code :: python
219
208
220
- import boto3
221
209
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
222
210
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
223
211
from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsMultiKeyringInput
224
212
from aws_cryptographic_materialproviders.mpl.references import IKeyring
225
213
226
- import aws_encryption_sdk
227
- from aws_encryption_sdk import CommitmentPolicy
228
-
229
- # Instantiate the encryption SDK client.
230
- client = aws_encryption_sdk.EncryptionSDKClient(
231
- commitment_policy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
232
- )
233
-
234
- # Create an AwsKmsMultiKeyring that protects your data under two different KMS Keys.
214
+ # Create an AwsKmsMultiKeyring that protects your data under three different KMS Keys.
235
215
# Either KMS Key individually is capable of decrypting data encrypted under this Multi Keyring.
236
216
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
237
217
config = MaterialProvidersConfig()
238
218
)
239
219
240
220
kms_multi_keyring_input: CreateAwsKmsMultiKeyringInput = CreateAwsKmsMultiKeyringInput(
241
221
generator = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
242
- kms_key_ids = [' arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333' ]
222
+ kms_key_ids = [' arn:aws:kms:us-west-2:3333333333333:key/33333333-3333-3333-3333-333333333333' ,
223
+ ' arn:aws:kms:ap-northeast-1:4444444444444:key/44444444-4444-4444-4444-444444444444' ]
243
224
)
244
225
245
226
kms_multi_keyring: IKeyring = mat_prov.create_aws_kms_multi_keyring(
@@ -249,9 +230,8 @@ encrypt data, any of the wrapping keys in any of its keyrings can decrypt that d
249
230
250
231
AwsKmsDiscoveryKeyring
251
232
======================
252
- We recommend using an ``AwsKmsKeyring `` in order to ensure that you can only
253
- encrypt and decrypt data using the AWS KMS key ARN you expect,
254
- or a ``MultiKeyring `` if you are using multiple keys. However, if you are unable to
233
+ We recommend using an ``AwsKmsMultiKeyring `` in order to ensure that you can only
234
+ encrypt and decrypt data using the AWS KMS key ARN you expect. However, if you are unable to
255
235
explicitly identify the AWS KMS key ARNs that should be used for decryption, you can instead
256
236
use an ``AwsKmsDiscoveryKeyring `` for decryption operations. This provider
257
237
attempts decryption of any ciphertexts as long as they match a ``DiscoveryFilter `` that
@@ -263,20 +243,12 @@ partition.
263
243
import boto3
264
244
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
265
245
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
266
- ffrom aws_cryptographic_materialproviders.mpl.models import (
246
+ from aws_cryptographic_materialproviders.mpl.models import (
267
247
CreateAwsKmsDiscoveryKeyringInput,
268
248
DiscoveryFilter,
269
249
)
270
250
from aws_cryptographic_materialproviders.mpl.references import IKeyring
271
251
272
- import aws_encryption_sdk
273
- from aws_encryption_sdk import CommitmentPolicy
274
-
275
- # Instantiate the encryption SDK client.
276
- client = aws_encryption_sdk.EncryptionSDKClient(
277
- commitment_policy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
278
- )
279
-
280
252
# Create a Discovery keyring to use for decryption
281
253
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
282
254
config = MaterialProvidersConfig()
@@ -304,78 +276,94 @@ Encryption and Decryption
304
276
After you create an instance of an ``EncryptionSDKClient `` and a ``Keyring ``, you can use either of
305
277
the client's two ``encrypt ``/``decrypt `` functions to encrypt and decrypt your data.
306
278
307
- Here's an example for using a KMS keyring for encryption and decryption:
308
-
309
279
.. code :: python
310
280
311
- # Encrypt the data.
312
- my_ciphertext, enc_header = client.encrypt(
281
+ from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
282
+ from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
283
+ from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsMultiKeyringInput
284
+ from aws_cryptographic_materialproviders.mpl.references import IKeyring
285
+
286
+ import aws_encryption_sdk
287
+ from aws_encryption_sdk.identifiers import CommitmentPolicy
288
+
289
+ client = aws_encryption_sdk.EncryptionSDKClient(
290
+ commitment_policy = CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
291
+ )
292
+
293
+ mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
294
+ config = MaterialProvidersConfig()
295
+ )
296
+
297
+ kms_multi_keyring_input: CreateAwsKmsMultiKeyringInput = CreateAwsKmsMultiKeyringInput(
298
+ generator = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
299
+ kms_key_ids = [' arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333' ]
300
+ )
301
+
302
+ kms_multi_keyring: IKeyring = mat_prov.create_aws_kms_multi_keyring(
303
+ input = kms_multi_keyring_input
304
+ )
305
+
306
+ my_plaintext = b ' This is some super secret data! Yup, sure is!'
307
+
308
+ my_ciphertext, encryptor_header = client.encrypt(
313
309
source = my_plaintext,
314
- keyring = kms_keyring
310
+ keyring = kms_multi_keyring
315
311
)
316
312
317
- # Decrypt your encrypted data.
318
- my_decrypted_plaintext, dec_header = client.decrypt(
313
+ decrypted_plaintext, decryptor_header = client.decrypt(
319
314
source = my_ciphertext,
320
- keyring = kms_keyring
315
+ keyring = kms_multi_keyring
321
316
)
322
317
323
- You can provide an ` encryption context `_: a form of additional authenticating information.
318
+ assert my_plaintext == decrypted_plaintext
324
319
325
- Here's an example for using KMS keyring with an encryption context:
320
+ You can provide an ` encryption context `_: a form of additional authenticating information.
326
321
327
322
.. code :: python
328
323
329
- import boto3
330
324
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
331
325
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
332
- from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsKeyringInput
326
+ from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsMultiKeyringInput
333
327
from aws_cryptographic_materialproviders.mpl.references import IKeyring
334
328
335
329
import aws_encryption_sdk
336
- from aws_encryption_sdk import CommitmentPolicy
330
+ from aws_encryption_sdk.identifiers import CommitmentPolicy
337
331
338
- # Instantiate the encryption SDK client.
339
332
client = aws_encryption_sdk.EncryptionSDKClient(
340
- commitment_policy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
333
+ commitment_policy = CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
341
334
)
342
335
343
- # Create an encryption context
344
- encryption_context: Dict[str , str ] = {
345
- " encryption" : " context" ,
346
- " is not" : " secret" ,
347
- " but adds" : " useful metadata" ,
348
- " that can help you" : " be confident that" ,
349
- " the data you are handling" : " is what you think it is" ,
350
- }
351
-
352
- # Create a KMS keyring.
353
336
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
354
337
config = MaterialProvidersConfig()
355
338
)
356
339
357
- keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput (
358
- kms_key_id = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
359
- kms_client = boto3.client( ' kms' , region_name = " us-east-1" )
340
+ kms_multi_keyring_input: CreateAwsKmsMultiKeyringInput = CreateAwsKmsMultiKeyringInput (
341
+ generator = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
342
+ kms_key_ids = [ ' arn:aws: kms: us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333 ' ]
360
343
)
361
344
362
- kms_keyring : IKeyring = mat_prov.create_aws_kms_keyring (
363
- input = keyring_input
345
+ kms_multi_keyring : IKeyring = mat_prov.create_aws_kms_multi_keyring (
346
+ input = kms_multi_keyring_input
364
347
)
348
+
349
+ my_plaintext = b ' This is some super secret data! Yup, sure is!'
365
350
366
- # Encrypt the data with the encryptionContext.
367
- my_ciphertext, enc_header = client.encrypt(
351
+ my_ciphertext, encryptor_header = client.encrypt(
368
352
source = my_plaintext,
369
- keyring = kms_keyring,
370
- encryption_context = encryption_context
353
+ keyring = kms_multi_keyring,
354
+ encryption_context = {
355
+ ' not really' : ' a secret' ,
356
+ ' but adds' : ' some authentication'
357
+ }
371
358
)
372
359
373
- # Decrypt your encrypted data.
374
- my_decrypted_plaintext, dec_header = client.decrypt(
360
+ decrypted_plaintext, decryptor_header = client.decrypt(
375
361
source = my_ciphertext,
376
- keyring = kms_keyring
362
+ keyring = kms_multi_keyring
377
363
)
378
364
365
+ assert my_plaintext == decrypted_plaintext
366
+
379
367
380
368
Streaming
381
369
=========
@@ -386,59 +374,56 @@ offering context manager and iteration support.
386
374
387
375
.. code :: python
388
376
389
- import boto3
390
377
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
391
378
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
392
- from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsKeyringInput
379
+ from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsMultiKeyringInput
393
380
from aws_cryptographic_materialproviders.mpl.references import IKeyring
394
381
395
382
import aws_encryption_sdk
396
- from aws_encryption_sdk import CommitmentPolicy
383
+ from aws_encryption_sdk.identifiers import CommitmentPolicy
397
384
398
- # Instantiate the encryption SDK client.
399
385
client = aws_encryption_sdk.EncryptionSDKClient(
400
386
commitment_policy = CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
401
387
)
402
388
403
- # Create a keyring.
404
389
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
405
390
config = MaterialProvidersConfig()
406
391
)
407
392
408
- keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput (
409
- kms_key_id = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
410
- kms_client = boto3.client( ' kms' , region_name = " us-east-1" )
393
+ kms_multi_keyring_input: CreateAwsKmsMultiKeyringInput = CreateAwsKmsMultiKeyringInput (
394
+ generator = ' arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222' ,
395
+ kms_key_ids = [ ' arn:aws: kms: us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333 ' ]
411
396
)
412
397
413
- kms_keyring : IKeyring = mat_prov.create_aws_kms_keyring (
414
- input = keyring_input
398
+ kms_multi_keyring : IKeyring = mat_prov.create_aws_kms_multi_keyring (
399
+ input = kms_multi_keyring_input
415
400
)
416
401
417
402
plaintext_filename = ' my-secret-data.dat'
418
403
ciphertext_filename = ' my-encrypted-data.ct'
419
404
420
- # Encrypt the data stream.
421
405
with open (plaintext_filename, ' rb' ) as pt_file, open (ciphertext_filename, ' wb' ) as ct_file:
422
406
with client.stream(
423
407
mode = ' e' ,
424
408
source = pt_file,
425
- keyring = kms_keyring
409
+ keyring = kms_multi_keyring
426
410
) as encryptor:
427
411
for chunk in encryptor:
428
412
ct_file.write(chunk)
429
413
430
414
decrypted_filename = ' my-decrypted-data.dat'
431
415
432
- # Decrypt your encrypted data stream.
433
416
with open (ciphertext_filename, ' rb' ) as ct_file, open (decrypted_filename, ' wb' ) as pt_file:
434
417
with client.stream(
435
418
mode = ' d' ,
436
419
source = ct_file,
437
- keyring = kms_keyring
420
+ keyring = kms_multi_keyring
438
421
) as decryptor:
439
422
for chunk in decryptor:
440
423
pt_file.write(chunk)
441
424
425
+ assert filecmp.cmp(plaintext_filename, decrypted_filename)
426
+
442
427
443
428
Performance Considerations
444
429
==========================
@@ -456,7 +441,7 @@ raw keyrings need testing, but may be launched as not thread safe.
456
441
457
442
The ``EncryptionSDKClient `` class is thread safe.
458
443
But instances of key material providers (i.e. keyrings or legacy master key providers) that call AWS KMS
459
- (ex. ``AwsKmsKeyring `` or other KMS keyrings; ``BaseKmsMasterKeyProvider `` or children of this class)
444
+ (ex. ``AwsKmsMultiKeyring `` or other KMS keyrings; ``BaseKmsMasterKeyProvider `` or children of this class)
460
445
MUST not be shared between threads
461
446
for the reasons outlined in `the boto3 docs <https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html#multithreading-or-multiprocessing-with-resources >`_.
462
447
0 commit comments