main/keyring/
aws_kms_mrk_multi_keyring_example.rs

1// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4/*
5This example sets up the AWS KMS MRK Multi Keyring
6
7The AWS Key Management Service (AWS KMS) MRK keyring interacts with AWS KMS to
8create, encrypt, and decrypt data keys with AWS KMS MRK keys.
9The KMS MRK multi-keyring consists of one or more individual keyrings of the
10same or different type. The keys can either be regular KMS keys or MRKs.
11The effect is like using several keyrings in a series.
12
13This example creates a AwsKmsMrkMultiKeyring using an mrk_key_id (generator) and a kms_key_id
14as a child key, and then encrypts a custom input EXAMPLE_DATA with an encryption context.
15Either KMS Key individually is capable of decrypting data encrypted under this keyring.
16This example also includes some sanity checks for demonstration:
171. Ciphertext and plaintext data are not the same
182. Decrypted plaintext value matches EXAMPLE_DATA
193. Ciphertext can be decrypted using an AwsKmsMrkKeyring containing a replica of the
20   MRK (from the multi-keyring used for encryption) copied from the first region into
21   the second region
22These sanity checks are for demonstration in the example only. You do not need these in your code.
23
24For more information on how to use KMS keyrings, see
25https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html
26
27For more info on KMS MRK (multi-region keys), see the KMS documentation:
28https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html
29
30For more information on KMS Key identifiers, see
31https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
32*/
33
34use aws_config::Region;
35use aws_esdk::client as esdk_client;
36use aws_esdk::material_providers::client as mpl_client;
37use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
38use aws_esdk::types::aws_encryption_sdk_config::AwsEncryptionSdkConfig;
39use std::collections::HashMap;
40
41pub async fn encrypt_and_decrypt_with_keyring(
42    example_data: &str,
43    mrk_key_id: &str,
44    kms_key_id: &str,
45    mrk_replica_key_id: &str,
46    mrk_replica_decrypt_region: String,
47) -> Result<(), crate::BoxError> {
48    // 1. Instantiate the encryption SDK client.
49    // This builds the default client with the RequireEncryptRequireDecrypt commitment policy,
50    // which enforces that this client only encrypts using committing algorithm suites and enforces
51    // that this client will only decrypt encrypted messages that were created with a committing
52    // algorithm suite.
53    let esdk_config = AwsEncryptionSdkConfig::builder().build()?;
54    let esdk_client = esdk_client::Client::from_conf(esdk_config)?;
55
56    // 2. Create encryption context.
57    // Remember that your encryption context is NOT SECRET.
58    // For more information, see
59    // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
60    let encryption_context = HashMap::from([
61        ("encryption".to_string(), "context".to_string()),
62        ("is not".to_string(), "secret".to_string()),
63        ("but adds".to_string(), "useful metadata".to_string()),
64        (
65            "that can help you".to_string(),
66            "be confident that".to_string(),
67        ),
68        (
69            "the data you are handling".to_string(),
70            "is what you think it is".to_string(),
71        ),
72    ]);
73
74    // 3. Create an AwsKmsMrkMultiKeyring that protects your data under two different KMS Keys.
75    // The Keys can either be regular KMS keys or MRKs.
76    // Either KMS Key individually is capable of decrypting data encrypted under this keyring.
77    let mpl_config = MaterialProvidersConfig::builder().build()?;
78    let mpl = mpl_client::Client::from_conf(mpl_config)?;
79
80    let kms_mrk_multi_keyring = mpl
81        .create_aws_kms_mrk_multi_keyring()
82        .generator(mrk_key_id)
83        .kms_key_ids(vec![kms_key_id.to_string()])
84        .send()
85        .await?;
86
87    // 4. Encrypt the data with the encryption_context using the kms_mrk_multi_keyring.
88    let plaintext = example_data.as_bytes();
89
90    let encryption_response = esdk_client
91        .encrypt()
92        .plaintext(plaintext)
93        .keyring(kms_mrk_multi_keyring.clone())
94        .encryption_context(encryption_context.clone())
95        .send()
96        .await?;
97
98    let ciphertext = encryption_response
99        .ciphertext
100        .expect("Unable to unwrap ciphertext from encryption response");
101
102    // 5. Demonstrate that the ciphertext and plaintext are different.
103    // (This is an example for demonstration; you do not need to do this in your own code.)
104    assert_ne!(
105        ciphertext,
106        aws_smithy_types::Blob::new(plaintext),
107        "Ciphertext and plaintext data are the same. Invalid encryption"
108    );
109
110    // 6. Decrypt your encrypted data using the same AwsKmsMrkMultiKeyring you used on encrypt.
111    // It will decrypt the data using the generator key (in this case, the MRK), since that is
112    // the first available KMS key on the keyring that is capable of decrypting the data.
113    let decryption_response = esdk_client
114        .decrypt()
115        .ciphertext(ciphertext.clone())
116        .keyring(kms_mrk_multi_keyring)
117        // Provide the encryption context that was supplied to the encrypt method
118        .encryption_context(encryption_context.clone())
119        .send()
120        .await?;
121
122    let decrypted_plaintext = decryption_response
123        .plaintext
124        .expect("Unable to unwrap plaintext from decryption response");
125
126    // 7. Demonstrate that the decrypted plaintext is identical to the original plaintext.
127    // (This is an example for demonstration; you do not need to do this in your own code.)
128    assert_eq!(
129        decrypted_plaintext,
130        aws_smithy_types::Blob::new(plaintext),
131        "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
132    );
133
134    // Demonstrate that a single AwsKmsMrkKeyring configured with a replica of the MRK from the
135    // multi-keyring used to encrypt the data is also capable of decrypting the data.
136    // (This is an example for demonstration; you do not need to do this in your own code.)
137
138    // 8. Create a single AwsKmsMrkKeyring with the replica KMS MRK from the second region.
139
140    // Create a client for KMS in the second region which is the region for mrk_replica_key_id.
141    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
142    let second_region_kms_config = aws_sdk_kms::config::Builder::from(&sdk_config)
143        .region(Region::new(mrk_replica_decrypt_region))
144        .build();
145    let second_region_kms_client = aws_sdk_kms::Client::from_conf(second_region_kms_config);
146
147    let second_region_mrk_keyring = mpl
148        .create_aws_kms_mrk_keyring()
149        .kms_key_id(mrk_replica_key_id)
150        .kms_client(second_region_kms_client)
151        .send()
152        .await?;
153
154    // 9. Decrypt your encrypted data using the second region AwsKmsMrkKeyring
155    let second_region_decryption_response = esdk_client
156        .decrypt()
157        .ciphertext(ciphertext)
158        .keyring(second_region_mrk_keyring)
159        // Provide the encryption context that was supplied to the encrypt method
160        .encryption_context(encryption_context)
161        .send()
162        .await?;
163
164    let second_region_decrypted_plaintext = second_region_decryption_response
165        .plaintext
166        .expect("Unable to unwrap plaintext from decryption response");
167
168    // 10. Demonstrate that the decrypted plaintext is identical to the original plaintext.
169    // (This is an example for demonstration; you do not need to do this in your own code.)
170    assert_eq!(
171        second_region_decrypted_plaintext,
172        aws_smithy_types::Blob::new(plaintext),
173        "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
174    );
175
176    // Not shown in this example: A KMS Keyring created with `kms_key_id` could also
177    // decrypt this message.
178
179    println!("KMS MRK Multi Keyring Example Completed Successfully");
180
181    Ok(())
182}
183
184#[tokio::test(flavor = "multi_thread")]
185pub async fn test_encrypt_and_decrypt_with_keyring() -> Result<(), crate::BoxError2> {
186    // Test function for encrypt and decrypt using the AWS KMS MRK Multi Keyring example
187    use crate::example_utils::utils;
188
189    let mrk_replica_decrypt_region: String = "eu-west-1".to_string();
190
191    encrypt_and_decrypt_with_keyring(
192        utils::TEST_EXAMPLE_DATA,
193        utils::TEST_MRK_KEY_ID_US_EAST_1,
194        utils::TEST_DEFAULT_KMS_KEY_ID,
195        utils::TEST_MRK_KEY_ID_EU_WEST_1,
196        mrk_replica_decrypt_region,
197    )
198    .await?;
199
200    Ok(())
201}