Skip to content

Commit 41f901b

Browse files
committed
chore: updated multi, discovery and discovery multi keyrings
1 parent 5bf8d2b commit 41f901b

File tree

4 files changed

+198
-10
lines changed

4 files changed

+198
-10
lines changed

examples/src/keyrings/aws_kms_discovery_keyring_example.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,19 @@
3131
which the KMS key used for encryption belongs
3232
These sanity checks are for demonstration in the example only. You do not need these in your code.
3333
34-
For more information on how to use KMS keyrings, see
34+
For more information on how to use KMS Discovery keyrings, see
3535
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html#kms-keyring-discovery
3636
"""
3737
import sys
3838

3939
import boto3
4040
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
4141
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
42-
from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsKeyringInput, CreateAwsKmsDiscoveryKeyringInput, DiscoveryFilter
42+
from aws_cryptographic_materialproviders.mpl.models import (
43+
CreateAwsKmsDiscoveryKeyringInput,
44+
CreateAwsKmsKeyringInput,
45+
DiscoveryFilter,
46+
)
4347
from aws_cryptographic_materialproviders.mpl.references import IKeyring
4448
from typing import Dict
4549

@@ -125,7 +129,6 @@ def encrypt_and_decrypt_with_keyring(
125129
# 7. Now create a Discovery keyring to use for decryption. We'll add a discovery filter
126130
# so that we limit the set of ciphertexts we are willing to decrypt to only ones
127131
# created by KMS keys in our account and partition.
128-
129132
discovery_keyring_input: CreateAwsKmsDiscoveryKeyringInput = CreateAwsKmsDiscoveryKeyringInput(
130133
kms_client=kms_client,
131134
discovery_filter=DiscoveryFilter(
@@ -151,7 +154,6 @@ def encrypt_and_decrypt_with_keyring(
151154
# successfully decrypted. The resulting data key is used to decrypt the
152155
# ciphertext's message.
153156
# If all calls to KMS fail, the decryption fails.
154-
155157
plaintext_bytes, dec_header = client.decrypt(
156158
source=ciphertext,
157159
keyring=discovery_keyring
@@ -167,13 +169,15 @@ def encrypt_and_decrypt_with_keyring(
167169
# (This is an example for demonstration; you do not need to do this in your own code.)
168170
assert plaintext_bytes == EXAMPLE_DATA
169171

170-
# 11. Demonstrate that if the Discovery keyring (Bob's) doesn't have the correct account id's,
172+
# 11. Demonstrate that if a discovery keyring (Bob's) doesn't have the correct AWS Account ID's,
171173
# the decrypt will fail with an error message
174+
# Note that the Account ID '888888888888' used here is different than the one used
175+
# during encryption '658956600833'
172176
discovery_keyring_input_bob: CreateAwsKmsDiscoveryKeyringInput = \
173177
CreateAwsKmsDiscoveryKeyringInput(
174178
kms_client=kms_client,
175179
discovery_filter=DiscoveryFilter(
176-
account_ids=["658956600834"],
180+
account_ids=["888888888888"],
177181
partition="aws"
178182
)
179183
)
@@ -183,7 +187,8 @@ def encrypt_and_decrypt_with_keyring(
183187
)
184188

185189
# Decrypt the ciphertext using Bob's discovery keyring which doesn't contain the required
186-
# Account ID's for the KMS keyring used for encryption
190+
# Account ID's for the KMS keyring used for encryption.
191+
# This should throw an AWSEncryptionSDKClientError exception
187192
try:
188193
plaintext_bytes, _ = client.decrypt(
189194
source=ciphertext,
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
This example sets up the AWS KMS Discovery Multi Keyring and demonstrates decryption
5+
using a Multi-Keyring containing multiple AWS KMS Discovery Keyrings.
6+
7+
The AWS Encryption SDK provides a standard AWS KMS discovery keyring and a discovery keyring
8+
for AWS KMS multi-Region keys. For information about using multi-Region keys with the
9+
AWS Encryption SDK, see
10+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/configure.html#config-mrks
11+
12+
Because it doesn't specify any wrapping keys, a discovery keyring can't encrypt data.
13+
If you use a discovery keyring to encrypt data, alone or in a multi-keyring, the encrypt
14+
operation fails. The exception is the AWS Encryption SDK for C, where the encrypt operation
15+
ignores a standard discovery keyring, but fails if you specify a multi-Region discovery
16+
keyring, alone or in a multi-keyring.
17+
18+
When decrypting, a discovery keyring allows the AWS Encryption SDK to ask AWS KMS to decrypt
19+
any encrypted data key by using the AWS KMS key that encrypted it, regardless of who owns or
20+
has access to that AWS KMS key. The call succeeds only when the caller has kms:Decrypt
21+
permission on the AWS KMS key.
22+
23+
This example creates a KMS Keyring and then encrypts a custom input EXAMPLE_DATA
24+
with an encryption context. This encrypted ciphertext is then decrypted using the Discovery Multi
25+
keyring. This example also includes some sanity checks for demonstration:
26+
1. Ciphertext and plaintext data are not the same
27+
2. Encryption context is correct in the decrypted message header
28+
3. Decrypted plaintext value matches EXAMPLE_DATA
29+
These sanity checks are for demonstration in the example only. You do not need these in your code.
30+
31+
For more information on how to use KMS Discovery keyrings, see
32+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html#kms-keyring-discovery
33+
"""
34+
import sys
35+
36+
import boto3
37+
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
38+
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
39+
from aws_cryptographic_materialproviders.mpl.models import (
40+
CreateAwsKmsDiscoveryMultiKeyringInput,
41+
CreateAwsKmsKeyringInput,
42+
DiscoveryFilter,
43+
)
44+
from aws_cryptographic_materialproviders.mpl.references import IKeyring
45+
from typing import Dict
46+
47+
import aws_encryption_sdk
48+
from aws_encryption_sdk import CommitmentPolicy
49+
50+
# TODO-MPL: Remove this as part of removing PYTHONPATH hacks.
51+
MODULE_ROOT_DIR = '/'.join(__file__.split("/")[:-1])
52+
53+
sys.path.append(MODULE_ROOT_DIR)
54+
55+
EXAMPLE_DATA: bytes = b"Hello World"
56+
57+
58+
def encrypt_and_decrypt_with_keyring(
59+
kms_key_id: str
60+
):
61+
"""Demonstrate an encrypt/decrypt cycle using an AWS KMS Discovery Multi Keyring.
62+
63+
Usage: encrypt_and_decrypt_with_keyring(kms_key_id)
64+
:param kms_key_id: KMS Key identifier for the KMS key you want to use for creating
65+
the kms_keyring used for encryption
66+
:type kms_key_id: string
67+
68+
For more information on KMS Key identifiers, see
69+
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
70+
"""
71+
# 1. Instantiate the encryption SDK client.
72+
# This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
73+
# which enforces that this client only encrypts using committing algorithm suites and enforces
74+
# that this client will only decrypt encrypted messages that were created with a committing
75+
# algorithm suite.
76+
# This is the default commitment policy if you were to build the client as
77+
# `client = aws_encryption_sdk.EncryptionSDKClient()`.
78+
client = aws_encryption_sdk.EncryptionSDKClient(
79+
commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
80+
)
81+
82+
# 2. Create a boto3 client for KMS.
83+
kms_client = boto3.client('kms', region_name="us-west-2")
84+
85+
# 3. Create encryption context.
86+
# Remember that your encryption context is NOT SECRET.
87+
# For more information, see
88+
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
89+
encryption_context: Dict[str, str] = {
90+
"encryption": "context",
91+
"is not": "secret",
92+
"but adds": "useful metadata",
93+
"that can help you": "be confident that",
94+
"the data you are handling": "is what you think it is",
95+
}
96+
97+
# 4. Create the keyring that determines how your data keys are protected.
98+
# Although this example highlights Discovery keyrings, Discovery keyrings cannot
99+
# be used to encrypt, so for encryption we create a KMS keyring without discovery mode.
100+
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
101+
config=MaterialProvidersConfig()
102+
)
103+
104+
kms_keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput(
105+
kms_key_id=kms_key_id,
106+
kms_client=kms_client
107+
)
108+
109+
encrypt_kms_keyring: IKeyring = mat_prov.create_aws_kms_keyring(
110+
input=kms_keyring_input
111+
)
112+
113+
# 5. Encrypt the data for the encryptionContext
114+
ciphertext, _ = client.encrypt(
115+
source=EXAMPLE_DATA,
116+
keyring=encrypt_kms_keyring,
117+
encryption_context=encryption_context
118+
)
119+
120+
# 6. Demonstrate that the ciphertext and plaintext are different.
121+
# (This is an example for demonstration; you do not need to do this in your own code.)
122+
assert ciphertext != EXAMPLE_DATA, \
123+
"Ciphertext and plaintext data are the same. Invalid encryption"
124+
125+
# 7. Now create a Discovery Multi keyring to use for decryption. We'll add a discovery filter
126+
# so that we limit the set of ciphertexts we are willing to decrypt to only ones
127+
# created by KMS keys in our account and partition.
128+
discovery_multi_keyring_input: CreateAwsKmsDiscoveryMultiKeyringInput = \
129+
CreateAwsKmsDiscoveryMultiKeyringInput(
130+
regions=["us-west-2", "us-east-1"],
131+
discovery_filter=DiscoveryFilter(
132+
account_ids=["658956600833"],
133+
partition="aws"
134+
)
135+
)
136+
137+
# This is a Multi Keyring composed of Discovery Keyrings.
138+
# There is a keyring for every region in `regions`.
139+
# All the keyrings have the same Discovery Filter.
140+
# Each keyring has its own KMS Client, which is created for the keyring's region.
141+
discovery_multi_keyring: IKeyring = mat_prov.create_aws_kms_discovery_multi_keyring(
142+
input=discovery_multi_keyring_input
143+
)
144+
145+
# 8. On Decrypt, the header of the encrypted message (ciphertext) will be parsed.
146+
# The header contains the Encrypted Data Keys (EDKs), which, if the EDK
147+
# was encrypted by a KMS Keyring, includes the KMS Key ARN.
148+
# For each member of the Multi Keyring, every EDK will try to be decrypted until a decryption
149+
# is successful.
150+
# Since every member of the Multi Keyring is a Discovery Keyring:
151+
# Each Keyring will filter the EDKs by the Discovery Filter
152+
# For the filtered EDKs, the keyring will try to decrypt it with the keyring's client.
153+
# All of this is done serially, until a success occurs or all keyrings have
154+
# failed all (filtered) EDKs.
155+
# KMS Discovery Keyrings will attempt to decrypt Multi Region Keys (MRKs) and regular KMS Keys.
156+
plaintext_bytes, dec_header = client.decrypt(
157+
source=ciphertext,
158+
keyring=discovery_multi_keyring
159+
)
160+
161+
# 9. Demonstrate that the encryption context is correct in the decrypted message header
162+
# (This is an example for demonstration; you do not need to do this in your own code.)
163+
for k, v in encryption_context.items():
164+
assert v == dec_header.encryption_context[k], \
165+
"Encryption context does not match expected values"
166+
167+
# 10. Demonstrate that the decrypted plaintext is identical to the original plaintext.
168+
# (This is an example for demonstration; you do not need to do this in your own code.)
169+
assert plaintext_bytes == EXAMPLE_DATA

examples/src/keyrings/multi_keyring_example.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
This example creates a multi_keyring using a KMS keyring as generator keyring and a raw AES keyring
3434
as a child keyring. You can use different combinations of keyrings in the multi_keyring.
3535
36-
For more information on how to use KMS keyrings, see
36+
For more information on how to use Multi keyrings, see
3737
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-multi-keyring.html
3838
"""
3939
import secrets
@@ -67,11 +67,11 @@ def encrypt_and_decrypt_with_keyring(
6767
):
6868
"""Demonstrate an encrypt/decrypt cycle using a Multi keyring.
6969
The multi_keyring is created using a KMS keyring as generator keyring and a raw AES keyring
70-
as a child keyring. Therefore we take a kms_key_id as input
70+
as a child keyring. Therefore, we take a kms_key_id as input
7171
7272
Usage: encrypt_and_decrypt_with_keyring(kms_key_id)
7373
:param kms_key_id: KMS Key identifier for the KMS key you want to use for encryption and
74-
decryption of your data keys in the kms_keyring that is in-turn used in the multi_keyring
74+
decryption of your data keys in the kms_keyring, that is in-turn used in the multi_keyring
7575
:type kms_key_id: string
7676
7777
For more information on KMS Key identifiers, see
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""Test suite for the AWS KMS Discovery Multi keyring example."""
4+
import pytest
5+
6+
from ...src.keyrings.aws_kms_discovery_multi_keyring_example import encrypt_and_decrypt_with_keyring
7+
8+
pytestmark = [pytest.mark.examples]
9+
10+
11+
def test_encrypt_and_decrypt_with_keyring():
12+
"""Test function for encrypt and decrypt using the AWS KMS Discovery Multi Keyring example."""
13+
kms_key_id = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f"
14+
encrypt_and_decrypt_with_keyring(kms_key_id)

0 commit comments

Comments
 (0)