Skip to content

Commit 5a77786

Browse files
committed
chore: Add examples to examine contents of query error list
1 parent 07bba8b commit 5a77786

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

Examples/runtimes/net/src/Examples.cs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ static async Task Main()
1212
ItemEncryptDecryptExample.PutItemGetItem();
1313

1414
await BasicPutGetExample.PutItemGetItem();
15+
await ScanErrorExample.ScanError();
1516
await GetEncryptedDataKeyDescriptionExample.GetEncryptedDataKeyDescription();
1617
await MultiPutGetExample.MultiPutGet();
1718
await ClientSupplierExample.ClientSupplierPutItemGetItem();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Net;
5+
using System.Threading.Tasks;
6+
using Amazon.DynamoDBv2.Model;
7+
using AWS.Cryptography.DbEncryptionSDK.DynamoDb;
8+
using AWS.Cryptography.DbEncryptionSDK.StructuredEncryption;
9+
using AWS.Cryptography.MaterialProviders;
10+
11+
/*
12+
This example sets up DynamoDb Encryption for the AWS SDK client
13+
and uses the low level PutItem and GetItem DDB APIs to demonstrate
14+
putting a client-side encrypted item into DynamoDb
15+
and then retrieving and decrypting that item from DynamoDb.
16+
17+
Running this example requires access to the DDB Table whose name
18+
is provided in CLI arguments.
19+
This table must be configured with the following
20+
primary key configuration:
21+
- Partition key is named "partition_key" with type (S)
22+
- Sort key is named "sort_key" with type (N)
23+
*/
24+
public class ScanErrorExample
25+
{
26+
public static async Task ScanError()
27+
{
28+
var kmsKeyId = TestUtils.TEST_KMS_KEY_ID;
29+
var ddbTableName = TestUtils.TEST_DDB_TABLE_NAME;
30+
// 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data.
31+
// For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use.
32+
// We will use the `CreateMrkMultiKeyring` method to create this keyring,
33+
// as it will correctly handle both single region and Multi-Region KMS Keys.
34+
var matProv = new MaterialProviders(new MaterialProvidersConfig());
35+
var keyringInput = new CreateAwsKmsMrkMultiKeyringInput { Generator = kmsKeyId };
36+
var kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);
37+
38+
// 2. Configure which attributes are encrypted and/or signed when writing new items.
39+
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
40+
// we must explicitly configure how they should be treated during item encryption:
41+
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
42+
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
43+
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
44+
var attributeActionsOnEncrypt = new Dictionary<string, CryptoAction>
45+
{
46+
["partition_key"] = CryptoAction.SIGN_ONLY, // Our partition attribute must be SIGN_ONLY
47+
["sort_key"] = CryptoAction.SIGN_ONLY, // Our sort attribute must be SIGN_ONLY
48+
["attribute1"] = CryptoAction.ENCRYPT_AND_SIGN,
49+
["attribute2"] = CryptoAction.SIGN_ONLY,
50+
[":attribute3"] = CryptoAction.DO_NOTHING
51+
};
52+
53+
// 3. Configure which attributes we expect to be included in the signature
54+
// when reading items. There are two options for configuring this:
55+
//
56+
// - (Recommended) Configure `allowedUnsignedAttributesPrefix`:
57+
// When defining your DynamoDb schema and deciding on attribute names,
58+
// choose a distinguishing prefix (such as ":") for all attributes that
59+
// you do not want to include in the signature.
60+
// This has two main benefits:
61+
// - It is easier to reason about the security and authenticity of data within your item
62+
// when all unauthenticated data is easily distinguishable by their attribute name.
63+
// - If you need to add new unauthenticated attributes in the future,
64+
// you can easily make the corresponding update to your `attributeActionsOnEncrypt`
65+
// and immediately start writing to that new attribute, without
66+
// any other configuration update needed.
67+
// Once you configure this field, it is not safe to update it.
68+
//
69+
// - Configure `allowedUnsignedAttributes`: You may also explicitly list
70+
// a set of attributes that should be considered unauthenticated when encountered
71+
// on read. Be careful if you use this configuration. Do not remove an attribute
72+
// name from this configuration, even if you are no longer writing with that attribute,
73+
// as old items may still include this attribute, and our configuration needs to know
74+
// to continue to exclude this attribute from the signature scope.
75+
// If you add new attribute names to this field, you must first deploy the update to this
76+
// field to all readers in your host fleet before deploying the update to start writing
77+
// with that new attribute.
78+
//
79+
// For this example, we have designed our DynamoDb table such that any attribute name with
80+
// the ":" prefix should be considered unauthenticated.
81+
const String unsignAttrPrefix = ":";
82+
83+
// 4. Create the DynamoDb Encryption configuration for the table we will be writing to.
84+
Dictionary<String, DynamoDbTableEncryptionConfig> tableConfigs =
85+
new Dictionary<String, DynamoDbTableEncryptionConfig>();
86+
DynamoDbTableEncryptionConfig config = new DynamoDbTableEncryptionConfig
87+
{
88+
LogicalTableName = ddbTableName,
89+
PartitionKeyName = "partition_key",
90+
SortKeyName = "sort_key",
91+
AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
92+
Keyring = kmsKeyring,
93+
AllowedUnsignedAttributePrefix = unsignAttrPrefix,
94+
// Specifying an algorithm suite is not required,
95+
// but is done here to demonstrate how to do so.
96+
// We suggest using the
97+
// `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite,
98+
// which includes AES-GCM with key derivation, signing, and key commitment.
99+
// This is also the default algorithm suite if one is not specified in this config.
100+
// For more information on supported algorithm suites, see:
101+
// https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html
102+
AlgorithmSuiteId = DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384
103+
};
104+
tableConfigs.Add(ddbTableName, config);
105+
106+
// 5. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs
107+
var ddb = new Client.DynamoDbClient(
108+
new DynamoDbTablesEncryptionConfig { TableEncryptionConfigs = tableConfigs });
109+
110+
var expressionAttributeValues = new Dictionary<String, AttributeValue>
111+
{
112+
[":prefix"] = new AttributeValue("Broken"),
113+
};
114+
115+
// 6. Perform a Scan for which some records will not decrypt
116+
var scanRequest = new ScanRequest
117+
{
118+
TableName = ddbTableName,
119+
FilterExpression = "begins_with(partition_key, :prefix)",
120+
ExpressionAttributeValues = expressionAttributeValues
121+
};
122+
123+
try
124+
{
125+
var scanResponse = await ddb.ScanAsync(scanRequest);
126+
}
127+
catch (DynamoDbEncryptionException e)
128+
{
129+
Console.Error.WriteLine("Encryptor Error : " + e.Message);
130+
}
131+
catch (AWS.Cryptography.DbEncryptionSDK.DynamoDb.Transforms.CollectionOfErrors e)
132+
{
133+
Console.Error.WriteLine("Decryption Errors : ");
134+
Console.Error.WriteLine(e.Message);
135+
foreach (Exception element in e.list)
136+
{
137+
Console.WriteLine(element);
138+
}
139+
}
140+
catch (Exception e)
141+
{
142+
Console.Error.WriteLine("Other Error : ");
143+
Console.Error.WriteLine(e);
144+
}
145+
}
146+
}

0 commit comments

Comments
 (0)