加密密钥管理
在本指南中,您可以了解如何使用密钥管理系统(KMS)管理您的客户端字段级加密(CSFLE)启用应用程序中的加密密钥。
加密组件
MongoDB使用以下组件执行客户端字段级加密
数据加密密钥(DEK)
客户主密钥(CMK)
密钥库集合
密钥管理系统(KMS)
有关密钥和密钥库的更多信息,请参阅加密密钥和密钥库.
支持的关键管理服务
客户端字段级加密支持以下密钥管理系统提供商
Amazon Web Services KMS
Azure Key Vault
Google Cloud KMS
任何符合KMIP的密钥管理系统
本地密钥提供者
默认的KMIP协议版本为1.2。您可以在MongoDB服务器配置文件中配置使用KMIP版本1.0或1.1。配置文件。
要了解更多关于这些提供者的信息,包括显示应用程序如何使用它们进行客户端字段级加密的图表,请参阅KMS提供者。
管理数据加密密钥的备用名称
您可以为数据加密密钥分配备用名称,以便更容易地引用。分配备用名称允许您执行以下操作
通过除DEK字段的
_id
字段以外的其他方式引用。在运行时动态分配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
对象的信息,请参阅KMS提供者。
在自动加密方案中使用备用密钥名称
加密方案包含用户指定的规则,用于标识哪些字段必须加密以及如何加密这些字段。在您的加密规则中,您可以指定用于加密字段的密钥的备用密钥名称。
您必须使用一个JSON指针
来引用密钥的备用名称。JSON指针是一个以“/”字符为前缀的字符串,可以用来访问同一文档或另一个文档中的特定字段值。使用JSON指针来引用包含您的密钥备用名称值的查询或更新文档中的字段。
重要
不能为确定性加密字段使用备用名称
在加密字段时,您不能通过其备用名称引用DEK。要使用确定性加密算法加密字段,您必须指定用于加密字段的密钥的_id
。
在加密方案中引用密钥备用名称
考虑以下加密方案,该方案加密了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
对象的信息,请参阅支持的关键管理服务。
删除数据加密密钥
您可以使用标准CRUD 删除操作从密钥库集合中删除数据加密密钥。如果您删除了DEK,则使用该DEK加密的所有字段将永久不可读。
提示
MongoDB Shell特定功能
MongoDB Shell允许您使用UUID
通过keyVault.deleteKey()
方法删除DEK,如下所示
keyVault = db.getKeyVault() keyVault.deleteKey(UUID("<UUID String>"))
有关密钥库集合的更多信息,请参阅加密密钥和密钥库。
了解更多
有关如何设置支持的各种KMS提供商的CSFLE启用应用程序的教程,请参阅以下页面
要查看加密方案的更多示例,请参阅CSFLE加密方案。