

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

# AWS KMS 階層式 keyring
<a name="use-hierarchical-keyring"></a>


****  

|  | 
| --- |
| 我們的用戶端加密程式庫已重新命名為 AWS 資料庫加密 SDK。此開發人員指南仍提供有關 [DynamoDB 加密用戶端](legacy-dynamodb-encryption-client.md)的資訊。 | 

**注意**  
自 2023 年 7 月 24 日起，不支援在開發人員預覽版期間建立的分支金鑰。建立新的分支金鑰，以繼續使用您在開發人員預覽期間建立的金鑰存放區。

使用 AWS KMS 階層式 keyring，您可以在對稱加密 KMS 金鑰下保護密碼編譯資料，而無需 AWS KMS 在每次加密或解密記錄時呼叫 。對於需要將對 的呼叫降至最低的應用程式 AWS KMS，以及可以重複使用某些密碼編譯資料而不違反其安全要求的應用程式，這是理想的選擇。

階層式 keyring 是一種密碼編譯資料快取解決方案，使用保留在 Amazon DynamoDB 資料表中的 AWS KMS 受保護*分支金鑰*，然後本機快取用於加密和解密操作的分支金鑰資料，以減少 AWS KMS 呼叫次數。DynamoDB 資料表做為管理和保護分支金鑰的金鑰存放區。它會存放作用中的分支金鑰和所有舊版的分支金鑰。*作用中*分支金鑰是最新的分支金鑰版本。階層式 keyring 會為每個加密請求使用唯一的資料加密金鑰，並使用衍生自作用中分支金鑰的唯一包裝金鑰來加密每個資料加密金鑰。階層式 keyring 取決於作用中分支索引鍵與其衍生包裝索引鍵之間建立的階層。

階層式 keyring 通常使用每個分支金鑰版本來滿足多個請求。但是，您可以控制重複使用作用中分支金鑰的程度，並判斷作用中分支金鑰的輪換頻率。分支金鑰的作用中版本會保持作用中狀態，直到您[將其輪換](rotate-branch-key.md)為止。舊版的作用中分支金鑰不會用於執行加密操作，但仍然可以查詢並用於解密操作。

當您執行個體化階層 keyring 時，它會建立本機快取。您可以指定[快取限制](#cache-limit)，定義分支金鑰資料在本機快取中存放的時間上限，然後再過期並從快取移出。階層式 keyring 會 AWS KMS 呼叫一次 來解密分支金鑰，並在 操作中第一次指定 `branch-key-id` 時組合分支金鑰材料。然後，分支金鑰資料會存放在本機快取中，並重複使用於指定 的所有加密和解密操作，`branch-key-id`直到快取限制過期為止。在本機快取中存放分支金鑰材料可減少 AWS KMS 呼叫。例如，請考慮 15 分鐘的快取限制。如果您在該快取限制內執行 10，000 個加密操作，[傳統 AWS KMS keyring](use-kms-keyring.md) 將需要進行 10，000 次 AWS KMS 呼叫，以滿足 10，000 個加密操作。如果您有一個作用中的 `branch-key-id`，則階層式 keyring 只需要呼叫一次 AWS KMS ，以滿足 10，000 個加密操作。

本機快取會將加密資料與解密資料分開。加密資料是從作用中分支金鑰組合而成，並重複使用於所有加密操作，直到快取限制過期為止。解密資料是從加密欄位中繼資料中識別的分支金鑰 ID 和版本組合而成，並且會重複使用於與分支金鑰 ID 和版本相關的所有解密操作，直到快取限制到期為止。本機快取一次可以存放相同分支金鑰的多個版本。當本機快取設定為使用 時[branch key ID supplier](#branch-key-id-supplier)，它也可以一次存放來自多個作用中分支金鑰的分支金鑰資料。

**注意**  
 AWS 資料庫加密 SDK 中提到的所有*階層式 keyring* 都是指 AWS KMS 階層式 keyring。

**Topics**
+ [運作方式](#how-hierarchical-keyring-works)
+ [先決條件](#hierarchical-keyring-prereqs)
+ [所需的許可](#hierarchical-keyring-permissions)
+ [選擇快取](#hierarchical-keyring-caches)
+ [建立階層 keyring](#initialize-hierarchical-keyring)
+ [使用階層式 keyring 進行可搜尋的加密](#searchable-encryption-hierarchical-keyrings)

## 運作方式
<a name="how-hierarchical-keyring-works"></a>

下列逐步解說說明階層式 keyring 如何組合加密和解密資料，以及 keyring 為加密和解密操作所做的不同呼叫。如需包裝金鑰衍生和純文字資料金鑰加密程序的技術詳細資訊，請參閱[AWS KMS 階層式 keyring 技術詳細資訊](reference.md#hierarchical-keyring-details)。

**加密和簽署**  
下列逐步解說說明階層式 keyring 如何組合加密資料並衍生唯一的包裝金鑰。

1. 加密方法會向階層式 keyring 詢問加密資料。keyring 會產生純文字資料金鑰，然後檢查本機快取中是否有有效的分支金鑰材料來產生包裝金鑰。如果有有效的分支金鑰材料， keyring 會繼續進行**步驟 4**。

1. 如果沒有有效的分支金鑰材料，階層式 keyring 會查詢作用中分支金鑰的金鑰存放區。

   1. 金鑰存放區會呼叫 AWS KMS 來解密作用中分支金鑰，並傳回純文字作用中分支金鑰。識別作用中分支金鑰的資料會序列化，以在解密呼叫中提供其他已驗證的資料 (AAD) AWS KMS。

   1. 金鑰存放區會傳回純文字分支金鑰和識別它的資料，例如分支金鑰版本。

1. 階層式 keyring 會組合分支金鑰材料 （純文字分支金鑰和分支金鑰版本），並將它們的副本存放在本機快取中。

1. 階層式 keyring 會從純文字分支金鑰和 16 位元組隨機 salt 衍生唯一的包裝金鑰。它使用衍生的包裝金鑰來加密純文字資料金鑰的副本。

加密方法使用加密資料來加密和簽署記錄。如需如何在 AWS 資料庫加密 SDK 中加密和簽署記錄的詳細資訊，請參閱[加密和簽署](how-it-works.md#encrypt-and-sign)。

**解密和驗證**  
下列逐步解說說明階層式 keyring 如何組合解密資料和解密加密的資料金鑰。

1. 解密方法會從加密記錄的資料描述欄位中識別加密的資料金鑰，並將其傳遞至階層式 keyring。

1. 階層式 keyring 會將識別加密資料金鑰的資料還原序列化，包括分支金鑰版本、16 位元組 salt，以及描述資料金鑰如何加密的其他資訊。

   如需詳細資訊，請參閱[AWS KMS 階層式 keyring 技術詳細資訊](reference.md#hierarchical-keyring-details)。

1. 階層式 keyring 會檢查本機快取中是否有與**步驟 2 **中識別的分支金鑰版本相符的有效分支金鑰材料。如果有有效的分支金鑰材料， keyring 會繼續進行**步驟 6**。

1. 如果沒有有效的分支金鑰資料，階層式 keyring 會查詢符合**步驟 2 **中所識別分支金鑰版本的分支金鑰存放區。

   1. 金鑰存放區會呼叫 AWS KMS 來解密分支金鑰，並傳回純文字作用中分支金鑰。識別作用中分支金鑰的資料會序列化，以在解密呼叫中提供其他已驗證的資料 (AAD) AWS KMS。

   1. 金鑰存放區會傳回純文字分支金鑰和識別它的資料，例如分支金鑰版本。

1. 階層式 keyring 會組合分支金鑰材料 （純文字分支金鑰和分支金鑰版本），並將它們的副本存放在本機快取中。

1. 階層式 keyring 使用**步驟 2** 中識別的組合分支金鑰材料和 16 位元組的 salt 來重現加密資料金鑰的唯一包裝金鑰。

1. 階層式 keyring 使用重現的包裝金鑰來解密資料金鑰，並傳回純文字資料金鑰。

解密方法使用解密資料和純文字資料金鑰來解密和驗證記錄。如需如何在 AWS 資料庫加密 SDK 中解密和驗證記錄的詳細資訊，請參閱[解密和驗證](how-it-works.md#decrypt-and-verify)。

## 先決條件
<a name="hierarchical-keyring-prereqs"></a>

在建立和使用階層 keyring 之前，請確定符合下列先決條件。
+ 您或您的金鑰存放區管理員[已建立金鑰存放](create-keystore.md)區，並[建立至少一個作用中的分支金鑰](create-branch-keys.md)。
+ 您已[設定金鑰存放區動作](keystore-actions.md#config-keystore-actions)。
**注意**  
如何設定金鑰存放區動作，決定您可以執行哪些操作，以及階層式 keyring 可以使用哪些 KMS 金鑰。如需詳細資訊，請參閱 [金鑰存放區動作](keystore-actions.md)。
+ 您擁有存取和使用金鑰存放區和分支金鑰所需的 AWS KMS 許可。如需詳細資訊，請參閱[所需的許可](#hierarchical-keyring-permissions)。
+ 您已檢閱支援的快取類型，並設定最符合您需求的快取類型。如需詳細資訊，請參閱[選擇快取](#hierarchical-keyring-caches)

## 所需的許可
<a name="hierarchical-keyring-permissions"></a>

 AWS 資料庫加密 SDK 不需要 ， AWS 帳戶 也不依賴任何 AWS 服務。不過，若要使用階層式 keyring，您需要 AWS 帳戶 和 AWS KMS key（金鑰存放區） 中對稱加密的下列最低許可。
+ 若要使用階層式 keyring 加密和解密資料，您需要 [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)。
+ 若要[建立](create-branch-keys.md)和[輪換](rotate-branch-key.md)分支金鑰，您需要 [kms:GenerateDataKeyWithoutPlaintext](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyWithoutPlaintext.html) 和 [kms:ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html)。

如需控制對分支金鑰和金鑰存放區之存取的詳細資訊，請參閱 [實作最低權限的許可](keystore-least-privilege.md)。

## 選擇快取
<a name="hierarchical-keyring-caches"></a>

階層式 keyring 透過本機快取用於加密和解密操作的分支金鑰資料 AWS KMS ，減少對 進行的呼叫數量。在[建立階層 keyring](#initialize-hierarchical-keyring) 之前，您需要決定要使用的快取類型。您可以使用預設快取或自訂快取，以符合您的需求。

階層式 keyring 支援下列快取類型：
+ [預設快取](#cache-default)
+ [MultiThreaded快取](#cache-multithreaded)
+ [StormTracking 快取](#cache-stormtracking)
+ [共用快取](#cache-shared)

### 預設快取
<a name="cache-default"></a>

對於大多數使用者，預設快取滿足其執行緒需求。預設快取旨在支援大量多執行緒環境。當分支金鑰材料項目過期時，預設快取 AWS KMS 會提前 10 秒通知一個執行緒分支金鑰材料項目即將過期，以防止多個執行緒呼叫。這可確保只有一個執行緒將請求傳送至 AWS KMS 以重新整理快取。

預設和 StormTracking 快取支援相同的執行緒模型，但您只需要指定使用預設快取的進入容量。如需更精細的快取自訂，請使用 [StormTracking 快取](#cache-stormtracking)。

除非您想要自訂可在本機快取中存放的分支金鑰材料項目數目，否則在建立階層式 keyring 時不需要指定快取類型。如果您未指定快取類型，階層式 keyring 會使用預設快取類型，並將進入容量設定為 1000。

若要自訂預設快取，請指定下列值：
+ **項目容量**： 限制可在本機快取中存放的分支金鑰材料項目數量。

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

```
.cache(CacheType.builder()
        .Default(DefaultCache.builder()
        .entryCapacity(100)
        .build())
```

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

```
CacheType defaultCache = new CacheType
{
    Default = new DefaultCache{EntryCapacity = 100}
};
```

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

```
let cache: CacheType = CacheType::Default(
    DefaultCache::builder()
        .entry_capacity(100)
        .build()?,
);
```

------

### MultiThreaded快取
<a name="cache-multithreaded"></a>

MultiThreaded快取可在多執行緒環境中安全使用，但它不提供將 AWS KMS 或 Amazon DynamoDB 呼叫降至最低的任何功能。因此，當分支金鑰材料項目過期時，所有執行緒都會同時收到通知。這可能會導致多個 AWS KMS 呼叫重新整理快取。

若要使用MultiThreaded快取，請指定下列值：
+ **項目容量**： 限制可在本機快取中存放的分支金鑰材料項目數量。
+ **項目剔除尾端大小**：定義達到進入容量時要剔除的項目數量。

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

```
.cache(CacheType.builder()
        .MultiThreaded(MultiThreadedCache.builder()
        .entryCapacity(100)
        .entryPruningTailSize(1)                                        
        .build())
```

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

```
CacheType multithreadedCache = new CacheType
{
    MultiThreaded = new MultiThreadedCache
    {
        EntryCapacity = 100,
        EntryPruningTailSize = 1
    }
};
```

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

```
CacheType::MultiThreaded(
            MultiThreadedCache::builder()
                    .entry_capacity(100)
                    .entry_pruning_tail_size(1)
                    .build()?)
```

------

### StormTracking 快取
<a name="cache-stormtracking"></a>

StormTracking 快取旨在支援大量多執行緒環境。當分支金鑰材料項目過期時， StormTracking 快取 AWS KMS 會提前通知一個執行緒分支金鑰材料項目即將過期，以防止多個執行緒呼叫。這可確保只有一個執行緒將請求傳送至 AWS KMS 以重新整理快取。



若要使用 StormTracking 快取，請指定下列值：
+ **項目容量**： 限制可在本機快取中存放的分支金鑰材料項目數量。

  預設值：1000 個項目
+ **項目剔除尾部大小**： 定義一次要剔除的分支金鑰材料項目數目。

  預設值：1 個項目
+ **寬限期**：定義過期前嘗試重新整理分支金鑰材料的秒數。

  預設值：10 秒
+ **Grace 間隔**：定義嘗試重新整理分支金鑰資料之間的秒數。

  預設值：1 秒
+ **Fan out**：定義可同時嘗試重新整理分支金鑰材料的次數。

  預設值：20 次嘗試
+ **飛行中存留時間 (TTL)**：定義直到嘗試重新整理分支金鑰資料逾時的秒數。每當快取傳回以`NoSuchEntry`回應 時`GetCacheEntry`，該分支金鑰會被視為正在*傳輸中*，直到使用`PutCache`項目寫入相同的金鑰為止。

  預設值：10 秒
+ **休眠**：定義`fanOut`超過 時執行緒應休眠的秒數。

  預設值：20 毫秒

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

```
.cache(CacheType.builder()
        .StormTracking(StormTrackingCache.builder()
        .entryCapacity(100)
        .entryPruningTailSize(1)
        .gracePeriod(10)
        .graceInterval(1)
        .fanOut(20) 
        .inFlightTTL(10)
        .sleepMilli(20)                                        
        .build())
```

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

```
CacheType stormTrackingCache = new CacheType
{
    StormTracking = new StormTrackingCache
    {
        EntryCapacity = 100,
        EntryPruningTailSize = 1,
        FanOut = 20,
        GraceInterval = 1,
        GracePeriod = 10,
        InFlightTTL = 10,
        SleepMilli = 20
    }
};
```

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

```
CacheType::StormTracking(
                StormTrackingCache::builder()
                    .entry_capacity(100)
                    .entry_pruning_tail_size(1)
                    .grace_period(10)
                    .grace_interval(1)
                    .fan_out(20)
                    .in_flight_ttl(10)
                    .sleep_milli(20)
                    .build()?)
```

------

### 共用快取
<a name="cache-shared"></a>

根據預設，階層式 keyring 會在您每次執行個體化 keyring 時建立新的本機快取。不過，共用快取可讓您跨多個階層 keyring 共用快取，以協助節省記憶體。共用快取不會為每個您執行個體化的階層式 keyring 建立新的密碼編譯資料快取，而是只會在記憶體中儲存一個快取，供參考該快取的所有階層式 keyring 使用。共用快取可避免在 keyring 之間重複密碼編譯資料，有助於最佳化記憶體使用量。相反地，階層式 keyring 可以存取相同的基礎快取，從而減少整體記憶體使用量。

建立共用快取時，您仍然會定義快取類型。您可以指定 [預設快取](#cache-default)、 [MultiThreaded快取](#cache-multithreaded)或 [StormTracking 快取](#cache-stormtracking)做為快取類型，或取代任何相容的自訂快取。



**分區**  
多個階層式 keyring 可以使用單一共用快取。當您使用共用快取建立階層 keyring 時，您可以定義選用的**分割區 ID**。分割區 ID 會區分要寫入快取的階層式 keyring。如果兩個階層 keyring 參考相同的分割區 ID、 [logical key store name](create-keystore.md#logical-key-store-name)和分支金鑰 ID，則兩個 keyring 將在快取中共用相同的快取項目。如果您使用相同的共用快取建立兩個階層 keyring，但分割區 IDs 不同，則每個 keyring 只會從共用快取內自己的指定分割區存取快取項目。分割區在共用快取中充當邏輯分割區，允許每個階層 keyring 在自己的指定分割區上獨立運作，而不會干擾存放在另一個分割區中的資料。

如果您想要重複使用或共用分割區中的快取項目，您必須定義自己的分割區 ID。當您將分割區 ID 傳遞至階層式 keyring 時，keyring 可以重複使用共用快取中已存在的快取項目，而不必再次擷取並重新授權分支金鑰資料。如果您未指定分割區 ID，則每次執行個體化階層式 keyring 時，都會自動將唯一的分割區 ID 指派給 keyring。

下列程序示範如何使用[預設快取類型](#cache-default)建立共用快取，並將其傳遞至階層式 keyring。

1. 使用物料提供者程式庫 `CryptographicMaterialsCache`(MPL) 建立 (CMC)。 [https://github.com/aws/aws-cryptographic-material-providers-library](https://github.com/aws/aws-cryptographic-material-providers-library)

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

   ```
   // Instantiate the MPL
   final MaterialProviders matProv =
       MaterialProviders.builder()
           .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
           .build();
   
   // Create a CacheType object for the Default cache
   final CacheType cache =
       CacheType.builder() 
           .Default(DefaultCache.builder().entryCapacity(100).build())
           .build();
   
   // Create a CMC using the default cache
   final CreateCryptographicMaterialsCacheInput cryptographicMaterialsCacheInput =
       CreateCryptographicMaterialsCacheInput.builder()
           .cache(cache)
           .build();
   
   final ICryptographicMaterialsCache sharedCryptographicMaterialsCache =
       matProv.CreateCryptographicMaterialsCache(cryptographicMaterialsCacheInput);
   ```

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

   ```
   // Instantiate the MPL
   var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
    
   // Create a CacheType object for the Default cache
   var cache = new CacheType { Default = new DefaultCache{EntryCapacity = 100} };
    
   // Create a CMC using the default cache
   var cryptographicMaterialsCacheInput = new CreateCryptographicMaterialsCacheInput {Cache = cache};
    
   var sharedCryptographicMaterialsCache = materialProviders.CreateCryptographicMaterialsCache(cryptographicMaterialsCacheInput);
   ```

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

   ```
   // Instantiate the MPL
   let mpl_config = MaterialProvidersConfig::builder().build()?;
   let mpl = mpl_client::Client::from_conf(mpl_config)?;
   
   // Create a CacheType object for the default cache
   let cache: CacheType = CacheType::Default(
       DefaultCache::builder()
           .entry_capacity(100)
           .build()?,
   );
   
   // Create a CMC using the default cache
   let shared_cryptographic_materials_cache: CryptographicMaterialsCacheRef = mpl.
       create_cryptographic_materials_cache()
       .cache(cache)
       .send()
       .await?;
   ```

------

1. 建立共用快取的`CacheType`物件。

   `sharedCryptographicMaterialsCache` 將您在**步驟 1 **中建立的 傳遞至新`CacheType`物件。

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

   ```
   // Create a CacheType object for the sharedCryptographicMaterialsCache
   final CacheType sharedCache =
       CacheType.builder()
           .Shared(sharedCryptographicMaterialsCache)
           .build();
   ```

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

   ```
   // Create a CacheType object for the sharedCryptographicMaterialsCache
   var sharedCache = new CacheType { Shared = sharedCryptographicMaterialsCache };
   ```

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

   ```
   // Create a CacheType object for the shared_cryptographic_materials_cache
   let shared_cache: CacheType = CacheType::Shared(shared_cryptographic_materials_cache);
   ```

------

1. 將`sharedCache`物件從**步驟 2** 傳遞至階層 keyring。

   當您使用共用快取建立階層式 keyring 時，您可以選擇性地定義 ，`partitionID`以在多個階層式 keyring 之間共用快取項目。如果您未指定分割區 ID，階層式 keyring 會自動為 keyring 指派唯一的分割區 ID。
**注意**  
如果您建立兩個或多個參考相同分割區 ID、 和分支金鑰 ID 的 keyring[logical key store name](create-keystore.md#logical-key-store-name)，您的階層 keyring 將在共用快取中共用相同的快取項目。如果您不希望多個 keyring 共用相同的快取項目，則必須為每個階層 keyring 使用唯一的分割區 ID。

   下列範例會使用 建立階層式 keyring[branch key ID supplier](#branch-key-id-supplier)，快取[限制](#cache-limit)為 600 秒。如需下列階層式 keyring 組態中定義之值的詳細資訊，請參閱 [建立階層 keyring](#initialize-hierarchical-keyring)。

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

   ```
   // Create the Hierarchical keyring
   final CreateAwsKmsHierarchicalKeyringInput keyringInput =
       CreateAwsKmsHierarchicalKeyringInput.builder()
           .keyStore(keystore)
           .branchKeyIdSupplier(branchKeyIdSupplier)
           .ttlSeconds(600)
           .cache(sharedCache)
           .partitionID(partitionID)
           .build();        
   final IKeyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
   ```

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

   ```
   // Create the Hierarchical keyring        
   var createKeyringInput = new CreateAwsKmsHierarchicalKeyringInput
   {
      KeyStore = keystore,
      BranchKeyIdSupplier = branchKeyIdSupplier,
      Cache = sharedCache,
      TtlSeconds = 600,
      PartitionId = partitionID
   };
   var keyring = materialProviders.CreateAwsKmsHierarchicalKeyring(createKeyringInput);
   ```

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

   ```
   // Create the Hierarchical keyring
   let keyring1 = mpl
       .create_aws_kms_hierarchical_keyring()
       .key_store(key_store1)
       .branch_key_id(branch_key_id.clone())
       // CryptographicMaterialsCacheRef is an Rc (Reference Counted), so if you clone it to
       // pass it to different Hierarchical Keyrings, it will still point to the same
       // underlying cache, and increment the reference count accordingly.
       .cache(shared_cache.clone())
       .ttl_seconds(600)
       .partition_id(partition_id.clone())
       .send()
       .await?;
   ```

------

## 建立階層 keyring
<a name="initialize-hierarchical-keyring"></a>

若要建立階層 keyring，您必須提供下列值：
+ **金鑰存放區名稱**

  您或金鑰存放區管理員建立做為金鑰存放區的 DynamoDB 資料表名稱。
+ 

  **快取限制存留時間 (TTL)**

  分支金鑰材料項目在本機快取過期前可以使用的秒數。快取限制 TTL 決定用戶端呼叫 AWS KMS 以授權使用分支金鑰的頻率。該值必須大於零。快取限制 TTL 過期後，永遠不會提供項目，並且會從本機快取移出。
+ **分支金鑰識別符**

  您可以靜態設定 `branch-key-id`，以識別金鑰存放區中的單一作用中分支金鑰，或提供分支金鑰 ID 供應商。

  

  *分支金鑰 ID 供應商*會使用存放在加密內容中的欄位，來判斷解密記錄所需的分支金鑰。根據預設，加密內容中只會包含分割區和排序金鑰。不過，您可以使用`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`[密碼編譯動作](concepts.md#crypt-actions)，在加密內容中包含其他欄位。

  對於每個租用戶都有自己的分支金鑰的多租用戶資料庫，我們強烈建議使用分支金鑰 ID 供應商。您可以使用分支金鑰 ID 供應商為分支金鑰 IDs 建立易記的名稱，以便輕鬆識別特定租用戶的正確分支金鑰 ID。例如，易記名稱可讓您將分支金鑰稱為 ，`tenant1`而不是 `b3f61619-4d35-48ad-a275-050f87e15122`。

  對於解密操作，您可以靜態設定單一階層 keyring 將解密限制為單一租用戶，也可以使用分支金鑰 ID 供應商來識別負責解密記錄的租用戶。
+ **（選用） 快取**

  如果您想要自訂快取類型或可在本機快取中存放的分支金鑰材料項目數量，請在初始化 keyring 時指定快取類型和項目容量。

  階層式 keyring 支援下列快取類型：預設、MultiThreaded、StormTracking和共用。如需示範如何定義每個快取類型的詳細資訊和範例，請參閱 [選擇快取](#hierarchical-keyring-caches)。

  如果您未指定快取，階層式 keyring 會自動使用預設快取類型，並將進入容量設定為 1000。
+ **（選用） 分割區 ID**

  如果您指定 [共用快取](#cache-shared)，您可以選擇定義分割區 ID。分割區 ID 會區分要寫入快取的階層式 keyring。如果您想要重複使用或共用分割區中的快取項目，您必須定義自己的分割區 ID。您可以為分割區 ID 指定任何字串。如果您未指定分割區 ID，則會在建立時自動將唯一的分割區 ID 指派給 keyring。

  如需詳細資訊，請參閱[Partitions](#shared-cache-partitions)。
**注意**  
如果您建立兩個或多個參考相同分割區 ID、 和分支金鑰 ID 的 keyring[logical key store name](create-keystore.md#logical-key-store-name)，您的階層 keyring 將在共用快取中共用相同的快取項目。如果您不希望多個 keyring 共用相同的快取項目，則必須為每個階層 keyring 使用唯一的分割區 ID。
+ **（選用） 授予權杖的清單**

  如果您使用[授權](https://docs.aws.amazon.com/kms/latest/developerguide/grants.html)控制對階層式 keyring 中 KMS 金鑰的存取，您必須在初始化 keyring 時提供所有必要的授予權杖。

### 使用靜態分支金鑰 ID 建立階層 keyring
<a name="static-branch-key-id-config"></a>

下列範例示範如何建立具有靜態分支金鑰 ID、 [預設快取](#cache-default)和快取限制 TTL 600 秒的階層式 keyring。

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

```
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder()
        .keyStore(branchKeyStoreName)
        .branchKeyId(branch-key-id)
        .ttlSeconds(600)
        .build();
final Keyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

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

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
{
   KeyStore = keystore,
   BranchKeyIdSupplier = branchKeyIdSupplier,
   TtlSeconds = 600
};
var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

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

```
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

let hierarchical_keyring = mpl
    .create_aws_kms_hierarchical_keyring()
    .branch_key_id(branch_key_id)
    .key_store(branch_key_store_name)
    .ttl_seconds(600)
    .send()
    .await?;
```

------

### 使用分支金鑰 ID 供應商建立階層 keyring
<a name="branch-key-id-supplier-config"></a>

下列程序示範如何使用分支金鑰 ID 供應商建立階層 keyring。

1. 建立分支金鑰 ID 供應商

   下列範例會為**步驟 1 **中建立的兩個分支金鑰建立易記名稱，並使用 DynamoDB 用戶端的 AWS Database Encryption SDK 呼叫 來`CreateDynamoDbEncryptionBranchKeyIdSupplier`建立分支金鑰 ID 供應商。

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

   ```
   // Create friendly names for each branch-key-id 
   class ExampleBranchKeyIdSupplier implements IDynamoDbKeyBranchKeyIdSupplier {
       private static String branchKeyIdForTenant1;
       private static String branchKeyIdForTenant2;
   
       public ExampleBranchKeyIdSupplier(String tenant1Id, String tenant2Id) {
           this.branchKeyIdForTenant1 = tenant1Id;
           this.branchKeyIdForTenant2 = tenant2Id;
       }
   // Create the branch key ID supplier    
   final DynamoDbEncryption ddbEnc = DynamoDbEncryption.builder()
           .DynamoDbEncryptionConfig(DynamoDbEncryptionConfig.builder().build())
           .build();
   final BranchKeyIdSupplier branchKeyIdSupplier = ddbEnc.CreateDynamoDbEncryptionBranchKeyIdSupplier(
       CreateDynamoDbEncryptionBranchKeyIdSupplierInput.builder()
               .ddbKeyBranchKeyIdSupplier(new ExampleBranchKeyIdSupplier(branch-key-ID-tenant1, branch-key-ID-tenant2))
               .build()).branchKeyIdSupplier();
   ```

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

   ```
   // Create friendly names for each branch-key-id
    class ExampleBranchKeyIdSupplier : DynamoDbKeyBranchKeyIdSupplierBase {
       private String _branchKeyIdForTenant1;
       private String _branchKeyIdForTenant2;
   
       public ExampleBranchKeyIdSupplier(String tenant1Id, String tenant2Id) {
           this._branchKeyIdForTenant1 = tenant1Id;
           this._branchKeyIdForTenant2 = tenant2Id;
       }    
   // Create the branch key ID supplier
   var ddbEnc = new DynamoDbEncryption(new DynamoDbEncryptionConfig());
   var branchKeyIdSupplier = ddbEnc.CreateDynamoDbEncryptionBranchKeyIdSupplier(
       new CreateDynamoDbEncryptionBranchKeyIdSupplierInput
       {
           DdbKeyBranchKeyIdSupplier = new ExampleBranchKeyIdSupplier(branch-key-ID-tenant1, branch-key-ID-tenant2)
       }).BranchKeyIdSupplier;
   ```

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

   ```
   // Create friendly names for each branch_key_id
   pub struct ExampleBranchKeyIdSupplier {
       branch_key_id_for_tenant1: String,
       branch_key_id_for_tenant2: String,
   }
   
   impl ExampleBranchKeyIdSupplier {
       pub fn new(tenant1_id: &str, tenant2_id: &str) -> Self {
           Self {
               branch_key_id_for_tenant1: tenant1_id.to_string(),
               branch_key_id_for_tenant2: tenant2_id.to_string(),
           }
       }
   }
   
   // Create the branch key ID supplier                                        
   let dbesdk_config = DynamoDbEncryptionConfig::builder().build()?;
   let dbesdk = dbesdk_client::Client::from_conf(dbesdk_config)?;
   let supplier = ExampleBranchKeyIdSupplier::new(tenant1_branch_key_id, tenant2_branch_key_id);
   
   let branch_key_id_supplier = dbesdk
       .create_dynamo_db_encryption_branch_key_id_supplier()
       .ddb_key_branch_key_id_supplier(supplier)
       .send()
       .await?
       .branch_key_id_supplier
       .unwrap();
   ```

------

1. 建立階層 keyring

   下列範例會使用**步驟 1 **中建立的分支金鑰 ID 供應商初始化階層 keyring，快取限制 TLL 為 600 秒，快取大小上限為 1000。

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

   ```
   final MaterialProviders matProv = MaterialProviders.builder()
           .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
           .build();
   final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder()
           .keyStore(keystore)
           .branchKeyIdSupplier(branchKeyIdSupplier)
           .ttlSeconds(600)
           .cache(CacheType.builder() //OPTIONAL
                   .Default(DefaultCache.builder()
                   .entryCapacity(100)
                   .build())
           .build())
           .build();
   final Keyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
   ```

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

   ```
   var matProv = new MaterialProviders(new MaterialProvidersConfig());
   var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
   {
      KeyStore = keystore,
      BranchKeyIdSupplier = branchKeyIdSupplier,
      TtlSeconds = 600, 
      Cache = new CacheType
      {
           Default = new DefaultCache { EntryCapacity = 100 }
      }
   };
   var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
   ```

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

   ```
   let mpl_config = MaterialProvidersConfig::builder().build()?;
   let mpl = mpl_client::Client::from_conf(mpl_config)?;
   
   let hierarchical_keyring = mpl
       .create_aws_kms_hierarchical_keyring()
       .branch_key_id_supplier(branch_key_id_supplier)
       .key_store(key_store)
       .ttl_seconds(600)
       .send()
       .await?;
   ```

------

## 使用階層式 keyring 進行可搜尋的加密
<a name="searchable-encryption-hierarchical-keyrings"></a>

[可搜尋加密](searchable-encryption.md)可讓您在不解密整個資料庫的情況下搜尋加密的記錄。這可透過使用[信標](beacons.md)為加密欄位的純文字值編製索引來完成。若要實作可搜尋加密，您必須使用階層式 keyring。

金鑰存放區`CreateKey`操作會產生分支金鑰和*信標金鑰*。分支金鑰用於記錄加密和解密操作。信標金鑰用於產生信標。

分支金鑰和信標金鑰受到 AWS KMS key 您在建立金鑰存放區服務時指定的相同保護。`CreateKey` 操作呼叫 AWS KMS 以產生分支金鑰後，它會再次呼叫 [kms:GenerateDataKeyWithoutPlaintext](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyWithoutPlaintext.html)，以使用以下請求產生信標金鑰。

```
{
   "EncryptionContext": { 
      "branch-key-id" : "branch-key-id",
      "type" : type,
      "create-time" : "timestamp",
      "tablename" : "the logical table name for your key store",
      "kms-arn" : the KMS key ARN,
      "hierarchy-version" : 1
   },
   "KeyId": "the KMS key ARN",
   "NumberOfBytes": "32"
}
```

產生這兩個金鑰後， `CreateKey`操作會呼叫 [ddb：TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) 來寫入兩個新項目，以將分支金鑰和信標金鑰保留在您的分支金鑰存放區中。

當您[設定標準信標](configure-beacons.md#config-standard-beacons)時， AWS 資料庫加密 SDK 會查詢信標金鑰的金鑰存放區。然後，它會使用 HMAC extract-and-expand金鑰衍生函數 ([HKDF](https://en.wikipedia.org/wiki/HKDF)) 來結合信標金鑰與[標準信標](beacons.md#standard-beacon-overview)的名稱，為指定的信標建立 HMAC 金鑰。

與分支金鑰不同，金鑰存放區`branch-key-id`中每個 只有一個信標金鑰版本。信標金鑰永遠不會輪換。

### 定義您的信標金鑰來源
<a name="beacon-key-source"></a>

當您定義標準和複合信標的信標[版本](using-beacons.md#beacon-version)時，您必須識別信標金鑰，並定義信標金鑰資料的快取存留時間 (TTL)。信標金鑰資料會存放在與分支金鑰不同的本機快取中。下列程式碼片段示範如何`keySource`為單一租戶資料庫定義 。透過`branch-key-id`與其相關聯的 來識別您的信標金鑰。

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

```
keySource(BeaconKeySource.builder()
        .single(SingleKeyStore.builder()
                .keyId(branch-key-id)
                .cacheTTL(6000)
                .build())
        .build())
```

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

```
KeySource = new BeaconKeySource
{
    Single = new SingleKeyStore
    {
       KeyId = branch-key-id,
       CacheTTL = 6000
    }
}
```

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

```
 .key_source(BeaconKeySource::Single(
    SingleKeyStore::builder()
        // `keyId` references a beacon key.
        // For every branch key we create in the keystore,
        // we also create a beacon key.
        // This beacon key is not the same as the branch key,
        // but is created with the same ID as the branch key.
        .key_id(branch_key_id)
        .cache_ttl(6000)
        .build()?,
))
```

------

**在多租戶資料庫中定義信標來源**  
如果您有多租戶資料庫，您必須在設定 時指定下列值`keySource`。  
+ 

  **keyFieldName**

  定義存放與用於為指定租用戶產生信標之信標金鑰`branch-key-id`相關聯的 的欄位名稱。`keyFieldName` 可以是任何字串，但對於資料庫中的所有其他欄位必須是唯一的。當您將新記錄寫入資料庫時，識別用於為該記錄產生任何信標的`branch-key-id`信標金鑰的 會存放在此欄位中。您必須在信標查詢中包含此欄位，並識別重新計算信標所需的適當信標金鑰資料。如需詳細資訊，請參閱[查詢多租戶資料庫中的信標](searchable-encryption-multitenant.md#query-multitenant-beacons)。
+ **cacheTTL**

  本機信標快取內信標金鑰資料項目在過期前可以使用的秒數。該值必須大於零。當快取限制 TTL 過期時，會從本機快取移出項目。
+ **（選用） 快取**

  如果您想要自訂快取類型或可在本機快取中存放的分支金鑰材料項目數量，請在初始化 keyring 時指定快取類型和項目容量。

  階層式 keyring 支援下列快取類型：預設、MultiThreaded、StormTracking和共用。如需示範如何定義每個快取類型的詳細資訊和範例，請參閱 [選擇快取](#hierarchical-keyring-caches)。

  如果您未指定快取，階層式 keyring 會自動使用預設快取類型，並將進入容量設定為 1000。
下列範例會使用分支金鑰 ID 供應商建立階層 keyring，快取限制 TLL 為 600 秒，而進入容量為 1000。  

```
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder()
        .keyStore(branchKeyStoreName)
        .branchKeyIdSupplier(branchKeyIdSupplier)
        .ttlSeconds(600)
        .cache(CacheType.builder() //OPTIONAL
                .Default(DefaultCache.builder()
                        .entryCapacity(1000)
                        .build())
                .build());
final IKeyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
{
   KeyStore = keystore,
   BranchKeyIdSupplier = branchKeyIdSupplier,
   TtlSeconds = 600, 
   Cache = new CacheType
   {
        Default = new DefaultCache { EntryCapacity = 1000 }
   }
};
var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

```
let provider_config = MaterialProvidersConfig::builder().build()?;
    let mat_prov = client::Client::from_conf(provider_config)?;
    let kms_keyring = mat_prov
        .create_aws_kms_hierarchical_keyring()
        .branch_key_id(branch_key_id)
        .key_store(key_store)
        .ttl_seconds(600)
        .send()
        .await?;
```