Skip to content

Commit 731e880

Browse files
chore: Add examples for MRKs (#145)
1 parent bafd6fb commit 731e880

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package com.amazonaws.examples;
4+
5+
import java.security.GeneralSecurityException;
6+
import java.util.Arrays;
7+
8+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
9+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
10+
import com.amazonaws.services.dynamodbv2.datamodeling.AttributeEncryptor;
11+
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
12+
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
13+
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig.TableNameOverride;
14+
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.DynamoDBEncryptor;
15+
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.providers.DirectKmsMaterialProvider;
16+
import com.amazonaws.services.kms.AWSKMS;
17+
import com.amazonaws.services.kms.AWSKMSClientBuilder;
18+
19+
/**
20+
* Example showing use of AWS KMS CMP with an AWS KMS Multi-Region Key. We encrypt a record with a key in one region,
21+
* then decrypt the ciphertext with the same key replicated to another region.
22+
*
23+
* This example assumes that you have a DDB Global Table replicated to two regions, and an AWS KMS Multi-Region Key
24+
* replicated to the same regions.
25+
*/
26+
public class AwsKmsMultiRegionKey {
27+
28+
public static void main(String[] args) throws GeneralSecurityException {
29+
final String tableName = args[0];
30+
final String cmkArn1 = args[1];
31+
final String cmkArn2 = args[2];
32+
33+
encryptRecord(tableName, cmkArn1, cmkArn2);
34+
}
35+
36+
public static void encryptRecord(final String tableName, final String cmkArnEncrypt, final String cmkArnDecrypt) throws GeneralSecurityException {
37+
AWSKMS kmsDecrypt = null;
38+
AWSKMS kmsEncrypt = null;
39+
AmazonDynamoDB ddbEncrypt = null;
40+
AmazonDynamoDB ddbDecrypt = null;
41+
try {
42+
// Sample object to be encrypted
43+
AwsKmsEncryptedObject.DataPoJo record = new AwsKmsEncryptedObject.DataPoJo();
44+
record.setPartitionAttribute("is this");
45+
record.setSortAttribute(42);
46+
record.setExample("data");
47+
record.setSomeNumbers(99);
48+
record.setSomeBinary(new byte[]{0x00, 0x01, 0x02});
49+
record.setLeaveMe("alone");
50+
51+
// Set up clients and configuration in the first region. All of this is thread-safe and can be reused
52+
// across calls
53+
final String encryptRegion = cmkArnEncrypt.split(":")[3];
54+
kmsEncrypt = AWSKMSClientBuilder.standard().withRegion(encryptRegion).build();
55+
ddbEncrypt = AmazonDynamoDBClientBuilder.standard().withRegion(encryptRegion).build();
56+
final DirectKmsMaterialProvider cmpEncrypt = new DirectKmsMaterialProvider(kmsEncrypt, cmkArnEncrypt);
57+
final DynamoDBEncryptor encryptor = DynamoDBEncryptor.getInstance(cmpEncrypt);
58+
59+
// Mapper Creation
60+
// Please note the use of SaveBehavior.PUT (SaveBehavior.CLOBBER works as well).
61+
// Omitting this can result in data-corruption.
62+
DynamoDBMapperConfig mapperConfig = DynamoDBMapperConfig.builder()
63+
.withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.PUT)
64+
.withTableNameOverride(TableNameOverride.withTableNameReplacement(tableName))
65+
.build();
66+
DynamoDBMapper encryptMapper = new DynamoDBMapper(ddbEncrypt, mapperConfig, new AttributeEncryptor(encryptor));
67+
68+
System.out.println("Plaintext Record: " + record);
69+
// Save the item to the DynamoDB table
70+
encryptMapper.save(record);
71+
72+
// DDB Global Table replication takes some time. Sleep for a moment to give the item a chance to replicate
73+
// to the second region
74+
try {
75+
Thread.sleep(1000);
76+
} catch (InterruptedException e) {}
77+
78+
// Set up clients and configuration in the second region
79+
final String decryptRegion = cmkArnDecrypt.split(":")[3];
80+
kmsDecrypt = AWSKMSClientBuilder.standard().withRegion(decryptRegion).build();
81+
ddbDecrypt = AmazonDynamoDBClientBuilder.standard().withRegion(decryptRegion).build();
82+
final DirectKmsMaterialProvider cmpDecrypt = new DirectKmsMaterialProvider(kmsDecrypt, cmkArnDecrypt);
83+
final DynamoDBEncryptor decryptor = DynamoDBEncryptor.getInstance(cmpDecrypt);
84+
85+
DynamoDBMapper decryptMapper = new DynamoDBMapper(ddbDecrypt, mapperConfig, new AttributeEncryptor(decryptor));
86+
87+
// Retrieve (and decrypt) it in the second region. This allows you to avoid a cross-region KMS call to the
88+
// first region if your application is running in the second region
89+
AwsKmsEncryptedObject.DataPoJo decryptedRecord = decryptMapper.load(AwsKmsEncryptedObject.DataPoJo.class, "is this", 42);
90+
System.out.println("Decrypted Record: " + decryptedRecord);
91+
92+
// The decrypted fields match the original fields before encryption
93+
assert record.getExample().equals(decryptedRecord.getExample());
94+
assert record.getSomeNumbers() == decryptedRecord.getSomeNumbers();
95+
assert Arrays.equals(record.getSomeBinary(), decryptedRecord.getSomeBinary());
96+
} finally {
97+
if (kmsDecrypt != null) {
98+
kmsDecrypt.shutdown();
99+
}
100+
if (kmsEncrypt != null) {
101+
kmsEncrypt.shutdown();
102+
}
103+
if (ddbEncrypt != null) {
104+
ddbEncrypt.shutdown();
105+
}
106+
if (ddbDecrypt != null) {
107+
ddbDecrypt.shutdown();
108+
}
109+
}
110+
}
111+
}
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+
4+
package com.amazonaws.examples;
5+
6+
import org.testng.annotations.Test;
7+
8+
import java.security.GeneralSecurityException;
9+
10+
import static com.amazonaws.examples.TestUtils.US_EAST_1_MRK_KEY_ID;
11+
import static com.amazonaws.examples.TestUtils.US_WEST_2_MRK_KEY_ID;
12+
13+
public class AwsKmsMultiRegionKeyIT {
14+
private static final String TABLE_NAME = "ddbec-mrk-testing";
15+
16+
@Test
17+
public void testEncryptAndDecrypt() throws GeneralSecurityException {
18+
AwsKmsMultiRegionKey.encryptRecord(TABLE_NAME, US_EAST_1_MRK_KEY_ID, US_WEST_2_MRK_KEY_ID);
19+
}
20+
}

examples/src/test/java/com/amazonaws/examples/TestUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ private TestUtils() {
2323
*/
2424
public static final String US_WEST_2_KEY_ID = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f";
2525
public static final String US_WEST_2 = "us-west-2";
26+
public static final String US_EAST_1_MRK_KEY_ID = "arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7";
27+
public static final String US_WEST_2_MRK_KEY_ID = "arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7";
2628

2729
public static void createDDBTable(AmazonDynamoDB ddb, String tableName, String partitionName, String sortName) {
2830
ArrayList<AttributeDefinition> attrDef = new ArrayList<AttributeDefinition>();

0 commit comments

Comments
 (0)