Skip to content

Commit 5abbf9c

Browse files
authored
docs: merge pull request #236 from mattsb42-aws/mkp-examples
docs: add master key provider examples
2 parents cbce224 + c5d3a94 commit 5abbf9c

File tree

13 files changed

+603
-1
lines changed

13 files changed

+603
-1
lines changed

examples/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,32 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
3333
* Using AWS Key Management Service (AWS KMS)
3434
* How to use one AWS KMS CMK
3535
* [with keyrings](./src/keyring/aws_kms/single_cmk.py)
36+
* [with master key providers](./src/master_key_provider/aws_kms/single_cmk.py)
3637
* How to use multiple AWS KMS CMKs in different regions
3738
* [with keyrings](./src/keyring/aws_kms/multiple_regions.py)
39+
* [with master key providers](./src/master_key_provider/aws_kms/multiple_regions.py)
3840
* How to decrypt when you don't know the CMK
3941
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt.py)
42+
* [with master key providers](./src/master_key_provider/aws_kms/discovery_decrypt.py)
4043
* How to decrypt within a region
4144
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt_in_region_only.py)
4245
* How to decrypt with a preferred region but failover to others
4346
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py)
4447
* Using raw wrapping keys
4548
* How to use a raw AES wrapping key
4649
* [with keyrings](./src/keyring/raw_aes/raw_aes.py)
50+
* [with master key providers](./src/master_key_provider/raw_aes/raw_aes.py)
4751
* How to use a raw RSA wrapping key
4852
* [with keyrings](./src/keyring/raw_rsa/private_key_only.py)
4953
* How to use a raw RSA wrapping key when the key is PEM or DER encoded
5054
* [with keyrings](./src/keyring/raw_rsa/private_key_only_from_pem.py)
55+
* [with master key providers](./src/master_key_provider/raw_rsa/private_key_only_from_pem.py)
5156
* How to encrypt with a raw RSA public key wrapping key without access to the private key
5257
* [with keyrings](./src/keyring/raw_rsa/public_private_key_separate.py)
5358
* Combining wrapping keys
5459
* How to combine AWS KMS with an offline escrow key
5560
* [with keyrings](./src/keyring/multi/aws_kms_with_escrow.py)
61+
* [with master key providers](./src/master_key_provider/multi/aws_kms_with_escrow.py)
5662

5763
### Keyrings
5864

examples/src/keyring/raw_aes/raw_aes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def run(source_plaintext):
4242
# Create the keyring that determines how your data keys are protected.
4343
keyring = RawAESKeyring(
4444
# The key namespace and key name are defined by you
45-
# and are used by the raw RSA keyring
45+
# and are used by the raw AES keyring
4646
# to determine whether it should attempt to decrypt
4747
# an encrypted data key.
4848
#
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Master key provider examples.
5+
6+
These examples show how to use master key providers.
7+
"""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
AWS KMS master key provider examples.
5+
6+
These examples show how to use the KMS master key provider.
7+
"""
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
This example is intended to serve as reference material for users migrating away from master key providers.
5+
We recommend using keyrings rather than master key providers.
6+
For examples using keyrings, see the ``examples/src/keyrings`` directory.
7+
8+
The KMS master key provider uses any key IDs that you specify on encrypt,
9+
but attempts to decrypt *any* data keys that were encrypted under a KMS CMK.
10+
This means that you do not need to know which CMKs were used to encrypt a message.
11+
12+
This example shows how to configure and use a KMS master key provider to decrypt without provider key IDs.
13+
14+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
15+
16+
For an example of how to use the KMS master key with a single CMK,
17+
see the ``master_key_provider/aws_kms/single_cmk`` example.
18+
19+
For an example of how to use the KMS master key provider with CMKs in multiple regions,
20+
see the ``master_key_provider/aws_kms/multiple_regions`` example.
21+
"""
22+
import aws_encryption_sdk
23+
from aws_encryption_sdk.key_providers.kms import KMSMasterKey, KMSMasterKeyProvider
24+
25+
26+
def run(aws_kms_cmk, source_plaintext):
27+
# type: (str, bytes) -> None
28+
"""Demonstrate configuring a KMS master key provider for decryption.
29+
30+
:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys
31+
:param bytes source_plaintext: Plaintext to encrypt
32+
"""
33+
# Prepare your encryption context.
34+
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
35+
encryption_context = {
36+
"encryption": "context",
37+
"is not": "secret",
38+
"but adds": "useful metadata",
39+
"that can help you": "be confident that",
40+
"the data you are handling": "is what you think it is",
41+
}
42+
43+
# Create the master key that determines how your data keys are protected.
44+
encrypt_master_key = KMSMasterKey(key_id=aws_kms_cmk)
45+
46+
# Create a KMS master key provider to use on decrypt.
47+
decrypt_master_key_provider = KMSMasterKeyProvider()
48+
49+
# Encrypt your plaintext data.
50+
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt(
51+
source=source_plaintext, encryption_context=encryption_context, key_provider=encrypt_master_key
52+
)
53+
54+
# Demonstrate that the ciphertext and plaintext are different.
55+
assert ciphertext != source_plaintext
56+
57+
# Decrypt your encrypted data using the KMS master key provider.
58+
#
59+
# You do not need to specify the encryption context on decrypt
60+
# because the header of the encrypted message includes the encryption context.
61+
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, key_provider=decrypt_master_key_provider)
62+
63+
# Demonstrate that the decrypted plaintext is identical to the original plaintext.
64+
assert decrypted == source_plaintext
65+
66+
# Verify that the encryption context used in the decrypt operation includes
67+
# the encryption context that you specified when encrypting.
68+
# The AWS Encryption SDK can add pairs, so don't require an exact match.
69+
#
70+
# In production, always use a meaningful encryption context.
71+
assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items())
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
This example is intended to serve as reference material for users migrating away from master key providers.
5+
We recommend using keyrings rather than master key providers.
6+
For examples using keyrings, see the ``examples/src/keyrings`` directory.
7+
8+
This example shows how to configure and use a KMS master key provider with with CMKs in multiple regions.
9+
10+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
11+
12+
For an example of how to use the KMS master key with a single CMK,
13+
see the ``master_key_provider/aws_kms/single_cmk`` example.
14+
15+
For an example of how to use the KMS master key provider in discovery mode on decrypt,
16+
see the ``master_key_provider/aws_kms/discovery_decrypt`` example.
17+
"""
18+
import aws_encryption_sdk
19+
from aws_encryption_sdk.key_providers.kms import KMSMasterKey, KMSMasterKeyProvider
20+
21+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
22+
from typing import Sequence # noqa pylint: disable=unused-import
23+
except ImportError: # pragma: no cover
24+
# We only actually need these imports when running the mypy checks
25+
pass
26+
27+
28+
def run(aws_kms_generator_cmk, aws_kms_additional_cmks, source_plaintext):
29+
# type: (str, Sequence[str], bytes) -> None
30+
"""Demonstrate an encrypt/decrypt cycle using a KMS master key provider with CMKs in multiple regions.
31+
32+
:param str aws_kms_generator_cmk: The ARN of the primary AWS KMS CMK
33+
:param List[str] aws_kms_additional_cmks: Additional ARNs of secondary KMS CMKs
34+
:param bytes source_plaintext: Plaintext to encrypt
35+
"""
36+
# Prepare your encryption context.
37+
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
38+
encryption_context = {
39+
"encryption": "context",
40+
"is not": "secret",
41+
"but adds": "useful metadata",
42+
"that can help you": "be confident that",
43+
"the data you are handling": "is what you think it is",
44+
}
45+
46+
# Create the master key provider that will encrypt your data keys under all requested CMKs.
47+
#
48+
# The KMS master key provider generates the data key using the first key ID in the list.
49+
key_ids = [aws_kms_generator_cmk]
50+
key_ids.extend(aws_kms_additional_cmks)
51+
master_key_provider = KMSMasterKeyProvider(key_ids=key_ids)
52+
53+
# Create master keys that each only use one of the CMKs.
54+
# We will use these later to demonstrate that any of the CMKs can be used to decrypt the message.
55+
single_cmk_master_key_that_generated = KMSMasterKey(key_id=aws_kms_generator_cmk)
56+
single_cmk_master_key_that_encrypted = KMSMasterKey(key_id=aws_kms_additional_cmks[0])
57+
58+
# Encrypt your plaintext data using the master key provider that uses all requests CMKs.
59+
ciphertext, encrypt_header = aws_encryption_sdk.encrypt(
60+
source=source_plaintext, encryption_context=encryption_context, key_provider=master_key_provider
61+
)
62+
63+
# Verify that the header contains the expected number of encrypted data keys (EDKs).
64+
# It should contain one EDK for each CMK.
65+
assert len(encrypt_header.encrypted_data_keys) == len(aws_kms_additional_cmks) + 1
66+
67+
# Demonstrate that the ciphertext and plaintext are different.
68+
assert ciphertext != source_plaintext
69+
70+
# Decrypt your encrypted data separately using the single-CMK master keys.
71+
#
72+
# You do not need to specify the encryption context on decrypt
73+
# because the header of the encrypted message includes the encryption context.
74+
decrypted_1, decrypt_header_1 = aws_encryption_sdk.decrypt(
75+
source=ciphertext, key_provider=single_cmk_master_key_that_generated
76+
)
77+
decrypted_2, decrypt_header_2 = aws_encryption_sdk.decrypt(
78+
source=ciphertext, key_provider=single_cmk_master_key_that_encrypted
79+
)
80+
81+
# Demonstrate that the decrypted plaintext is identical to the original plaintext.
82+
assert decrypted_1 == source_plaintext
83+
assert decrypted_2 == source_plaintext
84+
85+
# Verify that the encryption context used in the decrypt operation includes
86+
# the encryption context that you specified when encrypting.
87+
# The AWS Encryption SDK can add pairs, so don't require an exact match.
88+
#
89+
# In production, always use a meaningful encryption context.
90+
assert set(encryption_context.items()) <= set(decrypt_header_1.encryption_context.items())
91+
assert set(encryption_context.items()) <= set(decrypt_header_2.encryption_context.items())
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
This example is intended to serve as reference material for users migrating away from master key providers.
5+
We recommend using keyrings rather than master key providers.
6+
For examples using keyrings, see the ``examples/src/keyrings`` directory.
7+
8+
This example shows how to configure and use a KMS master key with a single KMS CMK.
9+
10+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
11+
12+
For an example of how to use the KMS master key provider with CMKs in multiple regions,
13+
see the ``master_key_provider/aws_kms/multiple_regions`` example.
14+
15+
For an example of how to use the KMS master key provider in discovery mode on decrypt,
16+
see the ``master_key_provider/aws_kms/discovery_decrypt`` example.
17+
"""
18+
import aws_encryption_sdk
19+
from aws_encryption_sdk.key_providers.kms import KMSMasterKey
20+
21+
22+
def run(aws_kms_cmk, source_plaintext):
23+
# type: (str, bytes) -> None
24+
"""Demonstrate an encrypt/decrypt cycle using a KMS master key with a single CMK.
25+
26+
:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys
27+
:param bytes source_plaintext: Plaintext to encrypt
28+
"""
29+
# Prepare your encryption context.
30+
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
31+
encryption_context = {
32+
"encryption": "context",
33+
"is not": "secret",
34+
"but adds": "useful metadata",
35+
"that can help you": "be confident that",
36+
"the data you are handling": "is what you think it is",
37+
}
38+
39+
# Create the master key that determines how your data keys are protected.
40+
master_key = KMSMasterKey(key_id=aws_kms_cmk)
41+
42+
# Encrypt your plaintext data.
43+
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt(
44+
source=source_plaintext, encryption_context=encryption_context, key_provider=master_key
45+
)
46+
47+
# Demonstrate that the ciphertext and plaintext are different.
48+
assert ciphertext != source_plaintext
49+
50+
# Decrypt your encrypted data using the same master key you used on encrypt.
51+
#
52+
# You do not need to specify the encryption context on decrypt
53+
# because the header of the encrypted message includes the encryption context.
54+
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, key_provider=master_key)
55+
56+
# Demonstrate that the decrypted plaintext is identical to the original plaintext.
57+
assert decrypted == source_plaintext
58+
59+
# Verify that the encryption context used in the decrypt operation includes
60+
# the encryption context that you specified when encrypting.
61+
# The AWS Encryption SDK can add pairs, so don't require an exact match.
62+
#
63+
# In production, always use a meaningful encryption context.
64+
assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items())
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Multi-master key provider examples.
5+
6+
These examples show how to combine master key providers.
7+
"""

0 commit comments

Comments
 (0)