

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

# AWS KMS 分层钥匙圈
<a name="use-hierarchical-keyring"></a>

使用 AWS KMS 分层密钥环，您可以在对称加密 KMS 密钥下保护您的加密材料，而无需在 AWS KMS 每次加密或解密数据时都调用。对于需要最大限度地减少调用的应用程序以及可以在不违反其安全要求的情况下重复使用某些加密材料的应用程序来说，这是一个不错的选择。 AWS KMS

分层密钥环是一种加密材料缓存解决方案，它使用 AWS KMS 保存在Amazon DynamoDB表中的受保护*分支密钥*，然后在本地缓存用于加密和解密操作的分支密钥材料，从而减少 AWS KMS 调用次数。DynamoDB 表用作管理和保护分支密钥的密钥存储。其存储活动分支密钥和分支密钥的所有先前版本。*活动*分支密钥为最新分支密钥版本。分层密钥环使用唯一的数据密钥来加密每条消息，并对每个加密请求的每个数据加密密钥进行加密，并使用从活动分支密钥派生的唯一包装密钥对每个数据加密密钥进行加密。分层密钥环依赖在活动分支密钥及其派生包装密钥之间建立的层次结构。

分层密钥环通常使用各分支密钥版本满足多个请求。但是您可以控制活动分支密钥的重复使用程度，并确定活动分支密钥的轮换频率。在您[轮换](rotate-branch-key.md)之前，分支密钥的活动版本会一直处于活动状态。活动分支密钥的先前版本不会用于执行加密操作，但仍可查询并用于解密操作。

当您实例化分层密钥环时，分层密钥环会创建本地缓存。您可以指定[缓存限制](#cache-limit)，该限制定义了分支密钥材料在过期并从缓存中移出之前存储在本地缓存中的最长时间。首次在操作中指定 a `branch-key-id` 时，分层密钥环会 AWS KMS 调用解密分支密钥并组装分支密钥材料。然后，分支密钥材料存储在本地缓存中，并重复用于所有指定 `branch-key-id` 的加密和解密操作，直至缓存限制到期。将分支密钥材料存储在本地缓存中可以减少 AWS KMS 调用。例如，假设缓存限制为 15 分钟。如果您在该缓存限制内执行 10,000 次加密操作，则[传统 AWS KMS 密钥环](use-kms-keyring.md)需要进行 10,000 次 AWS KMS 调用才能满足 10,000 次加密操作。如果您有一个处于活动状态`branch-key-id`，则分层密钥环只需要进行一次 AWS KMS 调用即可满足 10,000 个加密操作。

本地缓存将加密材料与解密材料分开。加密材料由活动分支密钥组合而成，并在缓存限制到期之前重复用于所有加密操作。解密材料是根据在加密字段的元数据中标识的分支密钥 ID 和版本汇编而成的，在缓存限制到期之前，它们可以重复用于与分支密钥 ID 和版本相关的所有解密操作。本地缓存可以一次存储同一个分支密钥的多个版本。将本地缓存配置为使用时[branch key ID supplier](#branch-key-id-supplier)，它还可以同时存储来自多个活动分支密钥的分支密钥材料。

**注意**  
中所有提及分*层密钥环*的 AWS Encryption SDK 内容均指 AWS KMS 分层密钥环。

**编程语言兼容性**  
以下编程语言和版本支持分层密钥环：
+ 版本 3。 的 *x* AWS Encryption SDK for Java
+ 版本 4。 .NET 的 *x* 及更高版本 AWS Encryption SDK 
+ 版本 4。 的 *x* AWS Encryption SDK for Python，当与可选的 MPL 依赖项一起使用时。
+ 版本 1。 *x 的 fo* r AWS Encryption SDK Rust
+ 版本 0.1。 *x* 或更高版本的 fo AWS Encryption SDK r Go

**Topics**
+ [工作原理](#how-hierarchical-keyring-works)
+ [先决条件](#hierarchical-keyring-prereqs)
+ [所需的权限](#hierarchical-keyring-permissions)
+ [选择缓存](#hierarchical-keyring-caches)
+ [创建分层密钥环](#initialize-hierarchical-keyring)

## 工作原理
<a name="how-hierarchical-keyring-works"></a>

以下演练描述了分层密钥环如何汇编加密和解密材料，以及密钥环对加密和解密操作的不同调用。有关包装密钥派生和明文数据密钥加密过程的技术详细信息，请参阅 [AWS KMS 分层密钥环技术详细信息](hierarchical-keyring-details.md)。

**加密并签名**  
以下演练描述了分层密钥环如何汇编加密材料并派生出唯一的包装密钥。

1. 加密方法要求分层密钥环提供加密材料。密钥环生成明文数据密钥，然后检查本地缓存中是否存在有效分支材料可供生成包装密钥。如果存在有效的分支密钥材料，则密钥环将进入**步骤 4**。

1. 如果没有有效的分支密钥材料，则分层密钥环会在密钥库中查询活动分支密钥。

   1. 密钥库调用 AWS KMS 解密活动分支密钥并返回纯文本活动分支密钥。标识活动分支密钥的数据会进行序列化，以便在解密调用 AWS KMS时提供额外验证数据。

   1. 密钥库返回纯文本分支密钥和标识该密钥的数据，例如分支密钥版本。

1. 分层密钥环汇编分支密钥材料（明文分支密钥和分支密钥版本），并将其副本存储在本地缓存中。

1. 分层密钥环从明文分支密钥和一个 16 字节的随机加密盐中派生出唯一的包装密钥。其使用派生包装密钥加密明文数据密钥的副本。

此加密方法使用加密材料加密数据。有关更多信息，请参阅[如何 AWS Encryption SDK 加密数据。](how-it-works.md#encrypt-workflow)

**解密并验证**  
以下演练描述了分层密钥环如何组装解密材料并解密加密数据密钥。

1. 该解密方法标识来自加密消息的加密数据密钥，并将其传递给分层密钥环。

1. 分层密钥环反序列化标识加密数据密钥的数据，包括分支密钥版本、16 字节的加密盐以及其他描述数据密钥加密方式的信息。

   有关更多信息，请参阅 [AWS KMS 分层钥匙圈技术细节](hierarchical-keyring-details.md)。

1. 分层密钥环会检查本地缓存中是否存在与**步骤 2** 标识的分支密钥版本相匹配的有效分支密钥材料。如果存在有效分支密钥材料，则密钥环将进入**步骤 6**。

1. 如果没有有效的分支密钥材料，则分层密钥环会在密钥库中查询与**步骤 2** 中确定的分支密钥版本相匹配的分支密钥。

   1. 密钥库调用 AWS KMS 解密分支密钥并返回纯文本活动分支密钥。标识活动分支密钥的数据会进行序列化，以便在解密调用 AWS KMS时提供额外验证数据。

   1. 密钥库返回纯文本分支密钥和标识该密钥的数据，例如分支密钥版本。

1. 分层密钥环汇编分支密钥材料（明文分支密钥和分支密钥版本），并将其副本存储在本地缓存中。

1. 分层密钥环使用汇编的分支密钥材料和**步骤 2** 标识的 16 字节加密盐重现加密数据密钥的唯一包装密钥。

1. 分层密钥环使用重现的包装密钥解密数据密钥并返回明文数据密钥。

该解密方法使用解密材料和明文数据密钥解密加密消息。有关更多信息，请参阅[如何 AWS Encryption SDK 解密加密邮件](how-it-works.md#decrypt-workflow)。

## 先决条件
<a name="hierarchical-keyring-prereqs"></a>

在创建和使用分层密钥环之前，请确保满足以下先决条件。
+ 您或您的密钥库管理员已[创建密钥库](create-keystore.md)并[创建了至少一个有效的分支密钥](create-branch-keys.md)。
+ 您已经[配置了密钥存储操作](keystore-actions.md#config-keystore-actions)。
**注意**  
如何配置密钥存储操作决定了您可以执行的操作以及分层密钥环可以使用哪些 KMS 密钥。有关更多信息，请参阅[密钥存储操作](keystore-actions.md)。
+ 您拥有访问和使用密钥库和分支密钥所需的 AWS KMS 权限。有关更多信息，请参阅 [所需的权限](#hierarchical-keyring-permissions)。
+ 您已经查看了支持的缓存类型并配置了最适合您需求的缓存类型。有关更多信息，请参阅 [选择缓存](#hierarchical-keyring-caches)。

## 所需的权限
<a name="hierarchical-keyring-permissions"></a>

 AWS Encryption SDK 不需要 AWS 账户 ，也不依赖于任何一个 AWS 服务。但是，要使用分层密钥环，您需要对 AWS 账户 密钥库中的对称加密 AWS KMS key具有以下最低权限。
+ [要使用分层密钥环加密和解密数据，你需要 kms: Decrypt。](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)
+ 要[创建](create-branch-keys.md)和[轮换](rotate-branch-key.md)分支密钥，你需要 k [ms: 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>

分层密钥环 AWS KMS 通过在本地缓存加密和解密操作中使用的分支密钥材料来减少调用的次数。在[创建分层密钥环](#initialize-hierarchical-keyring)之前，您需要决定要使用的缓存类型。您可以使用默认缓存或自定义缓存以最适合您的需求。

分层密钥环支持以下缓存类型：
+ [默认缓存](#cache-default)
+ [MultiThreaded 缓存](#cache-multithreaded)
+ [StormTracking 缓存](#cache-stormtracking)
+ [共享缓存](#cache-shared)

**重要**  
所有支持的缓存类型都旨在支持多线程环境。  
但是，与一起使用时 AWS Encryption SDK for Python，分层密钥环不支持多线程环境。有关更多信息，请参阅上的 [aws-cryptographic-material-providers-](https://github.com/aws/aws-cryptographic-material-providers-library/tree/main) library 存储库中的 [Python README.rst](https://github.com/aws/aws-cryptographic-material-providers-library/blob/main/AwsCryptographicMaterialProviders/runtimes/python/README.rst) 文件。 GitHub

### 默认缓存
<a name="cache-default"></a>

对于大多数用户而言，默认缓存可满足其线程要求。默认缓存用于支持超多线程环境。当分支密钥材料条目过期时，默认缓存会 AWS KMS 提前 10 秒通知一个线程分支密钥材料条目将过期，从而防止多个线程调用。这样可以确保只有一个线程向发送刷新缓存的请求。 AWS KMS 

默认和 StormTracking 缓存支持相同的线程模型，但您只需要指定入口容量即可使用默认缓存。要进行更精细的缓存自定义，请使用。[StormTracking 缓存](#cache-stormtracking)

除非要自定义可以存储在本地缓存中的分支密钥材料条目的数量，否则在创建分层密钥环时无需指定缓存类型。如果未指定缓存类型，则分层密钥环使用默认缓存类型并将条目容量设置为 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 秒
+ **宽限间隔**：定义两次尝试刷新分支密钥材料间隔的秒数。

  默认值：1 秒
+ **扇出**：定义可以同时尝试刷新分支密钥材料的次数。

  默认值：20 次尝试
+ **传输中生存时间（TTL）**：定义在分支密钥材料刷新尝试超时之前的秒数。每当缓存为响应 `GetCacheEntry` 而返回 `NoSuchEntry` 时，分支密钥均视为*传输中*，直至相同密钥与 `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>

默认情况下，每次实例化密钥环时，分层密钥环都会创建一个新的本地缓存。但是，共享缓存允许您在多个分层密钥环之间共享缓存，从而有助于节省内存。共享缓存不是为您实例化的每个分层密钥环创建新的加密材料缓存，而是在内存中只存储一个缓存，供所有引用它的分层密钥环使用。共享缓存可避免密钥环之间重复加密材料，从而帮助优化内存使用率。相反，分层密钥环可以访问相同的底层缓存，从而减少总体内存占用。

创建共享缓存时，仍需要定义缓存类型。您可以指定[默认缓存](#cache-default)[MultiThreaded 缓存](#cache-multithreaded)、或[StormTracking 缓存](#cache-stormtracking)作为缓存类型，也可以替换任何兼容的自定义缓存。



**分区**  
多个分层密钥环可以使用单个共享缓存。使用共享缓存创建分层密钥环时，可以定义可选的**分区 ID**。分区 ID 可区分哪个分层密钥环正在写入缓存。如果两个分层密钥环引用相同的分区 ID 和分支密钥 ID[logical key store name](create-keystore.md#logical-key-store-name)，则两个密钥环将在缓存中共享相同的缓存条目。如果您创建了两个具有相同共享缓存但分区不同的分层密钥环 IDs，则每个密钥环只能访问共享缓存中自己指定的分区中的缓存条目。分区充当共享缓存中的逻辑分区，允许每个分层密钥环在自己的指定分区上独立运行，而不会干扰存储在另一个分区中的数据。

如果您打算重复使用或共享分区中的缓存条目，则必须定义自己的分区 ID。当您将分区 ID 传递给分层密钥环时，密钥环可以重复使用共享缓存中已存在的缓存条目，而不必再次检索和重新授权分支密钥材料。如果您未指定分区 ID，则每次实例化分层密钥环时，都会自动为密钥环分配一个唯一的分区 ID。

以下过程演示如何创建[默认缓存类型的共享缓存](#cache-default)并将其传递给分层密钥环。

1. 使用[材料提供者库 `CryptographicMaterialsCache`](https://github.com/aws/aws-cryptographic-material-providers-library) (MPL) 创建 (CMC)。

------
#### [ 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. 将**步骤 2** 中的`sharedCache`对象传递到分层密钥环。

   使用共享缓存创建分层密钥环时，可以选择定义一个`partitionID`以在多个分层密钥环之间共享缓存条目。如果您未指定分区 ID，则分层密钥环会自动为密钥环分配一个唯一的分区 ID。
**注意**  
如果您创建两个或更多引用相同分区 ID 和分支密钥 ID 的密钥环，则分层密钥环将在共享缓存中共享相同的缓存条目。[logical key store name](create-keystore.md#logical-key-store-name)如果您不希望多个密钥环共享相同的缓存条目，则必须为每个分层密钥环使用唯一的分区 ID。

   以下示例创建了一个分层密钥环[branch key ID supplier](#branch-key-id-supplier)，其[缓存限制为](#cache-limit) 600 秒。有关以下分层密钥环配置中定义的值的更多信息，请参阅[创建分层密钥环](#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)
   }
   ```

------

## 创建分层密钥环
<a name="initialize-hierarchical-keyring"></a>

要创建分层密钥环，必须提供以下值：
+ **密钥库名称**

  您或您的密钥库管理员创建的用作密钥存储的 DynamoDB 表的名称。
+ 

  **缓存限制生存时间（TTL）**

  本地缓存中的分支密钥材料条目在过期之前可使用的时长（以秒为单位）。缓存限制 TTL 决定了客户端调 AWS KMS 用授权使用分支密钥的频率。该值必须大于零。缓存限制 TTL 到期后，该条目将永远不会被提供，并将从本地缓存中逐出。
+ **分支密钥标识符**

  您可以静态配置用于标识密钥库中单个活动分支密钥的，也可以提供分支密钥 ID 供应商。`branch-key-id`

  

  *分支密钥 ID 提供*者使用存储在加密上下文中的字段来确定解密记录需要哪个分支密钥。

  对于每个租户都有自己的分支密钥的多租户数据库，我们强烈建议使用分支密钥 ID 供应商。您可以使用分支密钥 ID 供应商为分支密钥创建友好名称， IDs 以便轻松识别特定租户的正确分支密钥 ID。例如，易记名称使您可以将分支密钥引用为 `tenant1` 而非 `b3f61619-4d35-48ad-a275-050f87e15122`。

  对于解密操作，您可以静态配置单个分层密钥环以限制对单个租户进行解密，也可以使用分支密钥 ID 提供程序确定哪个租户负责解密记录。
+ **（可选）缓存**

  如果要自定义缓存类型或可存储在本地缓存中分支密钥材料条目的数量，请在初始化密钥环时指定缓存类型和条目容量。

  分层密钥环支持以下缓存类型：默认、 MultiThreaded StormTracking、和共享。有关演示如何定义每种缓存类型的更多信息和示例，请参阅[选择缓存](#hierarchical-keyring-caches)。

  如果未指定缓存，则分层密钥环会自动使用默认缓存类型并将条目容量设置为 1000。
+ **（可选）分区 ID**

  如果指定[共享缓存](#cache-shared)，则可以选择定义分区 ID。分区 ID 可区分哪个分层密钥环正在写入缓存。如果您打算重复使用或共享分区中的缓存条目，则必须定义自己的分区 ID。您可以为分区 ID 指定任何字符串。如果您未指定分区 ID，则会在创建密钥环时自动为密钥环分配一个唯一的分区 ID。

  有关更多信息，请参阅 [Partitions](#shared-cache-partitions)。
**注意**  
如果您创建两个或更多引用相同分区 ID 和分支密钥 ID 的密钥环，则分层密钥环将在共享缓存中共享相同的缓存条目。[logical key store name](create-keystore.md#logical-key-store-name)如果您不希望多个密钥环共享相同的缓存条目，则必须为每个分层密钥环使用唯一的分区 ID。
+ **（可选）授权令牌列表**

  如果您通过[授权](https://docs.aws.amazon.com/kms/latest/developerguide/grants.html)控制对分层密钥环中 KMS 密钥的访问权限，则必须在初始化密钥环时提供所有必要的授权令牌。

### 使用静态分支密钥 ID 创建分层密钥环
<a name="static-branch-key-id-config"></a>

以下示例演示如何创建具有静态分支密钥 ID、缓存限制 TTL 为 600 秒的分层密钥环。[默认缓存](#cache-default)

------
#### [ 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 供应商创建分层密钥环
<a name="branch-key-id-supplier-config"></a>

以下过程演示如何使用分支密钥 ID 提供者创建分层密钥环。

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. 创建分层密钥环

   以下示例使用**步骤 1** 中创建的分支密钥 ID 供应商初始化分层密钥环，缓存限制 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)
   }
   ```

------