

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# DynamoDB 中的可搜索加密
<a name="ddb-searchable-encryption"></a>

要配置 Amazon DynamoDB 表以进行可搜索的加密，必须使用 [AWS KMS 分层密钥环](use-hierarchical-keyring.md)来生成、加密和解密用于保护项目的数据密钥。您还必须在表加密配置中包含 [`SearchConfig`](ddb-net-using.md#ddb-net-search-config)。

**注意**  
如果您使用适用于 DynamoDB 的 Java 客户端加密库，则必须使用适用于 DynamoDB 的 AWS 低级数据库加密 SDK API 来加密、签名、验证和解密您的表格项目。DynamoDB 增强版客户端和较低级别 `DynamoDBItemEncryptor` 不支持可搜索的加密。

**Topics**
+ [通过使用信标配置二级索引](#ddb-beacon-indexes)
+ [测试信标输出](#ddb-beacon-testing)

## 通过使用信标配置二级索引
<a name="ddb-beacon-indexes"></a>

[配置信标](configure-beacons.md)后，您必须先配置反映每个信标的二级索引，然后才能搜索加密的属性。

配置标准信标或复合信标时， AWS 数据库加密 SDK 会在信标名称中添加`aws_dbe_b_`前缀，以便服务器可以轻松识别信标。例如，如果您将复合信标命名为 `compoundBeacon`，则信标的完整名称实际上为 `aws_dbe_b_compoundBeacon`。如果您要配置包含标准信标或复合信标的[二级索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SecondaryIndexes.html)，则必须在标识信标名称时包含 `aws_dbe_b_` 前缀。

**分区键和排序键**  
您将无法加密主键值。您的分区和排序密钥必须经过签名。您的主键值不能是标准或复合信标。  
除非您指定任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性`SIGN_ONLY`，否则您的主键值必须是，分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。  
您的主键值可以是已签名的信标。如果您为每个主键值配置了不同的签名信标，则必须指定属性名称以将主键值标识为已签名信标名称。但是， AWS 数据库加密 SDK 不会为已签名的信标添加`aws_dbe_b_`前缀。即使您为主键值配置了不同的签名信标，您也只需要在配置二级索引时为主键值指定属性名称。

**本地二级索引**  
[本地二级索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html)的排序键可以是信标。  
如果您为排序键指定信标，类型必须为 String。如果您为排序键指定标准信标或复合信标，则必须在指定信标名称时包含 `aws_dbe_b_` 前缀。如果您指定签名信标，则请指定不包含任何前缀的信标名称。

**全局二级索引**  
[全局二级索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html)的分区键和排序键都可以是信标。  
如果您为分区键或排序键指定信标，则类型必须为 String。如果您为排序键指定标准信标或复合信标，则必须在指定信标名称时包含 `aws_dbe_b_` 前缀。如果您指定签名信标，则请指定不包含任何前缀的信标名称。

**属性投影**  
[投影](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Projections)是从表复制到二级索引的属性集。表的分区键和排序键始终投影到索引中；您可以投影其他属性以支持应用程序的查询要求。DynamoDB 为属性投影提供三种不同的选项：`KEYS_ONLY`、`INCLUDE` 和 `ALL`。  
如果使用 INCLUDE 属性投影在信标上进行搜索，则您必须指定构造信标所用的所有属性的名称以及包含 `aws_dbe_b_` 前缀的信标名称。例如，如果通过 `field1`、`field2` 和 `field3` 配置了复合信标 `compoundBeacon`，则必须在投影中指定 `aws_dbe_b_compoundBeacon`、`field1`、`field2` 和 `field3`。  
全局二级索引只能使用投影中显式指定的属性，但本地二级索引可以使用任何属性。

## 测试信标输出
<a name="ddb-beacon-testing"></a>

如果您[配置了复合信标](configure-beacons.md#config-compound-beacons)或使用[虚拟字段](configure-beacons.md#create-virtual-field)构造了信标，我们建议您在填充 DynamoDB 表之前验证这些信标是否产生了预期的输出。

 AWS 数据库加密 SDK 提供的`DynamoDbEncryptionTransforms`服务可帮助您对虚拟场和复合信标输出进行故障排除。

### 测试虚拟字段
<a name="ddb-beacon-testing-virtual-field"></a>

以下代码段创建测试项目，使用 D [ynamoDB 表加密](ddb-java-using.md#ddb-config-encrypt)配置定义`DynamoDbEncryptionTransforms`服务，并演示如何`ResolveAttributes`使用来验证虚拟字段是否产生预期的输出。

------
#### [ Java ]

**查看完整的代码示例**：[VirtualBeaconSearchableEncryptionExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/VirtualBeaconSearchableEncryptionExample.java) 

```
// Create test items
final PutItemRequest itemWithHasTestResultPutRequest = PutItemRequest.builder()
    .tableName(ddbTableName)
    .item(itemWithHasTestResult)
    .build();

final PutItemResponse itemWithHasTestResultPutResponse = ddb.putItem(itemWithHasTestResultPutRequest);

final PutItemRequest itemWithNoHasTestResultPutRequest = PutItemRequest.builder()
    .tableName(ddbTableName)
    .item(itemWithNoHasTestResult)
    .build();
    
final PutItemResponse itemWithNoHasTestResultPutResponse = ddb.putItem(itemWithNoHasTestResultPutRequest);    

// Define the DynamoDbEncryptionTransforms service
final DynamoDbEncryptionTransforms trans = DynamoDbEncryptionTransforms.builder()
    .DynamoDbTablesEncryptionConfig(encryptionConfig).build();

// Verify configuration
final ResolveAttributesInput resolveInput = ResolveAttributesInput.builder()
    .TableName(ddbTableName)
    .Item(itemWithHasTestResult)
    .Version(1)
    .build();
final ResolveAttributesOutput resolveOutput = trans.ResolveAttributes(resolveInput);

// Verify that VirtualFields has the expected value
Map<String, String> vf = new HashMap<>();
vf.put("stateAndHasTestResult", "CAt");
assert resolveOutput.VirtualFields().equals(vf);
```

------
#### [ C\$1 / .NET ]

**参见完整的代码示例**：[VirtualBeaconSearchableEncryptionExample.cs。](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/searchableencryption/VirtualBeaconSearchableEncryptionExample.cs)

```
 // Create item with hasTestResult=true
var itemWithHasTestResult = new Dictionary<String, AttributeValue>
{
    ["customer_id"] = new AttributeValue("ABC-123"),
    ["create_time"] = new AttributeValue { N = "1681495205" },
    ["state"] = new AttributeValue("CA"),
    ["hasTestResult"] = new AttributeValue { BOOL = true }
};

// Create item with hasTestResult=false
var itemWithNoHasTestResult = new Dictionary<String, AttributeValue>
{
    ["customer_id"] = new AttributeValue("DEF-456"),
    ["create_time"] = new AttributeValue { N = "1681495205" },
    ["state"] = new AttributeValue("CA"),
    ["hasTestResult"] = new AttributeValue { BOOL = false }
};

// Define the DynamoDbEncryptionTransforms service
var trans = new DynamoDbEncryptionTransforms(encryptionConfig);

// Verify configuration
var resolveInput = new ResolveAttributesInput
{
    TableName = ddbTableName,
    Item = itemWithHasTestResult,
    Version = 1
};
var resolveOutput = trans.ResolveAttributes(resolveInput);

// Verify that VirtualFields has the expected value
Debug.Assert(resolveOutput.VirtualFields.Count == 1);
Debug.Assert(resolveOutput.VirtualFields["stateAndHasTestResult"] == "CAt");
```

------
#### [ Rust ]

**参见完整的代码示例**：[virtual](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/virtual_beacon_searchable_encryption.rs) \$1beacon\$1searchable\$1encryption.rs。

```
// Create item with hasTestResult=true
let item_with_has_test_result = HashMap::from([
    (
        "customer_id".to_string(),
        AttributeValue::S("ABC-123".to_string()),
    ),
    (
        "create_time".to_string(),
        AttributeValue::N("1681495205".to_string()),
    ),
    ("state".to_string(), AttributeValue::S("CA".to_string())),
    ("hasTestResult".to_string(), AttributeValue::Bool(true)),
]);

// Create item with hasTestResult=false
let item_with_no_has_test_result = HashMap::from([
    (
        "customer_id".to_string(),
        AttributeValue::S("DEF-456".to_string()),
    ),
    (
        "create_time".to_string(),
        AttributeValue::N("1681495205".to_string()),
    ),
    ("state".to_string(), AttributeValue::S("CA".to_string())),
    ("hasTestResult".to_string(), AttributeValue::Bool(false)),
]);

// Define the transform service
let trans = transform_client::Client::from_conf(encryption_config.clone())?;

// Verify the configuration 
let resolve_output = trans
    .resolve_attributes()
    .table_name(ddb_table_name)
    .item(item_with_has_test_result.clone())
    .version(1)
    .send()
    .await?;

// Verify that VirtualFields has the expected value
let virtual_fields = resolve_output.virtual_fields.unwrap();
assert_eq!(virtual_fields.len(), 1);
assert_eq!(virtual_fields["stateAndHasTestResult"], "CAt");
```

------

### 测试复合信标
<a name="ddb-beacon-testing-compound-beacon"></a>

以下代码段创建了一个测试项目，使用 D [ynamoDB 表加密](ddb-java-using.md#ddb-config-encrypt)配置定义`DynamoDbEncryptionTransforms`服务，并演示了如何`ResolveAttributes`使用来验证复合信标是否产生了预期的输出。

------
#### [ Java ]

**查看完整的代码示例**：[CompoundBeaconSearchableEncryptionExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/CompoundBeaconSearchableEncryptionExample.java) 

```
// Create an item with both attributes used in the compound beacon.
final HashMap<String, AttributeValue> item = new HashMap<>();
item.put("work_id", AttributeValue.builder().s("9ce39272-8068-4efd-a211-cd162ad65d4c").build());
item.put("inspection_date", AttributeValue.builder().s("2023-06-13").build());
item.put("inspector_id_last4", AttributeValue.builder().s("5678").build());
item.put("unit", AttributeValue.builder().s("011899988199").build());
                            
// Define the DynamoDbEncryptionTransforms service
final DynamoDbEncryptionTransforms trans = DynamoDbEncryptionTransforms.builder()
    .DynamoDbTablesEncryptionConfig(encryptionConfig).build();

// Verify configuration 
final ResolveAttributesInput resolveInput = ResolveAttributesInput.builder()
    .TableName(ddbTableName)
    .Item(item)
    .Version(1)
    .build();

final ResolveAttributesOutput resolveOutput = trans.ResolveAttributes(resolveInput);
                            
// Verify that CompoundBeacons has the expected value   
Map<String, String> cbs = new HashMap<>();
cbs.put("last4UnitCompound", "L-5678.U-011899988199");
assert resolveOutput.CompoundBeacons().equals(cbs);
// Note : the compound beacon actually stored in the table is not "L-5678.U-011899988199"
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
```

------
#### [ C\$1 / .NET ]

**查看完整的代码示例**：[CompoundBeaconSearchableEncryptionExample.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/searchableencryption/CompoundBeaconSearchableEncryptionExample.cs)

```
// Create an item with both attributes used in the compound beacon
var item = new Dictionary<String, AttributeValue>
{
    ["work_id"] = new AttributeValue("9ce39272-8068-4efd-a211-cd162ad65d4c"),
    ["inspection_date"] = new AttributeValue("2023-06-13"),
    ["inspector_id_last4"] = new AttributeValue("5678"),
    ["unit"] = new AttributeValue("011899988199")
};                           
                            
// Define the DynamoDbEncryptionTransforms service
var trans = new DynamoDbEncryptionTransforms(encryptionConfig);

// Verify configuration
var resolveInput = new ResolveAttributesInput
{
    TableName = ddbTableName,
    Item = item,
    Version = 1
};
var resolveOutput = trans.ResolveAttributes(resolveInput);                            
                            
// Verify that CompoundBeacons has the expected value 
Debug.Assert(resolveOutput.CompoundBeacons.Count == 1);
Debug.Assert(resolveOutput.CompoundBeacons["last4UnitCompound"] == "L-5678.U-011899988199");
// Note : the compound beacon actually stored in the table is not "L-5678.U-011899988199"
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
```

------
#### [ Rust ]

**查看完整的代码示例：compound\$1beacon\$1searchable\$1encr** y [pt](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/compound_beacon_searchable_encryption.rs) ion.rs

```
// Create an item with both attributes used in the compound beacon
let item = HashMap::from([
    (
        "work_id".to_string(),
        AttributeValue::S("9ce39272-8068-4efd-a211-cd162ad65d4c".to_string()),
    ),
    (
        "inspection_date".to_string(),
        AttributeValue::S("2023-06-13".to_string()),
    ),
    (
        "inspector_id_last4".to_string(),
        AttributeValue::S("5678".to_string()),
    ),
    (
        "unit".to_string(),
        AttributeValue::S("011899988199".to_string()),
    ),
]);                           
                            
// Define the transforms service
let trans = transform_client::Client::from_conf(encryption_config.clone())?;

// Verify configuration
let resolve_output = trans
    .resolve_attributes()
    .table_name(ddb_table_name)
    .item(item.clone())
    .version(1)
    .send()
    .await?;                            
                            
// Verify that CompoundBeacons has the expected value 
let compound_beacons = resolve_output.compound_beacons.unwrap();
assert_eq!(compound_beacons.len(), 1);
assert_eq!(
    compound_beacons["last4UnitCompound"],
    "L-5678.U-011899988199"
);
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
```

------