50
50
or you can implement an interface that lets you map the primary key on your items
51
51
to the branch key that should be responsible for decrypting that data.
52
52
53
- This example first creates the DynamoDb-backed KeyStore,
54
- and creates two branch keys. These are control plane operations that
55
- only need to occur once. While not demonstrated in this example,
56
- you should additionally use the `VersionKey` API on the KeyStore
57
- to periodically rotate your branch key material.
58
-
59
53
This example then demonstrates configuring a Hierarchical Keyring
60
54
with a Branch Key ID Supplier to encrypt and decrypt data for
61
55
two separate tenants.
@@ -75,13 +69,17 @@ or you can implement an interface that lets you map the primary key on your item
75
69
*/
76
70
public class HierarchicalKeyringExample {
77
71
78
- public static void HierarchicalKeyringGetItemPutItem (String ddbTableName , String keyStoreTableName , String logicalKeyStoreName , String kmsKeyId ) {
79
- // Initial KeyStore Setup: Configure a keystore resource to create the table
80
- // that will persist your branch keys, then create two new branch keys.
81
- // This process should occur in your control plane, and returns
82
- // Branch Key IDs that you will need to configure for use in your data plane.
83
-
84
- // 1. Configure your KeyStore resource
72
+ public static void HierarchicalKeyringGetItemPutItem (
73
+ String ddbTableName , String tenant1BranchKeyId , String tenant2BranchKeyId , String keyStoreTableName ,
74
+ String logicalKeyStoreName , String kmsKeyId ) {
75
+ // Initial KeyStore Setup: This example requires that you have already
76
+ // created your KeyStore, and have populated it with two new branch keys.
77
+ // See the "Create KeyStore Table Example" and "Create KeyStore Key Example"
78
+ // for an example of how to do this.
79
+
80
+ // 1. Configure your KeyStore resource.
81
+ // This SHOULD be the same configuration that you used
82
+ // to initially create and populate your KeyStore.
85
83
final KeyStore keystore = KeyStore .builder ().KeyStoreConfig (
86
84
KeyStoreConfig .builder ()
87
85
.ddbClient (DynamoDbClient .create ())
@@ -93,32 +91,20 @@ public static void HierarchicalKeyringGetItemPutItem(String ddbTableName, String
93
91
.build ())
94
92
.build ()).build ();
95
93
96
- // 2. Create the DynamoDb table to store the branch keys
97
- keystore .CreateKeyStore (CreateKeyStoreInput .builder ().build ());
98
-
99
- // 3. Create two branch keys for our two tenants.
100
- // Use the same KMS Key to protect both keys.
101
- final String tenant1BranchKey = keystore .CreateKey ().branchKeyIdentifier ();
102
- final String tenant2BranchKey = keystore .CreateKey ().branchKeyIdentifier ();
103
-
104
- // Data Plane: Given the above setup done in our control plane, we have created
105
- // the resources required to encrypt and decrypt items for our two tenants by
106
- // configuring our AWS SDK Client to use a Hierarchical Keyring.
107
-
108
- // 4. Create a Branch Key ID Supplier. See ExampleBranchKeyIdSupplier in this directory.
94
+ // 2. Create a Branch Key ID Supplier. See ExampleBranchKeyIdSupplier in this directory.
109
95
final DynamoDbEncryption ddbEnc = DynamoDbEncryption .builder ()
110
96
.DynamoDbEncryptionConfig (DynamoDbEncryptionConfig .builder ().build ())
111
97
.build ();
112
98
final IBranchKeyIdSupplier branchKeyIdSupplier = ddbEnc .CreateDynamoDbEncryptionBranchKeyIdSupplier (
113
99
CreateDynamoDbEncryptionBranchKeyIdSupplierInput .builder ()
114
- .ddbKeyBranchKeyIdSupplier (new ExampleBranchKeyIdSupplier (tenant1BranchKey , tenant2BranchKey ))
100
+ .ddbKeyBranchKeyIdSupplier (new ExampleBranchKeyIdSupplier (tenant1BranchKeyId , tenant2BranchKeyId ))
115
101
.build ()).branchKeyIdSupplier ();
116
102
117
- // 5 . Create the Hierarchical Keyring, using the Branch Key ID Supplier above.
103
+ // 3 . Create the Hierarchical Keyring, using the Branch Key ID Supplier above.
118
104
// With this configuration, the AWS SDK Client ultimately configured will be capable
119
105
// of encrypting or decrypting items for either tenant (assuming correct KMS access).
120
106
// If you want to restrict the client to only encrypt or decrypt for a single tenant,
121
- // configure this Hierarchical Keyring using `.branchKeyId(tenant1BranchKey )` instead
107
+ // configure this Hierarchical Keyring using `.branchKeyId(tenant1BranchKeyId )` instead
122
108
// of `.branchKeyIdSupplier(branchKeyIdSupplier)`.
123
109
final MaterialProviders matProv = MaterialProviders .builder ()
124
110
.MaterialProvidersConfig (MaterialProvidersConfig .builder ().build ())
@@ -131,7 +117,7 @@ public static void HierarchicalKeyringGetItemPutItem(String ddbTableName, String
131
117
.build ();
132
118
final IKeyring hierarchicalKeyring = matProv .CreateAwsKmsHierarchicalKeyring (keyringInput );
133
119
134
- // 6 . Configure which attributes are encrypted and/or signed when writing new items.
120
+ // 4 . Configure which attributes are encrypted and/or signed when writing new items.
135
121
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
136
122
// we must explicitly configure how they should be treated during item encryption:
137
123
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
@@ -142,7 +128,7 @@ public static void HierarchicalKeyringGetItemPutItem(String ddbTableName, String
142
128
attributeActions .put ("sort_key" , CryptoAction .SIGN_ONLY ); // Our sort attribute must be SIGN_ONLY
143
129
attributeActions .put ("tenant_sensitive_data" , CryptoAction .ENCRYPT_AND_SIGN );
144
130
145
- // 3 . Configure which attributes we expect to be included in the signature
131
+ // 5 . Configure which attributes we expect to be included in the signature
146
132
// when reading items. There are two options for configuring this:
147
133
//
148
134
// - (Recommended) Configure `allowedUnauthenticatedAttributesPrefix`:
@@ -172,7 +158,7 @@ public static void HierarchicalKeyringGetItemPutItem(String ddbTableName, String
172
158
// add unauthenticated attributes in the future, we define a prefix ":" for such attributes.
173
159
final String unauthAttrPrefix = ":" ;
174
160
175
- // 7 . Create the DynamoDb Encryption configuration for the table we will be writing to.
161
+ // 6 . Create the DynamoDb Encryption configuration for the table we will be writing to.
176
162
final Map <String , DynamoDbTableEncryptionConfig > tableConfigs = new HashMap <>();
177
163
final DynamoDbTableEncryptionConfig config = DynamoDbTableEncryptionConfig .builder ()
178
164
.logicalTableName (ddbTableName )
@@ -184,27 +170,27 @@ public static void HierarchicalKeyringGetItemPutItem(String ddbTableName, String
184
170
.build ();
185
171
tableConfigs .put (ddbTableName , config );
186
172
187
- // 8 . Create the DynamoDb Encryption Interceptor
173
+ // 7 . Create the DynamoDb Encryption Interceptor
188
174
DynamoDbEncryptionInterceptor encryptionInterceptor = DynamoDbEncryptionInterceptor .builder ()
189
175
.config (DynamoDbTablesEncryptionConfig .builder ()
190
176
.tableEncryptionConfigs (tableConfigs )
191
177
.build ())
192
178
.build ();
193
179
194
- // 9 . Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above
180
+ // 8 . Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above
195
181
final DynamoDbClient ddb = DynamoDbClient .builder ()
196
182
.overrideConfiguration (
197
183
ClientOverrideConfiguration .builder ()
198
184
.addExecutionInterceptor (encryptionInterceptor )
199
185
.build ())
200
186
.build ();
201
187
202
- // 10 . Put an item into our table using the above client.
203
- // Before the item gets sent to DynamoDb, it will be encrypted
204
- // client-side, according to our configuration.
205
- // Because the item we are writing uses "tenantId1" as our partition value,
206
- // based on the code we wrote in the ExampleBranchKeySupplier,
207
- // `tenant1BranchKey ` will be used to encrypt this item.
188
+ // 9 . Put an item into our table using the above client.
189
+ // Before the item gets sent to DynamoDb, it will be encrypted
190
+ // client-side, according to our configuration.
191
+ // Because the item we are writing uses "tenantId1" as our partition value,
192
+ // based on the code we wrote in the ExampleBranchKeySupplier,
193
+ // `tenant1BranchKeyId ` will be used to encrypt this item.
208
194
final HashMap <String , AttributeValue > item = new HashMap <>();
209
195
item .put ("partition_key" , AttributeValue .builder ().s ("tenant1Id" ).build ());
210
196
item .put ("sort_key" , AttributeValue .builder ().n ("0" ).build ());
@@ -220,12 +206,12 @@ public static void HierarchicalKeyringGetItemPutItem(String ddbTableName, String
220
206
// Demonstrate that PutItem succeeded
221
207
assert 200 == putResponse .sdkHttpResponse ().statusCode ();
222
208
223
- // 11 . Get the item back from our table using the same client.
209
+ // 10 . Get the item back from our table using the same client.
224
210
// The client will decrypt the item client-side, and return
225
211
// back the original item.
226
212
// Because the returned item's partition value is "tenantId1",
227
213
// based on the code we wrote in the ExampleBranchKeySupplier,
228
- // `tenant1BranchKey ` will be used to decrypt this item.
214
+ // `tenant1BranchKeyId ` will be used to decrypt this item.
229
215
final HashMap <String , AttributeValue > keyToGet = new HashMap <>();
230
216
keyToGet .put ("partition_key" , AttributeValue .builder ().s ("tenant1Id" ).build ());
231
217
keyToGet .put ("sort_key" , AttributeValue .builder ().n ("0" ).build ());
@@ -245,12 +231,15 @@ public static void HierarchicalKeyringGetItemPutItem(String ddbTableName, String
245
231
246
232
public static void main (final String [] args ) {
247
233
if (args .length <= 0 ) {
248
- throw new IllegalArgumentException ("To run this example, include the ddbTable, keyStoreTableName, and kmsKeyId in args" );
234
+ throw new IllegalArgumentException ("To run this example, include the ddbTable, tenant1BranchKeyId, "
235
+ + "tenant2BranchKeyId, keyStoreTableName, logicalKeyStoreName, and kmsKeyId in args" );
249
236
}
250
237
final String ddbTableName = args [0 ];
251
- final String keyStoreTableName = args [1 ];
252
- final String logicalKeyStoreTableName = args [2 ];
253
- final String kmsKeyId = args [3 ];
254
- HierarchicalKeyringGetItemPutItem (ddbTableName , keyStoreTableName , logicalKeyStoreTableName , kmsKeyId );
238
+ final String tenant1BranchKeyId = args [1 ];
239
+ final String tenant2BranchKeyId = args [2 ];
240
+ final String keyStoreTableName = args [3 ];
241
+ final String logicalKeyStoreName = args [4 ];
242
+ final String kmsKeyId = args [5 ];
243
+ HierarchicalKeyringGetItemPutItem (ddbTableName , tenant1BranchKeyId , tenant2BranchKeyId , keyStoreTableName , logicalKeyStoreName , kmsKeyId );
255
244
}
256
245
}
0 commit comments