Skip to content

Commit 314323e

Browse files
committed
docs: add example to replicate AWS KMS MKP behavior with AWS KMS keyring
1 parent 00fcfe7 commit 314323e

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

examples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
4444
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt_in_region_only.py)
4545
* How to decrypt with a preferred region but failover to others
4646
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py)
47+
* How to replicate the behavior of an AWS KMS master key provider
48+
* [with keyrings](./src/keyring/aws_kms/act_like_aws_kms_master_key_provider.py)
4749
* Using raw wrapping keys
4850
* How to use a raw AES wrapping key
4951
* [with keyrings](./src/keyring/raw_aes/raw_aes.py)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Before there were keyrings, there were master key providers.
5+
Master key providers were the original configuration structure
6+
that we provided for defining how you want to protect your data keys.
7+
8+
The AWS KMS master key provider was the tool that we provided for interacting with AWS KMS.
9+
Like the AWS KMS keyring,
10+
the AWS KMS master key provider encrypts with all CMKs that you identify,
11+
but unlike the AWS KMS keyring,
12+
the AWS KMS master key provider always attempts to decrypt
13+
*any* data keys that were encrypted under an AWS KMS CMK.
14+
We have found that separating these two behaviors out,
15+
as we did in the AWS KMS keyring,
16+
makes it more clear what behavior to expect.
17+
However, as you migrate away from master key providers to keyrings,
18+
you might need to replicate the exact behavior of the AWS KMS master key provider.
19+
20+
This example shows how to configure a keyring that behaves like an AWS KMS master key provider.
21+
22+
For more examples of how to use the AWS KMS keyring,
23+
see the ``keyring/aws_kms`` directory.
24+
"""
25+
import aws_encryption_sdk
26+
from aws_encryption_sdk.key_providers.kms import KMSMasterKeyProvider
27+
from aws_encryption_sdk.keyrings.aws_kms import AwsKmsKeyring
28+
from aws_encryption_sdk.keyrings.multi import MultiKeyring
29+
30+
31+
def run(aws_kms_cmk, source_plaintext):
32+
# type: (str, bytes) -> None
33+
"""Demonstrate how to create a keyring that behaves like an AWS KMS master key provider.
34+
35+
:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys
36+
:param bytes source_plaintext: Plaintext to encrypt
37+
"""
38+
# Prepare your encryption context.
39+
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
40+
encryption_context = {
41+
"encryption": "context",
42+
"is not": "secret",
43+
"but adds": "useful metadata",
44+
"that can help you": "be confident that",
45+
"the data you are handling": "is what you think it is",
46+
}
47+
48+
# This is the master key provider whose behavior we want to replicate.
49+
#
50+
# On encrypt, this master key provider only uses the single target AWS KMS CMK,
51+
# but on decrypt, this master key provider attempts to decrypt
52+
# any data keys that were encrypted under an AWS KMS CMK.
53+
_master_key_provider_to_replicate = KMSMasterKeyProvider(key_ids=[aws_kms_cmk])
54+
55+
# Create a keyring that encrypts and decrypts using a single AWS KMS CMK.
56+
single_cmk_keyring = AwsKmsKeyring(generator_key_id=aws_kms_cmk)
57+
58+
# Create a discovery keyring that will attempt to decrypt
59+
# any data keys that were encrypted under an AWS KMS CMK.
60+
discovery_keyring = AwsKmsKeyring(is_discovery=True)
61+
62+
# Combine the single-CMK and discovery keyrings
63+
# to create a keyring that behaves like an AWS KMS master key provider.
64+
keyring = MultiKeyring(generator=single_cmk_keyring, children=[discovery_keyring])
65+
66+
# Encrypt your plaintext data.
67+
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt(
68+
source=source_plaintext, encryption_context=encryption_context, keyring=keyring
69+
)
70+
71+
# Demonstrate that the ciphertext and plaintext are different.
72+
assert ciphertext != source_plaintext
73+
74+
# Decrypt your encrypted data using the same keyring you used on encrypt.
75+
#
76+
# You do not need to specify the encryption context on decrypt
77+
# because the header of the encrypted message includes the encryption context.
78+
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, keyring=keyring)
79+
80+
# Demonstrate that the decrypted plaintext is identical to the original plaintext.
81+
assert decrypted == source_plaintext
82+
83+
# Verify that the encryption context used in the decrypt operation includes
84+
# the encryption context that you specified when encrypting.
85+
# The AWS Encryption SDK can add pairs, so don't require an exact match.
86+
#
87+
# In production, always use a meaningful encryption context.
88+
assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items())

0 commit comments

Comments
 (0)