配置 AWS 数据库加密 SDK - AWS 数据库加密 SDK

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

配置 AWS 数据库加密 SDK

我们的客户端加密库已重命名为 AWS 数据库加密SDK。本开发人员指南仍提供有关 DynamoDB 加密客户端的信息。

AWS 数据库加密设计SDK为易于使用。尽管 AWS 数据库加密SDK有多个配置选项,但默认值是经过精心选择的,以便对大多数应用程序既实用又安全。但是,您可能需要调整配置以提高性能或在设计中加入自定义功能。

选择编程语言

Dynam SDK oDB 的 AWS 数据库加密有多种编程语言版本。语言实现旨在实现完全互操作并提供相同的功能,尽管这些功能可能以不同的方式实现。通常,您使用与您的应用程序兼容的库。

选择包装密钥

AWS 数据库加密SDK生成一个唯一的对称数据密钥来加密每个字段。您不需要配置、管理或使用数据密钥。 AWS 数据库加密可以为您SDK做到这一点。

但是,必须选择一个或多个包装密钥来加密每个数据密钥。 AWS 数据库加密SDK支持 AWS Key Management Service(AWS KMS) 对称加密KMS密钥和非对称RSAKMS密钥。它还支持AES您提供的不同大小的RSA对称密钥和非对称密钥。您应对包装密钥的安全性和耐用性负责,因此我们建议您在硬件安全模块或密钥基础设施服务(例如)中使用加密密钥 AWS KMS。

要指定用于加密和解密的包装密钥,您可以使用密钥环。根据您使用的密钥环类型,您可以指定一个包装密钥或多个相同或不同类型的包装密钥。如果您使用多个包装密钥来包装一个数据密钥,则每个包装密钥将加密同一数据密钥的副本。加密的数据密钥(每个包装密钥一个)与加密的字段一起存储在材料描述中。要解密数据, AWS 数据库加密SDK必须首先使用您的一个包装密钥来解密加密的数据密钥。

我们建议尽可能使用其中一个 AWS KMS 钥匙圈。 AWS 数据库加密SDK提供了密AWS KMS 钥环AWS KMS 分层密钥环,这减少了对的调用次数。 AWS KMS要在密钥环 AWS KMS key 中指定,请使用支持的 AWS KMS 密钥标识符。如果使用 AWS KMS 分层密钥环,则必须指定密钥ARN。有关密钥的密钥标识符的 AWS KMS 详细信息,请参阅《AWS Key Management Service 开发人员指南》中的密钥标识符

  • 使用密 AWS KMS 钥环加密时,可以为对称加密KMS密钥指定任何有效的密钥标识符(密ARN钥ARN、别名、别名或密钥 ID)。如果您使用非对称RSAKMS密钥,则必须指定密钥ARN。

    如果您在加密时ARN为KMS密钥指定别名或别名,则 AWS 数据库加密会SDK保存ARN当前与该别名关联的密钥;它不会保存别名。对别名的更改不会影响用于解密数据密KMS钥的密钥。

  • 默认情况下,密 AWS KMS 钥环在严格模式(您指定特定KMS密钥)下解密记录。您必须使用密钥来识别ARN才能 AWS KMS keys 进行解密。

    当您使用密 AWS KMS 钥环加密时, AWS 数据库加密会将ARN的密钥与加密的数据密钥一起SDK存储 AWS KMS key 在材料描述中。在严格模式下解密时, AWS 数据库加密在尝试使用包装密钥解密加密的数据密钥之前,会SDK验证密钥环中是否ARN出现相同的密钥。如果您使用不同的密钥标识符,即使标识符引用相同的密钥 AWS KMS key, AWS 数据库加密SDK也无法识别或使用。

  • 发现模式下解密时,不需指定任何包装密钥。首先, AWS 数据库加密SDK尝试使用ARN存储在材料描述中的密钥来解密记录。如果这不起作用,则 AWS 数据库加密SDK会 AWS KMS 要求使用加密记录的密KMS钥解密记录,无论谁拥有或有权访问该KMS密钥。

要将原始AES密钥原始RSA密钥对指定为密钥环中的包装密钥,必须指定命名空间和名称。解密时,必须为每个原始包装密钥使用与加密时完全相同的命名空间和名称。如果您使用不同的命名空间或名称,即使密钥材料相同, AWS 数据库加密SDK也无法识别或使用包装密钥。

创建发现筛选条件

解密使用密KMS钥加密的数据时,最佳做法是在严格模式下解密,也就是说,将封装密钥限制为仅使用您指定的密钥。但是,如有必要,您也可以在发现模式下解密,在这种模式下,您无需指定任何包装密钥。在此模式下, AWS KMS 无论谁拥有或有权访问该密钥,都可以使用加密KMS密钥的密钥对加密数据密钥进行解密。KMS

如果您必须在发现模式下解密,我们建议您始终使用发现过滤器,该过滤器将可以使用的KMS密钥限制为指定 AWS 账户 和分区中的密钥。发现筛选条件是可选的,但这是最佳实践。

使用下表确定发现筛选条件的分区值。

区域 分区
AWS 区域 aws
中国区域 aws-cn
AWS GovCloud (US) Regions aws-us-gov

以下示例说明如何创建发现过滤器。在使用代码之前,请将示例值替换为 AWS 账户 和分区的有效值。

Java
// Create the discovery filter DiscoveryFilter discoveryFilter = DiscoveryFilter.builder() .partition("aws") .accountIds(111122223333) .build();
C# / .NET
var discoveryFilter = new DiscoveryFilter { Partition = "aws", AccountIds = 111122223333 };

使用多租户数据库

使用 AWS 数据库加密SDK,您可以使用不同的加密材料隔离每个租户,从而为具有共享架构的数据库配置客户端加密。在考虑多租户数据库时,请花点时间查看您的安全要求以及多租户可能会如何影响这些要求。例如,使用多租户数据库可能会影响您将 AWS 数据库加密与其他服务器端加密SDK解决方案结合使用的能力。

如果您有多个用户在数据库中执行加密操作,则可以使用其中一个 AWS KMS 密钥环为每个用户提供一个用于其加密操作的不同密钥。管理多租户客户端加密解决方案的数据密钥可能会很复杂。建议尽可能按租户来组织数据。如果租户由主键值(例如,Amazon DynamoDB 表中的分区键)标识,则可以更加轻松地管理密钥。

您可以使用AWS KMS 密钥环使用不同的密钥 AWS KMS 环隔离每个租户,然后. AWS KMS keys根据每个租户的 AWS KMS 呼叫量,您可能需要使用 AWS KMS 分层密钥环来最大限度地减少对的呼叫。 AWS KMSAWS KMS 分层密钥环是一种加密材料缓存解决方案,它使用 AWS KMS 保存在Amazon DynamoDB表中的受保护分支密钥,然后在本地缓存用于加密和解密操作的分支密钥材料,从而减少 AWS KMS 调用次数。必须使用 AWS KMS 分层密钥环在数据库中实现可搜索的加密

创建签名的信标

AWS 数据库加密SDK使用标准信标和复合信来提供可搜索的加密解决方案,使您无需解密所查询的整个数据库即可搜索加密记录。但是, AWS 数据库加密SDK还支持签名信标,这些信标可以完全从纯文本签名字段进行配置。签名信标是一种复合信标,用于对和SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT字段进行索引SIGN_ONLY和执行复杂查询。

举例来说,如果您有多租户数据库,则可能需要创建一个签名信标,使您能够在数据库中查询由特定租户密钥加密的记录。有关更多信息,请参阅 查询多租户数据库中的信标

必须使用 AWS KMS 分层密钥环来创建签名的信标。

要配置签名的信标,请提供以下值。

Java

复合信标配置

以下示例在已签名的信标配置中本地定义已签名部件列表。

List<CompoundBeacon> compoundBeaconList = new ArrayList<>(); CompoundBeacon exampleCompoundBeacon = CompoundBeacon.builder() .name("compoundBeaconName") .split(".") .signed(signedPartList) .constructors(constructorList) .build(); compoundBeaconList.add(exampleCompoundBeacon);

信标版本定义

以下示例在信标版本中全局定义了已签名的部件列表。有关定义信标版本的更多信息,请参阅使用信标。

List<BeaconVersion> beaconVersions = new ArrayList<>(); beaconVersions.add( BeaconVersion.builder() .standardBeacons(standardBeaconList) .compoundBeacons(compoundBeaconList) .signedParts(signedPartList) .version(1) // MUST be 1 .keyStore(keyStore) .keySource(BeaconKeySource.builder() .single(SingleKeyStore.builder() .keyId(branchKeyId) .cacheTTL(6000) .build()) .build()) .build() );
C# / .NET

查看完整的代码示例BeaconConfig.cs

签名信标配置

以下示例在已签名的信标配置中本地定义已签名部件列表。

var compoundBeaconList = new List<CompoundBeacon>(); var exampleCompoundBeacon = new CompoundBeacon { Name = "compoundBeaconName", Split = ".", Signed = signedPartList, Constructors = constructorList }; compoundBeaconList.Add(exampleCompoundBeacon);

信标版本定义

以下示例在信标版本中全局定义了已签名的部件列表。有关定义信标版本的更多信息,请参阅使用信标。

var beaconVersions = new List<BeaconVersion> { new BeaconVersion { StandardBeacons = standardBeaconList, CompoundBeacons = compoundBeaconList, SignedParts = signedPartsList, Version = 1, // MUST be 1 KeyStore = keyStore, KeySource = new BeaconKeySource { Single = new SingleKeyStore { KeyId = branchKeyId, CacheTTL = 6000 } } } };

您可以在本地或全局定义的列表中定义已签名的部件。我们建议尽可能在信标版本的全局列表中定义已签名的部件。通过全局定义带符号的部件,您可以定义每个零件一次,然后在多个复合信标配置中重复使用这些部件。如果您只打算使用一次签名部件,则可以在已签名信标配置的本地列表中对其进行定义。你可以在构造函数列表中同时引用局部和全局部分。

如果您在全局范围内定义已签名部件列表,则必须提供构造器部件列表,这些构造器部分标识已签名信标可以在信标配置中组合字段的所有可能方式。

注意

要全局定义已签名部件列表,必须使用 3.2 或更高版本的 AWS 数据库加密SDK。在全局定义任何新部分之前,先将新版本部署给所有读者。

您无法更新现有信标配置以全局定义已签名部件列表。

信标名称

查询信标时使用的名称。

已签名的信标名称不能与未加密的字段相同。任何两个信标的名称都不能相同。

分割字符

用于分隔构成签名信标的各个部分的字符。

分割字符不能出现在构成签名信标的任何字段的明文值中。

签名部分列表

标识签名信标中包含的签名字段。

每个部分都必须包含名称、来源和前缀。来源是部件标识的SIGN_ONLYSIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT字段。来源必须是字段名称或引用嵌套字段值的索引。如果您的部件名称标识了来源,则可以省略来源, AWS 数据库加密SDK将自动使用该名称作为其来源。建议尽可能将来源指定为部分名称。前缀可以是任何字符串,但它必须是唯一的。签名信标中任何两个已签名的部分都不能具有相同的前缀。建议使用简短的值,以将该部分与复合信标提供的其他部分区分开来。

我们建议尽可能在全局范围内定义您的签名部件。如果您只打算在一个复合信标中使用签名部件,则可以考虑在本地定义签名部件。本地定义的部件不能与全局定义的部件具有相同的前缀或名称。

Java
List<SignedPart> signedPartList = new ArrayList<>); SignedPart signedPartExample = SignedPart.builder() .name("signedFieldName") .prefix("S-") .build(); signedPartList.add(signedPartExample);
C# / .NET
var signedPartsList = new List<SignedPart> { new SignedPart { Name = "signedFieldName1", Prefix = "S-" }, new SignedPart { Name = "signedFieldName2", Prefix = "SF-" } };
构造器列表(可选)

标识定义签名信标汇编签名部分的不同方式的构造函数

如果未指定构造函数列表,则 AWS 数据库加密会使用以下默认构造函数SDK组装签名的信标。

  • 所有已签名的部分均按添加到已签名部分列表的顺序排列

  • 所有部分均为必填项

构造函数

每个构造函数都是构造函数部分的有序列表,该列表定义了签名信标的一种汇编方式。构造函数部分按照添加到列表中的顺序连接在一起,其每个部分由指定的分割字符分隔。

每个构造函数部分都会命名签名部分,并定义该部分在构造函数中是必填项还是可选项。例如,如果要在 Field1Field1.Field2Field1.Field2.Field3 上查询签名信标,请将 Field2Field3 标记为可选并创建一个构造函数。

每个构造函数必须具有至少一个必需部分。建议将每个构造函数的第一部分设为必填项,这样您就可以在查询中使用 BEGINS_WITH 运算符。

如果一个构造函数的所有必需部分都存在于记录中,则该构造函数成功。当您编写一条新记录时,签名信标使用构造函数列表来确定信标是否可以根据提供的值进行汇编。它尝试按照构造函数添加到构造函数列表的顺序汇编信标,并使用第一个成功的构造函数。如果任何构造函数都没有成功,则信标不会写入记录。

所有的读取者和写入者都应指定相同的构造函数顺序,以确保其查询结果正确无误。

使用以下过程指定您自己的构造函数列表。

  1. 为每个签名部分创建一个构造函数部分,以定义该部分是否为比填项。

    构造函数部分名称必须是签名字段的名称。

    以下示例演示如何为一个签名字段创建构造函数部分。

    Java
    ConstructorPart field1ConstructorPart = ConstructorPart.builder() .name("Field1") .required(true) .build();
    C# / .NET
    var field1ConstructorPart = new ConstructorPart { Name = "Field1", Required = true };
  2. 使用您在步骤 1 中创建的构造函数部分为汇编签名信标的每种可能方式创建构造函数。

    例如,如果您要查询 Field1.Field2.Field3Field4.Field2.Field3,则必须创建两个构造函数。Field1Field4 都可以是必填项,因为它们是在两个单独的构造函数中定义的。

    Java
    // Create a list for Field1.Field2.Field3 queries List<ConstructorPart> field123ConstructorPartList = new ArrayList<>(); field123ConstructorPartList.add(field1ConstructorPart); field123ConstructorPartList.add(field2ConstructorPart); field123ConstructorPartList.add(field3ConstructorPart); Constructor field123Constructor = Constructor.builder() .parts(field123ConstructorPartList) .build(); // Create a list for Field4.Field2.Field1 queries List<ConstructorPart> field421ConstructorPartList = new ArrayList<>(); field421ConstructorPartList.add(field4ConstructorPart); field421ConstructorPartList.add(field2ConstructorPart); field421ConstructorPartList.add(field1ConstructorPart); Constructor field421Constructor = Constructor.builder() .parts(field421ConstructorPartList) .build();
    C# / .NET
    // Create a list for Field1.Field2.Field3 queries var field123ConstructorPartList = new Constructor { Parts = new List<ConstructorPart> { field1ConstructorPart, field2ConstructorPart, field3ConstructorPart } }; // Create a list for Field4.Field2.Field1 queries var field421ConstructorPartList = new Constructor { Parts = new List<ConstructorPart> { field4ConstructorPart, field2ConstructorPart, field1ConstructorPart } };
  3. 创建一个构造函数列表,其中包含您在步骤 2 中创建的所有构造函数。

    Java
    List<Constructor> constructorList = new ArrayList<>(); constructorList.add(field123Constructor) constructorList.add(field421Constructor)
    C# / .NET
    var constructorList = new List<Constructor> { field123Constructor, field421Constructor };
  4. 在创建签名信标时指定 constructorList