From 314323e5511ea18420e8a357c9ca7662609b3138 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Thu, 16 Apr 2020 14:58:29 -0700 Subject: [PATCH 01/16] docs: add example to replicate AWS KMS MKP behavior with AWS KMS keyring --- examples/README.md | 2 + .../act_like_aws_kms_master_key_provider.py | 88 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py diff --git a/examples/README.md b/examples/README.md index 081e62fab..2d95fb535 100644 --- a/examples/README.md +++ b/examples/README.md @@ -44,6 +44,8 @@ We start with AWS KMS examples, then show how to use other wrapping keys. * [with keyrings](./src/keyring/aws_kms/discovery_decrypt_in_region_only.py) * How to decrypt with a preferred region but failover to others * [with keyrings](./src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py) + * How to replicate the behavior of an AWS KMS master key provider + * [with keyrings](./src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py) * Using raw wrapping keys * How to use a raw AES wrapping key * [with keyrings](./src/keyring/raw_aes/raw_aes.py) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py new file mode 100644 index 000000000..88c0059cc --- /dev/null +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -0,0 +1,88 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Before there were keyrings, there were master key providers. +Master key providers were the original configuration structure +that we provided for defining how you want to protect your data keys. + +The AWS KMS master key provider was the tool that we provided for interacting with AWS KMS. +Like the AWS KMS keyring, +the AWS KMS master key provider encrypts with all CMKs that you identify, +but unlike the AWS KMS keyring, +the AWS KMS master key provider always attempts to decrypt +*any* data keys that were encrypted under an AWS KMS CMK. +We have found that separating these two behaviors out, +as we did in the AWS KMS keyring, +makes it more clear what behavior to expect. +However, as you migrate away from master key providers to keyrings, +you might need to replicate the exact behavior of the AWS KMS master key provider. + +This example shows how to configure a keyring that behaves like an AWS KMS master key provider. + +For more examples of how to use the AWS KMS keyring, +see the ``keyring/aws_kms`` directory. +""" +import aws_encryption_sdk +from aws_encryption_sdk.key_providers.kms import KMSMasterKeyProvider +from aws_encryption_sdk.keyrings.aws_kms import AwsKmsKeyring +from aws_encryption_sdk.keyrings.multi import MultiKeyring + + +def run(aws_kms_cmk, source_plaintext): + # type: (str, bytes) -> None + """Demonstrate how to create a keyring that behaves like an AWS KMS master key provider. + + :param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys + :param bytes source_plaintext: Plaintext to encrypt + """ + # Prepare your encryption context. + # https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context + encryption_context = { + "encryption": "context", + "is not": "secret", + "but adds": "useful metadata", + "that can help you": "be confident that", + "the data you are handling": "is what you think it is", + } + + # This is the master key provider whose behavior we want to replicate. + # + # On encrypt, this master key provider only uses the single target AWS KMS CMK, + # but on decrypt, this master key provider attempts to decrypt + # any data keys that were encrypted under an AWS KMS CMK. + _master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) + + # Create a keyring that encrypts and decrypts using a single AWS KMS CMK. + single_cmk_keyring = AwsKmsKeyring(generator_key_id=aws_kms_cmk) + + # Create a discovery keyring that will attempt to decrypt + # any data keys that were encrypted under an AWS KMS CMK. + discovery_keyring = AwsKmsKeyring(is_discovery=True) + + # Combine the single-CMK and discovery keyrings + # to create a keyring that behaves like an AWS KMS master key provider. + keyring = MultiKeyring(generator=single_cmk_keyring, children=[discovery_keyring]) + + # Encrypt your plaintext data. + ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( + source=source_plaintext, encryption_context=encryption_context, keyring=keyring + ) + + # Demonstrate that the ciphertext and plaintext are different. + assert ciphertext != source_plaintext + + # Decrypt your encrypted data using the same keyring you used on encrypt. + # + # You do not need to specify the encryption context on decrypt + # because the header of the encrypted message includes the encryption context. + decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, keyring=keyring) + + # Demonstrate that the decrypted plaintext is identical to the original plaintext. + assert decrypted == source_plaintext + + # Verify that the encryption context used in the decrypt operation includes + # the encryption context that you specified when encrypting. + # The AWS Encryption SDK can add pairs, so don't require an exact match. + # + # In production, always use a meaningful encryption context. + assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items()) From 356083dc8e27066da8ddf67843e039bc56246bcb Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Thu, 16 Apr 2020 15:04:40 -0700 Subject: [PATCH 02/16] docs: thanks, grazie; fixing grammar --- .../keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 88c0059cc..f2349f394 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -47,8 +47,8 @@ def run(aws_kms_cmk, source_plaintext): # This is the master key provider whose behavior we want to replicate. # - # On encrypt, this master key provider only uses the single target AWS KMS CMK, - # but on decrypt, this master key provider attempts to decrypt + # On encrypt, this master key provider only uses the single target AWS KMS CMK. + # However, on decrypt, this master key provider attempts to decrypt # any data keys that were encrypted under an AWS KMS CMK. _master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) From 3c71661db1b24d4bf115a42a03c9d76a6e605623 Mon Sep 17 00:00:00 2001 From: Matt Bullock Date: Fri, 17 Apr 2020 11:21:48 -0700 Subject: [PATCH 03/16] docs: update examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py Co-Authored-By: Wesley Rosenblum <55108558+WesleyRosenblum@users.noreply.github.com> --- .../src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index f2349f394..ba2bc23a6 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -55,7 +55,7 @@ def run(aws_kms_cmk, source_plaintext): # Create a keyring that encrypts and decrypts using a single AWS KMS CMK. single_cmk_keyring = AwsKmsKeyring(generator_key_id=aws_kms_cmk) - # Create a discovery keyring that will attempt to decrypt + # Create an AWS KMS discovery keyring that will attempt to decrypt # any data keys that were encrypted under an AWS KMS CMK. discovery_keyring = AwsKmsKeyring(is_discovery=True) From b0c0cc04800590942a93ef37f2e69afd65b187a9 Mon Sep 17 00:00:00 2001 From: Matt Bullock Date: Fri, 17 Apr 2020 11:56:01 -0700 Subject: [PATCH 04/16] docs: update examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py --- .../src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index ba2bc23a6..8b2327e82 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -15,7 +15,7 @@ as we did in the AWS KMS keyring, makes it more clear what behavior to expect. However, as you migrate away from master key providers to keyrings, -you might need to replicate the exact behavior of the AWS KMS master key provider. +you might need to replicate the behavior of the AWS KMS master key provider. This example shows how to configure a keyring that behaves like an AWS KMS master key provider. From 93a13711bebe694134c90b798b8e2ce28f7f37e8 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Fri, 17 Apr 2020 11:58:01 -0700 Subject: [PATCH 05/16] docs: reword behavior separation statement --- .../keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 8b2327e82..d3897cfa4 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -11,9 +11,9 @@ but unlike the AWS KMS keyring, the AWS KMS master key provider always attempts to decrypt *any* data keys that were encrypted under an AWS KMS CMK. -We have found that separating these two behaviors out, -as we did in the AWS KMS keyring, -makes it more clear what behavior to expect. +We have found that separating these two behaviors +makes it more clear what behavior to expect, +so that is what we did with the AWS KMS keyring and the AWS KMS discovery keyring. However, as you migrate away from master key providers to keyrings, you might need to replicate the behavior of the AWS KMS master key provider. From 70134b1b9b9948cd89ceeca3d993fa75d2b0e40c Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Fri, 17 Apr 2020 12:13:38 -0700 Subject: [PATCH 06/16] docs: linting fix --- .../src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index d3897cfa4..7ff65034a 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -50,7 +50,7 @@ def run(aws_kms_cmk, source_plaintext): # On encrypt, this master key provider only uses the single target AWS KMS CMK. # However, on decrypt, this master key provider attempts to decrypt # any data keys that were encrypted under an AWS KMS CMK. - _master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) + _master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) # noqa: intentionally never used # Create a keyring that encrypts and decrypts using a single AWS KMS CMK. single_cmk_keyring = AwsKmsKeyring(generator_key_id=aws_kms_cmk) From 0181431d1e71208d39232c9d2797cf2650134d78 Mon Sep 17 00:00:00 2001 From: Matt Bullock Date: Mon, 20 Apr 2020 13:19:50 -0700 Subject: [PATCH 07/16] docs: apply suggestions from code review Co-Authored-By: June Blender --- .../act_like_aws_kms_master_key_provider.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 7ff65034a..7abb2d312 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -1,21 +1,19 @@ # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """ -Before there were keyrings, there were master key providers. -Master key providers were the original configuration structure -that we provided for defining how you want to protect your data keys. +In earlier versions of the AWS Encryption SDK, you used master key providers to determine how your data keys are protected. -The AWS KMS master key provider was the tool that we provided for interacting with AWS KMS. +The AWS Encryption SDK provided an AWS KMS master key provider for interacting with AWS Key Management Service (AWS KMS). Like the AWS KMS keyring, the AWS KMS master key provider encrypts with all CMKs that you identify, but unlike the AWS KMS keyring, the AWS KMS master key provider always attempts to decrypt *any* data keys that were encrypted under an AWS KMS CMK. We have found that separating these two behaviors -makes it more clear what behavior to expect, +makes the expected behavior clearer, so that is what we did with the AWS KMS keyring and the AWS KMS discovery keyring. -However, as you migrate away from master key providers to keyrings, -you might need to replicate the behavior of the AWS KMS master key provider. +However, as you migrate from master key providers to keyrings, +you might want a keyring that behaves like the AWS KMS master key provider. This example shows how to configure a keyring that behaves like an AWS KMS master key provider. @@ -47,8 +45,8 @@ def run(aws_kms_cmk, source_plaintext): # This is the master key provider whose behavior we want to replicate. # - # On encrypt, this master key provider only uses the single target AWS KMS CMK. - # However, on decrypt, this master key provider attempts to decrypt + # When encrypting, this master key provider uses only the specified `aws_kms_cmk`. + # However, when decrypting, this master key provider attempts to decrypt # any data keys that were encrypted under an AWS KMS CMK. _master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) # noqa: intentionally never used From 2aed0c87a9219329e907fb44dedfae0c922eb427 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Mon, 20 Apr 2020 13:30:08 -0700 Subject: [PATCH 08/16] docs: s/replicate/reproduce/ --- examples/README.md | 2 +- .../src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/README.md b/examples/README.md index 2d95fb535..700af4c97 100644 --- a/examples/README.md +++ b/examples/README.md @@ -44,7 +44,7 @@ We start with AWS KMS examples, then show how to use other wrapping keys. * [with keyrings](./src/keyring/aws_kms/discovery_decrypt_in_region_only.py) * How to decrypt with a preferred region but failover to others * [with keyrings](./src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py) - * How to replicate the behavior of an AWS KMS master key provider + * How to reproduce the behavior of an AWS KMS master key provider * [with keyrings](./src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py) * Using raw wrapping keys * How to use a raw AES wrapping key diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 7abb2d312..8a315441c 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -43,7 +43,7 @@ def run(aws_kms_cmk, source_plaintext): "the data you are handling": "is what you think it is", } - # This is the master key provider whose behavior we want to replicate. + # This is the master key provider whose behavior we want to reproduce. # # When encrypting, this master key provider uses only the specified `aws_kms_cmk`. # However, when decrypting, this master key provider attempts to decrypt From bbb24efbc343885f0ef17b0dafa66a42333aabad Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Mon, 20 Apr 2020 13:31:00 -0700 Subject: [PATCH 09/16] docs: keep naming consistent --- .../src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 8a315441c..49b2616a4 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -50,7 +50,7 @@ def run(aws_kms_cmk, source_plaintext): # any data keys that were encrypted under an AWS KMS CMK. _master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) # noqa: intentionally never used - # Create a keyring that encrypts and decrypts using a single AWS KMS CMK. + # Create a single-CMK keyring that encrypts and decrypts using a single AWS KMS CMK. single_cmk_keyring = AwsKmsKeyring(generator_key_id=aws_kms_cmk) # Create an AWS KMS discovery keyring that will attempt to decrypt From b7ced3d1950eda0d67bae9d1a3470909e4d0a572 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Tue, 21 Apr 2020 09:58:26 -0700 Subject: [PATCH 10/16] docs: fix line length issue in docstring --- .../keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 49b2616a4..d213d4440 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -1,9 +1,11 @@ # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """ -In earlier versions of the AWS Encryption SDK, you used master key providers to determine how your data keys are protected. +In earlier versions of the AWS Encryption SDK, +you used master key providers to determine how your data keys are protected. -The AWS Encryption SDK provided an AWS KMS master key provider for interacting with AWS Key Management Service (AWS KMS). +The AWS Encryption SDK provided an AWS KMS master key provider for +interacting with AWS Key Management Service (AWS KMS). Like the AWS KMS keyring, the AWS KMS master key provider encrypts with all CMKs that you identify, but unlike the AWS KMS keyring, From 6239257b525e60a9ca0d3ba2f54dd18bea83ed91 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 22 Apr 2020 11:00:17 -0700 Subject: [PATCH 11/16] docs: revise description of AWS KMS discovery decrypt behavior --- .../act_like_aws_kms_master_key_provider.py | 16 ++++++++++------ .../src/keyring/aws_kms/discovery_decrypt.py | 8 +++++++- .../aws_kms/discovery_decrypt_in_region_only.py | 8 +++++++- .../discovery_decrypt_with_preferred_regions.py | 9 ++++++++- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index d213d4440..77e5c32fd 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -1,24 +1,28 @@ # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """ -In earlier versions of the AWS Encryption SDK, -you used master key providers to determine how your data keys are protected. +You might have used master key providers to protect your data keys +in an earlier version of the AWS Encryption SDK. +This example shows how to configure a keyring that behaves like an AWS KMS master key provider. The AWS Encryption SDK provided an AWS KMS master key provider for interacting with AWS Key Management Service (AWS KMS). Like the AWS KMS keyring, the AWS KMS master key provider encrypts with all CMKs that you identify, but unlike the AWS KMS keyring, -the AWS KMS master key provider always attempts to decrypt -*any* data keys that were encrypted under an AWS KMS CMK. +the AWS KMS master key provider reviews each encrypted data key (EDK) in turn +and if the EDK was encrypted under an AWS KMS CMK +then the AWS KMS master key provider attempts to decrypt it. +Whether decryption succeeds depends on network access to the KMS service +and permissions on the CMK. +This continues until the AWS KMS master key provider either runs out of EDKs +or succeeds in decrypting an EDK. We have found that separating these two behaviors makes the expected behavior clearer, so that is what we did with the AWS KMS keyring and the AWS KMS discovery keyring. However, as you migrate from master key providers to keyrings, you might want a keyring that behaves like the AWS KMS master key provider. -This example shows how to configure a keyring that behaves like an AWS KMS master key provider. - For more examples of how to use the AWS KMS keyring, see the ``keyring/aws_kms`` directory. """ diff --git a/examples/src/keyring/aws_kms/discovery_decrypt.py b/examples/src/keyring/aws_kms/discovery_decrypt.py index cd329b1c9..78f5c3a14 100644 --- a/examples/src/keyring/aws_kms/discovery_decrypt.py +++ b/examples/src/keyring/aws_kms/discovery_decrypt.py @@ -7,7 +7,13 @@ especially when you don't know which CMKs were used to encrypt a message. To address this need, you can use an AWS KMS discovery keyring. The AWS KMS discovery keyring does nothing on encrypt, -but attempts to decrypt *any* data keys that were encrypted under an AWS KMS CMK. +but on decrypt it reviews each encrypted data key (EDK) in turn +and if the EDK was encrypted under an AWS KMS CMK +then the AWS KMS discovery keyring attempts to decrypt it. +Whether decryption succeeds depends on network access to the KMS service +and permissions on the CMK. +This continues until the AWS KMS discovery keyring either runs out of EDKs +or succeeds in decrypting an EDK. This example shows how to configure and use an AWS KMS discovery keyring. diff --git a/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py b/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py index 97e1e2b15..4a65f3a0e 100644 --- a/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py +++ b/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py @@ -7,7 +7,13 @@ especially when you don't know which CMKs were used to encrypt a message. To address this need, you can use an AWS KMS discovery keyring. The AWS KMS discovery keyring does nothing on encrypt, -but attempts to decrypt *any* data keys that were encrypted under an AWS KMS CMK. +but on decrypt it reviews each encrypted data key (EDK) in turn +and if the EDK was encrypted under an AWS KMS CMK +then the AWS KMS discovery keyring attempts to decrypt it. +Whether decryption succeeds depends on network access to the KMS service +and permissions on the CMK. +This continues until the AWS KMS discovery keyring either runs out of EDKs +or succeeds in decrypting an EDK. However, sometimes you need to be a *bit* more restrictive than that. To address this need, you can use a client supplier that restricts the regions an AWS KMS keyring can talk to. diff --git a/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py b/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py index ff823e02f..3691024bf 100644 --- a/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py +++ b/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py @@ -7,7 +7,14 @@ especially when you don't know which CMKs were used to encrypt a message. To address this need, you can use an AWS KMS discovery keyring. The AWS KMS discovery keyring does nothing on encrypt, -but attempts to decrypt *any* data keys that were encrypted under an AWS KMS CMK. +The AWS KMS discovery keyring does nothing on encrypt, +but on decrypt it reviews each encrypted data key (EDK) in turn +and if the EDK was encrypted under an AWS KMS CMK +then the AWS KMS discovery keyring attempts to decrypt it. +Whether decryption succeeds depends on network access to the KMS service +and permissions on the CMK. +This continues until the AWS KMS discovery keyring either runs out of EDKs +or succeeds in decrypting an EDK. However, sometimes you need to be a *bit* more restrictive than that. To address this need, you can use a client supplier to restrict what regions an AWS KMS keyring can talk to. From 52d6277a8a8b44ba1fbb868fd2c6a6b17bcc96af Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 22 Apr 2020 11:18:44 -0700 Subject: [PATCH 12/16] docs: remove duplicate typo --- .../keyring/aws_kms/discovery_decrypt_with_preferred_regions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py b/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py index 3691024bf..b4fe160d3 100644 --- a/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py +++ b/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py @@ -7,7 +7,6 @@ especially when you don't know which CMKs were used to encrypt a message. To address this need, you can use an AWS KMS discovery keyring. The AWS KMS discovery keyring does nothing on encrypt, -The AWS KMS discovery keyring does nothing on encrypt, but on decrypt it reviews each encrypted data key (EDK) in turn and if the EDK was encrypted under an AWS KMS CMK then the AWS KMS discovery keyring attempts to decrypt it. From 88372844ded093ed1645521889eb2af5bb0db622 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 22 Apr 2020 12:04:12 -0700 Subject: [PATCH 13/16] docs: refine wording on discovery descriptions --- .../act_like_aws_kms_master_key_provider.py | 15 +++++++-------- examples/src/keyring/aws_kms/discovery_decrypt.py | 11 +++++------ .../aws_kms/discovery_decrypt_in_region_only.py | 11 +++++------ .../discovery_decrypt_with_preferred_regions.py | 11 +++++------ 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 77e5c32fd..cb767ca00 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -7,14 +7,13 @@ The AWS Encryption SDK provided an AWS KMS master key provider for interacting with AWS Key Management Service (AWS KMS). -Like the AWS KMS keyring, -the AWS KMS master key provider encrypts with all CMKs that you identify, -but unlike the AWS KMS keyring, -the AWS KMS master key provider reviews each encrypted data key (EDK) in turn -and if the EDK was encrypted under an AWS KMS CMK -then the AWS KMS master key provider attempts to decrypt it. -Whether decryption succeeds depends on network access to the KMS service -and permissions on the CMK. +On encrypt, the AWS KMS master key provider behaves like the AWS KMS keyring +and encrypts with all CMKs that you identify. +However, on decrypt, +the AWS KMS master key provider reviews each encrypted data key (EDK). +If the EDK was encrypted under an AWS KMS CMK, +the AWS KMS master key provider attempts to decrypt it. +Whether decryption succeeds depends on permissions on the CMK. This continues until the AWS KMS master key provider either runs out of EDKs or succeeds in decrypting an EDK. We have found that separating these two behaviors diff --git a/examples/src/keyring/aws_kms/discovery_decrypt.py b/examples/src/keyring/aws_kms/discovery_decrypt.py index 78f5c3a14..54ee5fc10 100644 --- a/examples/src/keyring/aws_kms/discovery_decrypt.py +++ b/examples/src/keyring/aws_kms/discovery_decrypt.py @@ -6,12 +6,11 @@ However, sometimes you need more flexibility on decrypt, especially when you don't know which CMKs were used to encrypt a message. To address this need, you can use an AWS KMS discovery keyring. -The AWS KMS discovery keyring does nothing on encrypt, -but on decrypt it reviews each encrypted data key (EDK) in turn -and if the EDK was encrypted under an AWS KMS CMK -then the AWS KMS discovery keyring attempts to decrypt it. -Whether decryption succeeds depends on network access to the KMS service -and permissions on the CMK. +The AWS KMS discovery keyring does nothing on encrypt. +On decrypt it reviews each encrypted data key (EDK). +If an EDK was encrypted under an AWS KMS CMK, +the AWS KMS discovery keyring attempts to decrypt it. +Whether decryption succeeds depends on permissions on the CMK. This continues until the AWS KMS discovery keyring either runs out of EDKs or succeeds in decrypting an EDK. diff --git a/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py b/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py index 4a65f3a0e..162bfd88f 100644 --- a/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py +++ b/examples/src/keyring/aws_kms/discovery_decrypt_in_region_only.py @@ -6,12 +6,11 @@ However, sometimes you need more flexibility on decrypt, especially when you don't know which CMKs were used to encrypt a message. To address this need, you can use an AWS KMS discovery keyring. -The AWS KMS discovery keyring does nothing on encrypt, -but on decrypt it reviews each encrypted data key (EDK) in turn -and if the EDK was encrypted under an AWS KMS CMK -then the AWS KMS discovery keyring attempts to decrypt it. -Whether decryption succeeds depends on network access to the KMS service -and permissions on the CMK. +The AWS KMS discovery keyring does nothing on encrypt. +On decrypt it reviews each encrypted data key (EDK). +If an EDK was encrypted under an AWS KMS CMK, +the AWS KMS discovery keyring attempts to decrypt it. +Whether decryption succeeds depends on permissions on the CMK. This continues until the AWS KMS discovery keyring either runs out of EDKs or succeeds in decrypting an EDK. diff --git a/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py b/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py index b4fe160d3..a9d753c9d 100644 --- a/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py +++ b/examples/src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py @@ -6,12 +6,11 @@ However, sometimes you need more flexibility on decrypt, especially when you don't know which CMKs were used to encrypt a message. To address this need, you can use an AWS KMS discovery keyring. -The AWS KMS discovery keyring does nothing on encrypt, -but on decrypt it reviews each encrypted data key (EDK) in turn -and if the EDK was encrypted under an AWS KMS CMK -then the AWS KMS discovery keyring attempts to decrypt it. -Whether decryption succeeds depends on network access to the KMS service -and permissions on the CMK. +The AWS KMS discovery keyring does nothing on encrypt. +On decrypt it reviews each encrypted data key (EDK). +If an EDK was encrypted under an AWS KMS CMK, +the AWS KMS discovery keyring attempts to decrypt it. +Whether decryption succeeds depends on permissions on the CMK. This continues until the AWS KMS discovery keyring either runs out of EDKs or succeeds in decrypting an EDK. From b3598d339a9ea0b954da4c88d4742a4092c05474 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 22 Apr 2020 12:53:35 -0700 Subject: [PATCH 14/16] docs: revise AWS KMS keyring-as-mkp example * show using multiple CMKs * demonstrate how the generating CMK is defined in both * explain that it does not matter if the CMK keyring fails --- .../act_like_aws_kms_master_key_provider.py | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index cb767ca00..de8b2eb90 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -30,12 +30,19 @@ from aws_encryption_sdk.keyrings.aws_kms import AwsKmsKeyring from aws_encryption_sdk.keyrings.multi import MultiKeyring +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Sequence # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass -def run(aws_kms_cmk, source_plaintext): - # type: (str, bytes) -> None + +def run(aws_kms_cmk, aws_kms_additional_cmks, source_plaintext): + # type: (str, Sequence[str], bytes) -> None """Demonstrate how to create a keyring that behaves like an AWS KMS master key provider. :param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys + :param List[str] aws_kms_additional_cmks: Additional ARNs of secondary AWS KMS CMKs :param bytes source_plaintext: Plaintext to encrypt """ # Prepare your encryption context. @@ -50,13 +57,22 @@ def run(aws_kms_cmk, source_plaintext): # This is the master key provider whose behavior we want to reproduce. # - # When encrypting, this master key provider uses only the specified `aws_kms_cmk`. + # When encrypting, this master key provider generates the data key using the first CMK in the list + # and encrypts the data key using all specified CMKs. # However, when decrypting, this master key provider attempts to decrypt # any data keys that were encrypted under an AWS KMS CMK. - _master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk]) # noqa: intentionally never used + master_key_provider_cmks = [aws_kms_cmk] + aws_kms_additional_cmks + _master_key_provider_to_replicate = KMSMasterKeyProvider( # noqa: intentionally never used + key_ids=master_key_provider_cmks, + ) - # Create a single-CMK keyring that encrypts and decrypts using a single AWS KMS CMK. - single_cmk_keyring = AwsKmsKeyring(generator_key_id=aws_kms_cmk) + # Create a CMK keyring that encrypts and decrypts using the specified AWS KMS CMKs. + # + # This keyring reproduces the encryption behavior of the AWS KMS master key provider. + # + # The AWS KMS keyring requires that you explicitly identify the CMK + # that you want the keyring to use to generate the data key. + cmk_keyring = AwsKmsKeyring(generator_key_id=aws_kms_cmk, key_ids=aws_kms_additional_cmks) # Create an AWS KMS discovery keyring that will attempt to decrypt # any data keys that were encrypted under an AWS KMS CMK. @@ -64,7 +80,15 @@ def run(aws_kms_cmk, source_plaintext): # Combine the single-CMK and discovery keyrings # to create a keyring that behaves like an AWS KMS master key provider. - keyring = MultiKeyring(generator=single_cmk_keyring, children=[discovery_keyring]) + # + # The CMK keyring reproduces the encryption behavior + # and the discovery keyring reproduces the decryption behavior. + # This also means that it does not matter if the CMK keyring fails on decrypt, + # for example if you configured it with aliases which would work on encrypt + # but fail to match any encrypted data keys on decrypt, + # because the discovery keyring attempts to decrypt any AWS KMS-encrypted + # data keys that it finds. + keyring = MultiKeyring(generator=cmk_keyring, children=[discovery_keyring]) # Encrypt your plaintext data. ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( From 86f618b3298a396c68eda3a7e892664207c05bfa Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Thu, 23 Apr 2020 14:17:29 -0700 Subject: [PATCH 15/16] docs: break up long sentence --- .../aws_kms/act_like_aws_kms_master_key_provider.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index de8b2eb90..219a15401 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -83,11 +83,12 @@ def run(aws_kms_cmk, aws_kms_additional_cmks, source_plaintext): # # The CMK keyring reproduces the encryption behavior # and the discovery keyring reproduces the decryption behavior. - # This also means that it does not matter if the CMK keyring fails on decrypt, - # for example if you configured it with aliases which would work on encrypt - # but fail to match any encrypted data keys on decrypt, - # because the discovery keyring attempts to decrypt any AWS KMS-encrypted - # data keys that it finds. + # This also means that it does not matter if the CMK keyring fails to decrypt. + # For example if you configured the CMK keyring with aliases, + # it works on encrypt but fails to match any encrypted data keys on decrypt + # because the serialized key name is the resulting CMK ARN rather than the alias name. + # However, because the discovery keyring attempts to decrypt any AWS KMS-encrypted + # data keys that it finds, the message still decrypts successfully. keyring = MultiKeyring(generator=cmk_keyring, children=[discovery_keyring]) # Encrypt your plaintext data. From a57c3791bab17860efb0bd81b9792f42662de3ca Mon Sep 17 00:00:00 2001 From: Matt Bullock Date: Thu, 23 Apr 2020 23:21:41 -0700 Subject: [PATCH 16/16] docs: update examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py Co-Authored-By: Wesley Rosenblum <55108558+WesleyRosenblum@users.noreply.github.com> --- .../src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py index 219a15401..89eeda62b 100644 --- a/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py +++ b/examples/src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py @@ -84,7 +84,7 @@ def run(aws_kms_cmk, aws_kms_additional_cmks, source_plaintext): # The CMK keyring reproduces the encryption behavior # and the discovery keyring reproduces the decryption behavior. # This also means that it does not matter if the CMK keyring fails to decrypt. - # For example if you configured the CMK keyring with aliases, + # For example, if you configured the CMK keyring with aliases, # it works on encrypt but fails to match any encrypted data keys on decrypt # because the serialized key name is the resulting CMK ARN rather than the alias name. # However, because the discovery keyring attempts to decrypt any AWS KMS-encrypted