You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
8.1 KiB
170 lines
8.1 KiB
[[mongo.encryption]] |
|
= Encryption (CSFLE) |
|
|
|
Client Side Encryption is a feature that encrypts data in your application before it is sent to MongoDB. |
|
We recommend you get familiar with the concepts, ideally from the https://www.mongodb.com/docs/manual/core/csfle/[MongoDB Documentation] to learn more about its capabilities and restrictions before you continue applying Encryption through Spring Data. |
|
|
|
[NOTE] |
|
==== |
|
Make sure to set the drivers `com.mongodb.AutoEncryptionSettings` to use client-side encryption. |
|
MongoDB does not support encryption for all field types. |
|
Specific data types require deterministic encryption to preserve equality comparison functionality. |
|
==== |
|
|
|
[[mongo.encryption.automatic]] |
|
== Automatic Encryption |
|
|
|
MongoDB supports https://www.mongodb.com/docs/manual/core/csfle/[Client-Side Field Level Encryption] out of the box using the MongoDB driver with its Automatic Encryption feature. |
|
Automatic Encryption requires a xref:mongodb/mapping/mapping-schema.adoc[JSON Schema] that allows to perform encrypted read and write operations without the need to provide an explicit en-/decryption step. |
|
|
|
Please refer to the xref:mongodb/mapping/mapping-schema.adoc#mongo.jsonSchema.encrypted-fields[JSON Schema] section for more information on defining a JSON Schema that holds encryption information. |
|
|
|
To make use of a the `MongoJsonSchema` it needs to be combined with `AutoEncryptionSettings` which can be done eg. via a `MongoClientSettingsBuilderCustomizer`. |
|
|
|
[source,java] |
|
---- |
|
@Bean |
|
MongoClientSettingsBuilderCustomizer customizer(MappingContext mappingContext) { |
|
return (builder) -> { |
|
|
|
// ... keyVaultCollection, kmsProvider, ... |
|
|
|
MongoJsonSchemaCreator schemaCreator = MongoJsonSchemaCreator.create(mappingContext); |
|
MongoJsonSchema patientSchema = schemaCreator |
|
.filter(MongoJsonSchemaCreator.encryptedOnly()) |
|
.createSchemaFor(Patient.class); |
|
|
|
AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder() |
|
.keyVaultNamespace(keyVaultCollection) |
|
.kmsProviders(kmsProviders) |
|
.extraOptions(extraOpts) |
|
.schemaMap(Collections.singletonMap("db.patient", patientSchema.schemaDocument().toBsonDocument())) |
|
.build(); |
|
|
|
builder.autoEncryptionSettings(autoEncryptionSettings); |
|
}; |
|
} |
|
---- |
|
|
|
[[mongo.encryption.explicit]] |
|
== Explicit Encryption |
|
|
|
Explicit encryption uses the MongoDB driver's encryption library (`org.mongodb:mongodb-crypt`) to perform encryption and decryption tasks. |
|
The `@ExplicitEncrypted` annotation is a combination of the `@Encrypted` annotation used for xref:mongodb/mapping/mapping-schema.adoc#mongo.jsonSchema.encrypted-fields[JSON Schema creation] and a xref:mongodb/mapping/property-converters.adoc[Property Converter]. |
|
In other words, `@ExplicitEncrypted` uses existing building blocks to combine them for simplified explicit encryption support. |
|
|
|
[NOTE] |
|
==== |
|
Fields annotated with `@ExplicitEncrypted` are always encrypted as whole. |
|
Consider the following example: |
|
|
|
[source,java] |
|
---- |
|
@ExplicitEncrypted(…) |
|
String simpleValue; <1> |
|
|
|
@ExplicitEncrypted(…) |
|
Address address; <2> |
|
|
|
@ExplicitEncrypted(…) |
|
List<...> list; <3> |
|
|
|
@ExplicitEncrypted(…) |
|
Map<..., ...> mapOfString; <4> |
|
---- |
|
|
|
<1> Encrypts the value of the simple type such as a `String` if not `null`. |
|
<2> Encrypts the entire `Address` object and all its nested fields as `Document`. |
|
To only encrypt parts of the `Address`, like `Address#street` the `street` field within `Address` needs to be annotated with `@ExplicitEncrypted`. |
|
<3> ``Collection``-like fields are encrypted as single value and not per entry. |
|
<4> ``Map``-like fields are encrypted as single value and not as a key/value entry. |
|
==== |
|
|
|
Client-Side Field Level Encryption allows you to choose between a deterministic and a randomized algorithm. Depending on the https://www.mongodb.com/docs/v5.0/reference/security-client-side-automatic-json-schema/#std-label-field-level-encryption-json-schema/[chosen algorithm], https://www.mongodb.com/docs/manual/core/csfle/reference/supported-operations/[different operations] may be supported. |
|
To pick a certain algorithm use `@ExplicitEncrypted(algorithm)`, see `EncryptionAlgorithms` for algorithm constants. |
|
Please read the https://www.mongodb.com/docs/manual/core/csfle/fundamentals/encryption-algorithms[Encryption Types] manual for more information on algorithms and their usage. |
|
|
|
To perform the actual encryption we require a Data Encryption Key (DEK). |
|
Please refer to the https://www.mongodb.com/docs/manual/core/csfle/quick-start/#create-a-data-encryption-key[MongoDB Documentation] for more information on how to set up key management and create a Data Encryption Key. |
|
The DEK can be referenced directly via its `id` or a defined _alternative name_. |
|
The `@EncryptedField` annotation only allows referencing a DEK via an alternative name. |
|
It is possible to provide an `EncryptionKeyResolver`, which will be discussed later, to any DEK. |
|
|
|
.Reference the Data Encryption Key |
|
==== |
|
[source,java] |
|
---- |
|
@EncryptedField(algorithm=…, altKeyName = "secret-key") <1> |
|
String ssn; |
|
---- |
|
|
|
[source,java] |
|
---- |
|
@EncryptedField(algorithm=…, altKeyName = "/name") <2> |
|
String ssn; |
|
---- |
|
|
|
<1> Use the DEK stored with the alternative name `secret-key`. |
|
<2> Uses a field reference that will read the actual field value and use that for key lookup. |
|
Always requires the full document to be present for save operations. |
|
Fields cannot be used in queries/aggregations. |
|
==== |
|
|
|
By default, the `@ExplicitEncrypted(value=…)` attribute references a `MongoEncryptionConverter`. |
|
It is possible to change the default implementation and exchange it with any `PropertyValueConverter` implementation by providing the according type reference. |
|
To learn more about custom `PropertyValueConverters` and the required configuration, please refer to the xref:mongodb/mapping/property-converters.adoc[Property Converters - Mapping specific fields] section. |
|
|
|
[[mongo.encryption.explicit-setup]] |
|
=== MongoEncryptionConverter Setup |
|
|
|
The converter setup for `MongoEncryptionConverter` requires a few steps as several components are involved. |
|
The bean setup consists of the following: |
|
|
|
1. The `ClientEncryption` engine |
|
2. A `MongoEncryptionConverter` instance configured with `ClientEncryption` and a `EncryptionKeyResolver`. |
|
3. A `PropertyValueConverterFactory` that uses the registered `MongoEncryptionConverter` bean. |
|
|
|
A side effect of using annotated key resolution is that the `@ExplicitEncrypted` annotation does not need to specify an alt key name. |
|
The `EncryptionKeyResolver` uses an `EncryptionContext` providing access to the property allowing for dynamic DEK resolution. |
|
|
|
.Sample MongoEncryptionConverter Configuration |
|
==== |
|
[source,java] |
|
---- |
|
class Config extends AbstractMongoClientConfiguration { |
|
|
|
@Autowired ApplicationContext appContext; |
|
|
|
@Bean |
|
ClientEncryption clientEncryption() { <1> |
|
ClientEncryptionSettings encryptionSettings = ClientEncryptionSettings.builder(); |
|
// … |
|
|
|
return ClientEncryptions.create(encryptionSettings); |
|
} |
|
|
|
@Bean |
|
MongoEncryptionConverter encryptingConverter(ClientEncryption clientEncryption) { |
|
|
|
Encryption<BsonValue, BsonBinary> encryption = MongoClientEncryption.just(clientEncryption); |
|
EncryptionKeyResolver keyResolver = EncryptionKeyResolver.annotated((ctx) -> …); <2> |
|
|
|
return new MongoEncryptionConverter(encryption, keyResolver); <3> |
|
} |
|
|
|
@Override |
|
protected void configureConverters(MongoConverterConfigurationAdapter adapter) { |
|
|
|
adapter |
|
.registerPropertyValueConverterFactory(PropertyValueConverterFactory.beanFactoryAware(appContext)); <4> |
|
} |
|
} |
|
---- |
|
|
|
<1> Set up a `Encryption` engine using `com.mongodb.client.vault.ClientEncryption`. |
|
The instance is stateful and must be closed after usage. |
|
Spring takes care of this because `ClientEncryption` is ``Closeable``. |
|
<2> Set up an annotation-based `EncryptionKeyResolver` to determine the `EncryptionKey` from annotations. |
|
<3> Create the `MongoEncryptionConverter`. |
|
<4> Enable for a `PropertyValueConverter` lookup from the `BeanFactory`. |
|
====
|
|
|