Skip to content

Commit 9297b8b

Browse files
committed
added kms mrk and mrk multi keyrings
1 parent 05abfa9 commit 9297b8b

File tree

4 files changed

+209
-16
lines changed

4 files changed

+209
-16
lines changed

examples/src/keyrings/aws_kms_mrk_keyring_example.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,28 @@
3838
EXAMPLE_DATA: bytes = b"Hello World"
3939

4040

41-
def get_aws_region_from_kms_key_id(kms_key_id: str) -> str:
42-
"""
43-
Get the AWS Region from the KMS Key ID.
44-
Usage: get_aws_region_from_kms_key_id(kms_key_id)
45-
:param kms_key_id: KMS Key identifier for the KMS key you want to use
46-
:type kms_key_id: string
47-
:return: AWS Region
48-
:rtype: string
49-
"""
50-
return kms_key_id.split(":")[3]
51-
52-
5341
def encrypt_and_decrypt_with_keyring(
5442
encrypt_kms_key_id: str,
5543
decrypt_kms_key_id: str,
44+
encrypt_region: str,
45+
decrypt_region: str
5646
):
5747
"""Demonstrate an encrypt/decrypt cycle using an AWS KMS keyring.
5848
59-
Usage: encrypt_and_decrypt_with_keyring(encrypt_kms_key_id, decrypt_kms_key_id)
49+
Usage: encrypt_and_decrypt_with_keyring(encrypt_kms_key_id,
50+
decrypt_kms_key_id,
51+
encrypt_region,
52+
decrypt_region)
6053
:param encrypt_kms_key_id: KMS Key identifier for the KMS key you want to use
6154
for encryption of your data keys.
6255
:type encrypt_kms_key_id: string
6356
:param decrypt_kms_key_id: KMS Key identifier for the KMS key you want to use
6457
for decryption of your data keys.
6558
:type decrypt_kms_key_id: string
59+
:param encrypt_region: AWS Region for encryption of your data keys
60+
:type encrypt_region: string
61+
:param decrypt_region: AWS Region for decryption of your data keys
62+
:type decrypt_region: string
6663
6764
For more information on KMS Key identifiers, see
6865
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
@@ -96,7 +93,6 @@ def encrypt_and_decrypt_with_keyring(
9693
)
9794

9895
# Create a boto3 client for KMS in the first region.
99-
encrypt_region: str = get_aws_region_from_kms_key_id(encrypt_kms_key_id)
10096
encrypt_kms_client = boto3.client('kms', region_name=encrypt_region)
10197

10298
encrypt_keyring_input: CreateAwsKmsMrkKeyringInput = CreateAwsKmsMrkKeyringInput(
@@ -126,7 +122,6 @@ def encrypt_and_decrypt_with_keyring(
126122
# https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html
127123

128124
# Create a boto3 client for KMS in the second region.
129-
decrypt_region: str = get_aws_region_from_kms_key_id(decrypt_kms_key_id)
130125
decrypt_kms_client = boto3.client('kms', region_name=decrypt_region)
131126

132127
decrypt_keyring_input: CreateAwsKmsMrkKeyringInput = CreateAwsKmsMrkKeyringInput(
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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 KMS MRK Multi Keyring
5+
6+
KMS MRK keyring interacts with AWS Key Management Service (AWS KMS) to create, encrypt,
7+
and decrypt data keys using AWS KMS defined Customer Master Keys (CMKs).
8+
This example creates a KMS MRK Keyring and then encrypts a custom input EXAMPLE_DATA
9+
with an encryption context. This example also includes some sanity checks for demonstration:
10+
1. Ciphertext and plaintext data are not the same
11+
2. Encryption context is correct in the decrypted message header
12+
3. Decrypted plaintext value matches EXAMPLE_DATA
13+
4. Ciphertext can be decrypted using an AwsKmsMrkKeyring containing a replica of the
14+
MRK key (from the multi-keyring used for encryption) copied from the first region into
15+
the second region
16+
These sanity checks are for demonstration in the example only. You do not need these in your code.
17+
18+
For more information on how to use KMS keyrings, see
19+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html
20+
"""
21+
import sys
22+
23+
import boto3
24+
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders
25+
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig
26+
from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsMrkKeyringInput, CreateAwsKmsMrkMultiKeyringInput
27+
from aws_cryptographic_materialproviders.mpl.references import IKeyring
28+
from typing import Dict
29+
30+
import aws_encryption_sdk
31+
from aws_encryption_sdk import CommitmentPolicy
32+
33+
# TODO-MPL: Remove this as part of removing PYTHONPATH hacks.
34+
MODULE_ROOT_DIR = '/'.join(__file__.split("/")[:-1])
35+
36+
sys.path.append(MODULE_ROOT_DIR)
37+
38+
EXAMPLE_DATA: bytes = b"Hello World"
39+
40+
41+
def encrypt_and_decrypt_with_keyring(
42+
mrk_key_id: str,
43+
kms_key_id: str,
44+
mrk_replica_key_id: str,
45+
second_region: str
46+
):
47+
"""Demonstrate an encrypt/decrypt cycle using a Multi-Keyring made
48+
up of multiple AWS KMS MRK Keyrings
49+
50+
Usage: encrypt_and_decrypt_with_keyring(mrk_key_id,
51+
kms_key_id,
52+
mrk_replica_key_id,
53+
second_region)
54+
:param mrk_key_id: KMS Key identifier for an AWS KMS multi-Region key (MRK) located in your
55+
default region
56+
:type mrk_key_id: string
57+
:param kms_key_id: KMS Key identifier for a KMS key, possibly located in a different region
58+
than the MRK key
59+
:type kms_key_id: string
60+
:param mrk_replica_key_id: KMS Key identifier for an MRK that is a replica of the
61+
`mrk_key_id` in a second region.
62+
:type mrk_replica_key_id: string
63+
:param second_region: The second region where the MRK replica is located
64+
:type second_region: string
65+
66+
For more information on KMS Key identifiers, see
67+
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
68+
"""
69+
# 1. Instantiate the encryption SDK client.
70+
# This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
71+
# which enforces that this client only encrypts using committing algorithm suites and enforces
72+
# that this client will only decrypt encrypted messages that were created with a committing
73+
# algorithm suite.
74+
# This is the default commitment policy if you were to build the client as
75+
# `client = aws_encryption_sdk.EncryptionSDKClient()`.
76+
client = aws_encryption_sdk.EncryptionSDKClient(
77+
commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
78+
)
79+
80+
# 2. Create encryption context.
81+
# Remember that your encryption context is NOT SECRET.
82+
# For more information, see
83+
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
84+
encryption_context: Dict[str, str] = {
85+
"encryption": "context",
86+
"is not": "secret",
87+
"but adds": "useful metadata",
88+
"that can help you": "be confident that",
89+
"the data you are handling": "is what you think it is",
90+
}
91+
92+
# 3. Create an AwsKmsMrkMultiKeyring that protects your data under two different KMS Keys.
93+
# The Keys can either be regular KMS keys or MRKs.
94+
# Either KMS Key individually is capable of decrypting data encrypted under this keyring.
95+
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
96+
config=MaterialProvidersConfig()
97+
)
98+
99+
kms_mrk_multi_keyring_input: CreateAwsKmsMrkMultiKeyringInput =\
100+
CreateAwsKmsMrkMultiKeyringInput(
101+
generator=mrk_key_id,
102+
kms_key_ids=[kms_key_id]
103+
)
104+
105+
kms_mrk_multi_keyring: IKeyring = mat_prov.create_aws_kms_mrk_multi_keyring(
106+
input=kms_mrk_multi_keyring_input
107+
)
108+
109+
# 4. Encrypt the data with the encryptionContext using the kms_mrk_multi_keyring.
110+
ciphertext, _ = client.encrypt(
111+
source=EXAMPLE_DATA,
112+
keyring=kms_mrk_multi_keyring,
113+
encryption_context=encryption_context
114+
)
115+
116+
# 5. Demonstrate that the ciphertext and plaintext are different.
117+
# (This is an example for demonstration; you do not need to do this in your own code.)
118+
assert ciphertext != EXAMPLE_DATA, \
119+
"Ciphertext and plaintext data are the same. Invalid encryption"
120+
121+
# 6. Decrypt your encrypted data using the same AwsKmsMrkMultiKeyring you used on encrypt.
122+
# It will decrypt the data using the generator KMS key since that is the first available
123+
# KMS key on the keyring that is capable of decrypting the data.
124+
plaintext_bytes, dec_header = client.decrypt(
125+
source=ciphertext,
126+
keyring=kms_mrk_multi_keyring
127+
)
128+
129+
# 7. Demonstrate that the encryption context is correct in the decrypted message header
130+
# (This is an example for demonstration; you do not need to do this in your own code.)
131+
for k, v in encryption_context.items():
132+
assert v == dec_header.encryption_context[k], \
133+
"Encryption context does not match expected values"
134+
135+
# 8. Demonstrate that the decrypted plaintext is identical to the original plaintext.
136+
# (This is an example for demonstration; you do not need to do this in your own code.)
137+
assert plaintext_bytes == EXAMPLE_DATA
138+
139+
# Demonstrate that a single AwsKmsMrkKeyring configured with a replica of the MRK from the
140+
# multi-keyring used to encrypt the data is also capable of decrypting the data.
141+
# Not shown in this example: A KMS Keyring created with `kmsKeyArn` could also
142+
# decrypt this message.
143+
# (This is an example for demonstration; you do not need to do this in your own code.)
144+
145+
# 9. Create a single AwsKmsMrkKeyring with the replica KMS MRK from the second region.
146+
147+
# Create a boto3 client for KMS in the second region.
148+
second_region_kms_client = boto3.client('kms', region_name=second_region)
149+
150+
second_region_mrk_keyring_input: CreateAwsKmsMrkKeyringInput = CreateAwsKmsMrkKeyringInput(
151+
kms_key_id=mrk_replica_key_id,
152+
kms_client=second_region_kms_client
153+
)
154+
155+
second_region_mrk_keyring: IKeyring = mat_prov.create_aws_kms_mrk_keyring(
156+
input=second_region_mrk_keyring_input
157+
)
158+
159+
# 10. Decrypt your encrypted data using the second region AwsKmsMrkKeyring
160+
plaintext_bytes_second_region, dec_header_second_region = client.decrypt(
161+
source=ciphertext,
162+
keyring=second_region_mrk_keyring
163+
)
164+
165+
# 11. Demonstrate that the encryption context is correct in the decrypted message header
166+
# (This is an example for demonstration; you do not need to do this in your own code.)
167+
for k, v in encryption_context.items():
168+
assert v == dec_header_second_region.encryption_context[k], \
169+
"Encryption context does not match expected values"
170+
171+
# 12. Demonstrate that the decrypted plaintext is identical to the original plaintext.
172+
# (This is an example for demonstration; you do not need to do this in your own code.)
173+
assert plaintext_bytes_second_region == EXAMPLE_DATA

examples/test/keyrings/test_i_aws_kms_mrk_keyring_example.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ def test_encrypt_and_decrypt_with_keyring():
1414
"arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7"
1515
decrypt_kms_key_id = \
1616
"arn:aws:kms:eu-west-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7"
17-
encrypt_and_decrypt_with_keyring(encrypt_kms_key_id, decrypt_kms_key_id)
17+
encrypt_region = "us-east-1"
18+
decrypt_region = "eu-west-1"
19+
encrypt_and_decrypt_with_keyring(encrypt_kms_key_id,
20+
decrypt_kms_key_id,
21+
encrypt_region,
22+
decrypt_region)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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 MRK Multi keyring example."""
4+
import pytest
5+
6+
from ...src.keyrings.aws_kms_mrk_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 MRK Multi Keyring example."""
13+
mrk_key_id = \
14+
"arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7"
15+
kms_key_id = \
16+
"arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f"
17+
mrk_replica_key_id = \
18+
"arn:aws:kms:eu-west-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7"
19+
second_region = "eu-west-1"
20+
encrypt_and_decrypt_with_keyring(mrk_key_id, kms_key_id, mrk_replica_key_id, second_region)

0 commit comments

Comments
 (0)