main/keyring/
aws_kms_mrk_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-region key) Keyring
6
7The AWS Key Management Service (AWS KMS) MRK keyring interacts with AWS KMS to
8create, encrypt, and decrypt data keys with multi-region AWS KMS keys (MRKs).
9This example creates a KMS MRK Keyring and then encrypts a custom input EXAMPLE_DATA
10with an encryption context. This example also includes some sanity checks for demonstration:
111. Ciphertext and plaintext data are not the same
122. Decrypted plaintext value matches EXAMPLE_DATA
13These sanity checks are for demonstration in the example only. You do not need these in your code.
14
15AWS KMS MRK keyrings can be used independently or in a multi-keyring with other keyrings
16of the same or a different type.
17
18For more information on how to use KMS keyrings, see
19https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html
20
21For more info on KMS MRK (multi-region keys), see the KMS documentation:
22https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html
23
24For more information on KMS Key identifiers, see
25https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id
26*/
27
28use aws_config::Region;
29use aws_esdk::client as esdk_client;
30use aws_esdk::material_providers::client as mpl_client;
31use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
32use aws_esdk::types::aws_encryption_sdk_config::AwsEncryptionSdkConfig;
33use std::collections::HashMap;
34
35pub async fn encrypt_and_decrypt_with_keyring(
36    example_data: &str,
37    mrk_key_id_encrypt: &str,
38    mrk_replica_key_id_decrypt: &str,
39    mrk_encrypt_region: String,
40    mrk_replica_decrypt_region: String,
41) -> Result<(), crate::BoxError> {
42    // 1. Instantiate the encryption SDK client.
43    // This builds the default client with the RequireEncryptRequireDecrypt commitment policy,
44    // which enforces that this client only encrypts using committing algorithm suites and enforces
45    // that this client will only decrypt encrypted messages that were created with a committing
46    // algorithm suite.
47    let esdk_config = AwsEncryptionSdkConfig::builder().build()?;
48    let esdk_client = esdk_client::Client::from_conf(esdk_config)?;
49
50    // 2. Create encryption context.
51    // Remember that your encryption context is NOT SECRET.
52    // For more information, see
53    // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
54    let encryption_context = HashMap::from([
55        ("encryption".to_string(), "context".to_string()),
56        ("is not".to_string(), "secret".to_string()),
57        ("but adds".to_string(), "useful metadata".to_string()),
58        (
59            "that can help you".to_string(),
60            "be confident that".to_string(),
61        ),
62        (
63            "the data you are handling".to_string(),
64            "is what you think it is".to_string(),
65        ),
66    ]);
67
68    // 3. Create a keyring that will encrypt your data, using a KMS MRK in the first region.
69    let mpl_config = MaterialProvidersConfig::builder().build()?;
70    let mpl = mpl_client::Client::from_conf(mpl_config)?;
71
72    // Create a KMS client in the first region
73    let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
74    let encrypt_kms_config = aws_sdk_kms::config::Builder::from(&sdk_config)
75        .region(Region::new(mrk_encrypt_region))
76        .build();
77    let encrypt_kms_client = aws_sdk_kms::Client::from_conf(encrypt_kms_config);
78
79    // Create the keyring that determines how your data keys are protected.
80    let encrypt_kms_keyring = mpl
81        .create_aws_kms_mrk_keyring()
82        .kms_key_id(mrk_key_id_encrypt)
83        .kms_client(encrypt_kms_client)
84        .send()
85        .await?;
86
87    // 4. Encrypt the data with the encryption_context using the encrypt_keyring.
88    let plaintext = example_data.as_bytes();
89
90    let encryption_response = esdk_client
91        .encrypt()
92        .plaintext(plaintext)
93        .keyring(encrypt_kms_keyring)
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. Create a keyring that will decrypt your data, using the same KMS MRK replicated
111    // to the second region. This example assumes you have already replicated your key
112
113    // Create a KMS Client in the second region.
114    let decrypt_kms_config = aws_sdk_kms::config::Builder::from(&sdk_config)
115        .region(Region::new(mrk_replica_decrypt_region))
116        .build();
117    let decrypt_kms_client = aws_sdk_kms::Client::from_conf(decrypt_kms_config);
118
119    let decrypt_kms_keyring = mpl
120        .create_aws_kms_mrk_keyring()
121        .kms_key_id(mrk_replica_key_id_decrypt)
122        .kms_client(decrypt_kms_client)
123        .send()
124        .await?;
125
126    // 7. Decrypt your encrypted data using the decrypt keyring.
127    let decryption_response = esdk_client
128        .decrypt()
129        .ciphertext(ciphertext)
130        .keyring(decrypt_kms_keyring)
131        // Provide the encryption context that was supplied to the encrypt method
132        .encryption_context(encryption_context)
133        .send()
134        .await?;
135
136    let decrypted_plaintext = decryption_response
137        .plaintext
138        .expect("Unable to unwrap plaintext from decryption response");
139
140    // 8. Demonstrate that the decrypted plaintext is identical to the original plaintext.
141    // (This is an example for demonstration; you do not need to do this in your own code.)
142    assert_eq!(
143        decrypted_plaintext,
144        aws_smithy_types::Blob::new(plaintext),
145        "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
146    );
147
148    println!("KMS MRK Keyring Example Completed Successfully");
149
150    Ok(())
151}
152
153#[tokio::test(flavor = "multi_thread")]
154pub async fn test_encrypt_and_decrypt_with_keyring() -> Result<(), crate::BoxError2> {
155    // Test function for encrypt and decrypt using the AWS KMS MRK Keyring example
156    use crate::example_utils::utils;
157
158    let mrk_encrypt_region: String = "us-east-1".to_string();
159    let mrk_replica_decrypt_region: String = "eu-west-1".to_string();
160
161    encrypt_and_decrypt_with_keyring(
162        utils::TEST_EXAMPLE_DATA,
163        utils::TEST_MRK_KEY_ID_US_EAST_1,
164        utils::TEST_MRK_KEY_ID_EU_WEST_1,
165        mrk_encrypt_region,
166        mrk_replica_decrypt_region,
167    )
168    .await?;
169
170    Ok(())
171}