

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

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

使用 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)，也可以一次儲存來自多個作用中分支金鑰的分支金鑰資料。

**注意**  
中提到的所有*階層式 keyring* AWS Encryption SDK 都參考 AWS KMS 階層式 keyring。

**程式設計語言相容性**  
下列程式設計語言和版本支援階層式 keyring：
+ 3.*x* 版 適用於 JAVA 的 AWS Encryption SDK
+  AWS Encryption SDK 適用於 .NET 的 4.*x* 版和更新版本
+ 4.*x* 版 適用於 Python 的 AWS Encryption SDK，與選用的 MPL 相依性搭配使用時。
+ for Rust 的 1.*x* AWS Encryption SDK 版
+ 適用於 Go 的 0.1.*x* AWS Encryption SDK 版或更新版本

**Topics**
+ [運作方式](#how-hierarchical-keyring-works)
+ [先決條件](#hierarchical-keyring-prereqs)
+ [所需的許可](#hierarchical-keyring-permissions)
+ [選擇快取](#hierarchical-keyring-caches)
+ [建立階層 keyring](#initialize-hierarchical-keyring)

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

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

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

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

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

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

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

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

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

加密方法使用加密資料來加密資料。如需詳細資訊，請參閱 [如何 AWS Encryption SDK 加密資料](how-it-works.md#encrypt-workflow)。

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

1. 解密方法會從加密的訊息識別加密的資料金鑰，並將其傳遞至階層式 keyring。

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

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

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 Encryption SDK 解密加密的訊息](how-it-works.md#decrypt-workflow)。

## 先決條件
<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 Encryption 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)

**重要**  
所有支援的快取類型都旨在支援多執行緒環境。  
不過，當 與 搭配使用時 適用於 Python 的 AWS Encryption SDK，階層式 keyring 不支援多執行緒環境。如需詳細資訊，請參閱 GitHub 上 [aws-cryptographic-material-providers-library](https://github.com/aws/aws-cryptographic-material-providers-library/tree/main) 儲存庫中的 [Python README.rst](https://github.com/aws/aws-cryptographic-material-providers-library/blob/main/AwsCryptographicMaterialProviders/runtimes/python/README.rst) 檔案。

### 預設快取
<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\# / .NET ]

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

------
#### [ Python ]

```
default_cache = CacheTypeDefault(
    value=DefaultCache(
        entry_capacity={{100}}
    )
)
```

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

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

------
#### [ Go ]

```
cache := mpltypes.CacheTypeMemberDefault{
		Value: mpltypes.DefaultCache{
			EntryCapacity: 100,
		},
	}
```

------

### 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\# / .NET ]

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

------
#### [ Python ]

```
multithreaded_cache = CacheTypeMultiThreaded(
    value=MultiThreadedCache(
        entry_capacity={{100}},
        entry_pruning_tail_size={{1}}
    )
)
```

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

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

------
#### [ Go ]

```
var entryPruningTailSize int32 = 1
	cache := mpltypes.CacheTypeMemberMultiThreaded{
		Value: mpltypes.MultiThreadedCache{
			EntryCapacity:        100,
			EntryPruningTailSize: &entryPruningTailSize,
		},
	}
```

------

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

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



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

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

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

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

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

  預設值：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\# / .NET ]

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

------
#### [ Python ]

```
storm_tracking_cache = CacheTypeStormTracking(
    value=StormTrackingCache(
        entry_capacity={{100}},
        entry_pruning_tail_size={{1}},
        fan_out={{20}},
        grace_interval={{1}},
        grace_period={{10}},
        in_flight_ttl={{10}},
        sleep_milli={{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()?)
```

------
#### [ Go ]

```
var entryPruningTailSize int32 = 1
	cache := mpltypes.CacheTypeMemberStormTracking{
		Value: mpltypes.StormTrackingCache{
			EntryCapacity:        100,
			EntryPruningTailSize: &entryPruningTailSize,
			GraceInterval:        1,
			GracePeriod:          10,
			FanOut:               20,
			InFlightTTL:          10,
			SleepMilli:           20,
		},
	}
```

------

### 共用快取
<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\# / .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);
   ```

------
#### [ Python ]

   ```
   # Instantiate the MPL
   mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
       config=MaterialProvidersConfig()
   )
   
   # Create a CacheType object for the default cache
   cache: CacheType = CacheTypeDefault(
       value=DefaultCache(
           entry_capacity=100,
       )
   )
   
   # Create a CMC using the default cache
   cryptographic_materials_cache_input = CreateCryptographicMaterialsCacheInput(
       cache=cache,
   )
   
   shared_cryptographic_materials_cache = mat_prov.create_cryptographic_materials_cache(
       cryptographic_materials_cache_input
   )
   ```

------
#### [ 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?;
   ```

------
#### [ Go ]

   ```
   import (
       "context"
       
   	mpl "aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated"
   	mpltypes "aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes"
   )
   
   // Instantiate the MPL
   matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{})
   if err != nil {
       panic(err)
   }
   
   // Create a CacheType object for the default cache
   cache := mpltypes.CacheTypeMemberDefault{
       Value: mpltypes.DefaultCache{
           EntryCapacity: 100,
       },
   }
   
   // Create a CMC using the default cache
   cmcCacheInput := mpltypes.CreateCryptographicMaterialsCacheInput{
       Cache: &cache,
   }
   sharedCryptographicMaterialsCache, err := matProv.CreateCryptographicMaterialsCache(context.Background(), cmcCacheInput)
   if err != nil {
       panic(err)
   }
   ```

------

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

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

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

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

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

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

------
#### [ Python ]

   ```
   # Create a CacheType object for the shared_cryptographic_materials_cache
   shared_cache: CacheType = CacheTypeShared(
       value=shared_cryptographic_materials_cache
   )
   ```

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

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

------
#### [ Go ]

   ```
   // Create a CacheType object for the shared_cryptographic_materials_cache
   shared_cache := mpltypes.CacheTypeMemberShared{sharedCryptographicMaterialsCache}
   ```

------

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\# / .NET ]

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

------
#### [ Python ]

   ```
   # Create the Hierarchical keyring
   keyring_input: CreateAwsKmsHierarchicalKeyringInput = CreateAwsKmsHierarchicalKeyringInput(
       key_store=keystore,
       branch_key_id_supplier=branch_key_id_supplier,
       ttl_seconds={{600}},
       cache=shared_cache,
       partition_id={{partition_id}}
   )
   
   hierarchical_keyring: IKeyring = mat_prov.create_aws_kms_hierarchical_keyring(
       input=keyring_input
   )
   ```

------
#### [ 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?;
   ```

------
#### [ Go ]

   ```
   // Create the Hierarchical keyring
   hkeyringInput := mpltypes.CreateAwsKmsHierarchicalKeyringInput{
       KeyStore:    keyStore1,
       BranchKeyId: &branchKeyId,
       TtlSeconds:  {{600}},
       Cache:       &shared_cache,
       PartitionId: {{&partitionId}},
   }
   keyring, err := matProv.CreateAwsKmsHierarchicalKeyring(context.Background(), hkeyringInput)
   if err != nil {
       panic(err)
   }
   ```

------

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

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

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

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

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

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

  

  *分支金鑰 ID 供應商*會使用存放在加密內容中的欄位，來判斷解密記錄所需的分支金鑰。

  對於每個租用戶都有自己的分支金鑰的多租用戶資料庫，我們強烈建議使用分支金鑰 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\# / .NET ]

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
{
   KeyStore = keystore,
   BranchKeyId = {{branch-key-id}},
   TtlSeconds = {{600}}
};
var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

------
#### [ Python ]

```
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
    config=MaterialProvidersConfig()
)

keyring_input: CreateAwsKmsHierarchicalKeyringInput = CreateAwsKmsHierarchicalKeyringInput(
    key_store=keystore,
    branch_key_id={{branch_key_id}},
    ttl_seconds={{600}}
)

hierarchical_keyring: IKeyring = mat_prov.create_aws_kms_hierarchical_keyring(
    input=keyring_input
)
```

------
#### [ 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()
        .key_store(key_store.clone())
        .branch_key_id({{branch_key_id}})
        .ttl_seconds({{600}})
        .send()
        .await?;
```

------
#### [ Go ]

```
matProv, err := mpl.NewClient(mpltypes.MaterialProvidersConfig{})
if err != nil {
    panic(err)
}
hkeyringInput := mpltypes.CreateAwsKmsHierarchicalKeyringInput{
    KeyStore:    keyStore,
    BranchKeyId: {{&branchKeyID}},
    TtlSeconds:  {{600}},
}
hKeyRing, err := matProv.CreateAwsKmsHierarchicalKeyring(context.Background(), hkeyringInput)
if err != nil {
    panic(err)
}
```

------

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

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

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

   下列範例會建立兩個分支金鑰的易記名稱，並呼叫 `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\# / .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;
   ```

------
#### [ Python ]

   ```
   # Create branch key ID supplier that maps the branch key ID to a friendly name
   branch_key_id_supplier: IBranchKeyIdSupplier = ExampleBranchKeyIdSupplier(
           tenant_1_id=branch_key_id_a,
           tenant_2_id=branch_key_id_b,
   )
   ```

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

   ```
   // Create branch key ID supplier that maps the branch key ID to a friendly name
   let branch_key_id_supplier = ExampleBranchKeyIdSupplier::new(
       &branch_key_id_a,
       &branch_key_id_b
   );
   ```

------
#### [ Go ]

   ```
   // Create branch key ID supplier that maps the branch key ID to a friendly name
   keySupplier := branchKeySupplier{branchKeyA: branchKeyA, branchKeyB: branchKeyB}
   ```

------

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();
   final Keyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
   ```

------
#### [ C\# / .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);
   ```

------
#### [ Python ]

   ```
   mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
       config=MaterialProvidersConfig()
   )
   
   keyring_input: CreateAwsKmsHierarchicalKeyringInput = CreateAwsKmsHierarchicalKeyringInput(
       key_store=keystore,
       branch_key_id_supplier=branch_key_id_supplier,
       ttl_seconds=600,
       cache=CacheTypeDefault(
           value=DefaultCache(
               entry_capacity=100
           )
       ),
   )
   
   hierarchical_keyring: IKeyring = mat_prov.create_aws_kms_hierarchical_keyring(
       input=keyring_input
   )
   ```

------
#### [ 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()
       .key_store(key_store.clone())
       .branch_key_id_supplier(branch_key_id_supplier)
       .ttl_seconds(600)
       .send()
       .await?;
   ```

------
#### [ Go ]

   ```
   hkeyringInput := mpltypes.CreateAwsKmsHierarchicalKeyringInput{
       KeyStore:            keyStore,
       BranchKeyIdSupplier: &keySupplier,
       TtlSeconds:          600,
   }
   hKeyRing, err := matProv.CreateAwsKmsHierarchicalKeyring(context.Background(), hkeyringInput)
   if err != nil {
       panic(err)
   }
   ```

------