

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

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

若要設定 Amazon DynamoDB 資料表進行可搜尋加密，您必須使用[AWS KMS 階層式 keyring](use-hierarchical-keyring.md) 來產生、加密和解密用於保護項目的資料金鑰。您還必須在資料表加密組態[`SearchConfig`](ddb-net-using.md#ddb-net-search-config)中包含 。

**注意**  
如果您使用適用於 DynamoDB 的 Java 用戶端加密程式庫，則必須使用適用於 DynamoDB API 的低階 AWS 資料庫加密開發套件來加密、簽署、驗證和解密資料表項目。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_ONLY`，除非您指定任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`屬性，否則分割區和排序屬性也必須是 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。  
您的主索引鍵值可以是已簽章的信標。如果您為每個主索引鍵值設定了不同的簽章信標，則必須指定屬性名稱，將主索引鍵值識別為簽章信標名稱。不過， AWS 資料庫加密 SDK 不會將 `aws_dbe_b_` 字首新增至已簽章的信標。即使您為主索引鍵值設定了不同的簽章信標，您只需要在設定輔助索引時為主索引鍵值指定屬性名稱。

**本機次要索引**  
[本機次要索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html)的排序索引鍵可以是信標。  
如果您為排序索引鍵指定信標，則類型必須為字串。如果您為排序索引鍵指定標準或複合信標，則必須在指定信標名稱時包含 `aws_dbe_b_`字首。如果您指定已簽章的信標，請指定不含任何字首的信標名稱。

**全域次要索引**  
[全域次要索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html)的分割區和排序索引鍵可以是信標。  
如果您為分割區或排序索引鍵指定信標，則類型必須為字串。如果您為排序索引鍵指定標準或複合信標，則必須在指定信標名稱時包含 `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`和 設定複合信標 `compoundBeacon``field3`，您必須在投影`field3`中指定 `field2`、、 `aws_dbe_b_compoundBeacon` `field1`和 。  
全域次要索引只能使用投影中明確指定的屬性，但本機次要索引可以使用任何屬性。

## 測試信標輸出
<a name="ddb-beacon-testing"></a>

如果您[設定複合信標](configure-beacons.md#config-compound-beacons)或使用[虛擬欄位](configure-beacons.md#create-virtual-field)建構信標，建議您在填入 DynamoDB 資料表之前驗證這些信標是否產生預期的輸出。

 AWS Database Encryption SDK 提供 `DynamoDbEncryptionTransforms`服務，協助您對虛擬欄位和複合信標輸出進行疑難排解。

### 測試虛擬欄位
<a name="ddb-beacon-testing-virtual-field"></a>

下列程式碼片段會建立測試項目、使用 [DynamoDB 資料表加密組態](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\$1beacon\$1searchable\$1encryption.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/virtual_beacon_searchable_encryption.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>

下列程式碼片段會建立測試項目、使用 [DynamoDB 資料表加密組態](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\$1encryption.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/compound_beacon_searchable_encryption.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
```

------