加密密钥管理
在此页面上
本指南中,您可以了解如何在启用“客户端字段级加密”(CSFLE) 的应用程序中使用“密钥管理系统”(KMS) 管理加密密钥。
加密组件
MongoDB 使用以下组件来执行客户端字段级加密:
数据加密密钥 (DEK)
客户主密钥 (CMK)
密钥保管库集合
密钥管理系统 (KMS)
要了解有关密钥和密钥保管库的更多信息,请参阅密钥与密钥保管库。
支持的密钥管理服务
客户端字段级加密支持以下密钥管理系统提供程序:
Amazon Web Services KMS
Azure Key Vault
Google Cloud KMS
任何符合 KMIP 的密钥管理系统
本地密钥提供程序(仅供测试)
默认 KMIP 协议版本是 1.2。您可以在 MongoDB 服务器的配置文件中将 MongoDB 配置为使用 KMIP 1.0 或 1.1 版本。
要了解有关这些提供程序的详情,包括展示应用程序如何使用它们来执行客户端字段级加密的图表,请参阅 CSFLE KMS 提供程序。
使用远程密钥管理系统的原因
较之使用本地文件系统来托管 CMK,使用远程密钥管理系统来管理客户主密钥具有以下优势:
安全存储密钥并进行访问审核
降低了访问权限问题的风险
密钥对远程客户端的可用性以及将密钥分发给远程客户端
自动密钥备份和恢复
集中加密密钥生命周期管理
此外,对于以下 KMS 提供程序,KMS 会远程加密和解密您的数据加密密钥,确保客户主密钥绝不会暴露给启用 CSFLE 的应用程序:
Amazon Web Services KMS
Azure Key Vault
Google Cloud KMS
管理数据加密密钥的备用名称
您可以为数据加密密钥指定备用名称,以方便应用密钥。通过指定备用名称,您可以执行以下操作:
以不同于
_id
字段的方式引用 DEK。在运行时动态分配 DEK。
使用备用名称创建数据加密密钥
重要
先决条件
在添加新的密钥备用名称之前,您必须在 keyAltNames
字段上创建部分唯一索引。对于存在 keyAltNames
的文档,该索引应具有 partialFilterExpression
。
客户端字段级加密取决于服务器强制执行的密钥备用名称的唯一性。
如需了解如何创建部分索引,请参阅“部分索引”。
以下示例创建具有备用名称的数据加密密钥。 选择与您的驱动程序语言相对应的标签页:
var autoEncryptionOpts = { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, }; var encryptedClient = Mongo( connectionString, autoEncryptionOpts ); var clientEncryption = encryptedClient.getClientEncryption(); var masterKey = { "<Your dataKeyOpts Key>": "<Your dataKeyOpts Value>", }; var keyVault = encryptedClient.getKeyVault(); var keyId = keyVault.createKey("aws", masterKey, ["<Your Key Alt Name>"]);
var keyVaultClient = new MongoClient(connectionString); var clientEncryptionOptions = new ClientEncryptionOptions( keyVaultClient: keyVaultClient, keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders); var clientEncryption = new ClientEncryption(clientEncryptionOptions); var dataKeyOptions = new DataKeyOptions( alternateKeyNames: new[] { "<Your Key Alt Name>" }, masterKey: new BsonDocument { { "<Your dataKeyOpts Keys>", "<Your dataKeyOpts Values>" }, }); var dataKeyId = clientEncryption.CreateDataKey("<Your KMS Provider>", dataKeyOptions, CancellationToken.None);
clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(KeyVaultNamespace).SetKmsProviders(kmsProviders) keyVaultClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(URI)) if err != nil { return fmt.Errorf("Client connect error %v", err) } clientEnc, err := mongo.NewClientEncryption(keyVaultClient, clientEncryptionOpts) if err != nil { return fmt.Errorf("NewClientEncryption error %v", err) } defer func() { _ = clientEnc.Close(context.TODO()) }() masterKey := map[string]interface{}{ "<Your dataKeyOpts Key>": "<Your dataKeyOpts Value>", } dataKeyOpts := options.DataKey(). SetMasterKey(masterKey). SetKeyAltNames([]string{"<Your Key Alt Name>"}) dataKeyID, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts) if err != nil { return fmt.Errorf("create data key error %v", err) }
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder() .keyVaultMongoClientSettings(MongoClientSettings.builder() .applyConnectionString(new ConnectionString(connectionString)) .build()) .keyVaultNamespace(keyVaultNamespace) .kmsProviders(kmsProviders) .build(); ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings); BsonDocument masterKeyProperties = new BsonDocument(); masterKeyProperties.put("provider", new BsonString("<Your KMS Provider>")); masterKeyProperties.put("<Your dataKeyOpts Key>", new BsonString("<Your dataKeyOpts Value>")); List keyAltNames = new ArrayList<String>(); keyAltNames.add("<Your Key Alt Name>"); BsonBinary dataKeyId = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions().masterKey(masterKeyProperties).keyAltNames(keyAltNames));
const encryption = new ClientEncryption(client, { keyVaultNamespace, kmsProviders, }); const masterKey = { "<Your dataKeyOpts Key>": "<Your dataKeyOpts Value>", }; const key = await encryption.createDataKey(provider, { masterKey: masterKey, keyAltNames: ["<Your Key Alt Name>"], });
client = MongoClient(connection_string) client_encryption = ClientEncryption( kms_providers, key_vault_namespace, client, CodecOptions(uuid_representation=STANDARD), ) master_key={ "<Your dataKeyOpts Key>" : "<Your dataKeyOpts Value>"} data_key_id = client_encryption.create_data_key(provider, master_key, key_alt_names=["<Your Key Alt Name>"])
要了解有关 dataKeyOpts
和 kmsProviders
对象的详情,请参阅 CSFLE KMS 提供程序。
在自动加密模式中使用密钥备用名称
加密模式包含用户指定的规则,用于指定必须加密哪些字段以及如何加密这些字段。在加密规则中,您可以为加密字段的数据加密密钥指定备用密钥名称。
您必须使用 JSON 指针引用密钥备用名称。JSON 指针是一个以 "/"
字符为前缀的字符串,可用于访问同一文档或另一个文档中的特定字段值。可以使用 JSON 指针引用查询或更新文档中包含密钥备用名称值的字段。
加密模式中的参考密钥备用名称
考虑以下对 salary
字段加密的加密模式:
{ "<database>.<collection>": { "bsonType": "object", "properties": { "salary": { "encrypt": { "bsonType": "int", "keyId": "/fieldWithAltName", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" } } } } }
该模式的 keyId
字段包含了 JSON 指针,用于引用正在加密的文档中的 fieldWithAltName
字段。
以下文档的 fieldWithAltName
值为 my-alt-name
:
{ "name": "Jon Doe", "salary": 45000, "fieldWithAltName": "my-alt-name" }
salary
字段由备用名称为 my-alt-name
的 DEK 加密。
在运行时动态分配密钥
您可以使用备用密钥名称,在运行时动态设置字段的“数据加密密钥”。使用此功能,可以使用相同的加密模式,用不同的 DEK 加密单个文档。
例如,考虑以下文档:
{ "name": "Jon Doe", "salary": 45000, "fieldWithAltName": "my-alt-name" }, { "name": "Jane Smith", "salary": 70000, "fieldWithAltName": "my-other-alt-name" }
您可以使用启用 CSFLE 的客户端插入上述文档,该客户端配置有上一个示例中的加密模式。
在加密模式中,salary.encrypt.keyId
字段包含指向插入的文档的 fieldWithAltName
字段的 JSON 指针。因此,两个示例文档中的 salary
字段使用各自文档特定的 DEK 进行加密。这些密钥是在运行时动态分配的。
程序:使用 Mongo Shell 轮换加密密钥
对于 Mongo Shell 1.5 和更高版本,您可以使用 rewrapManyDataKey
方法轮换加密密钥。rewrapManyDataKey
方法自动解密多个数据密钥,并使用指定的客户主密钥重新加密这些密钥。然后,它在密钥保管库集合中更新轮换的密钥。这种方法允许您根据两个可选参数轮换加密密钥:
用于指定要轮换的密钥的筛选器。如果没有与给定筛选器匹配的数据密钥,则不会轮换任何密钥。省略筛选器可轮换密钥保管库集合中的所有密钥。
表示新 CMK 的对象。可以省略该对象以使用当前 CMK 轮换数据密钥。
rewrapManyDataKey
使用以下事务语法:
keyVault = db.getKeyVault() keyVault.rewrapManyDataKey( { "<Your custom filter>" }, { provider: "<KMS provider>", masterKey: { "<dataKeyOpts Key>" : "<dataKeyOpts Value>" } } )
如需进一步了解 KMS 提供商的 dataKeyOpts
对象,请参阅“支持密钥管理服务”。
删除数据加密密钥
您可以使用标准增删改查操作中的删除操作将数据加密密钥从密钥保管库集合中删除。如果删除了 DEK,使用该 DEK 加密的所有字段将永久不可读。
提示
MongoDB Shell 特定功能
MongoDB Shell 允许您使用 keyVault.deleteKey()
方法通过 UUID
删除 DEK,如下所示:
keyVault = db.getKeyVault() keyVault.deleteKey(UUID("<UUID String>"))
如需了解有关“密钥保管库集合”的更多信息,请参阅“密钥保管库集合”。
了解详情
有关详细介绍如何使用每个支持的 KMS 提供程序设置支持 CSFLE 的应用程序的教程,请参阅以下页面:
如需查看加密模式的其他示例,请参阅“CSFLE 加密模式”。