Skip to content

Commit d8c0a62

Browse files
terakilobyteChris Cho
andauthored
csfle (#51)
csfle Co-authored-by: Chris Cho <[email protected]>
1 parent a773621 commit d8c0a62

File tree

3 files changed

+316
-0
lines changed

3 files changed

+316
-0
lines changed

source/fundamentals/csfle.txt

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
==================================
2+
Client-Side Field Level Encryption
3+
==================================
4+
5+
.. default-domain:: mongodb
6+
7+
Client-Side Field Level Encryption (CSFLE) allows you to encrypt
8+
specific data fields within a document with your MongoDB client application before sending the data to the server.
9+
Starting in MongoDB 4.2 Enterprise, you can perform this client-side encryption automatically.
10+
11+
With CSFLE, your client application encrypts fields client-side without requiring any server-side configuration or
12+
directives. CSFLE is useful for situations in which applications must guarantee that unauthorized parties, including
13+
server administrators, cannot read the encrypted data.
14+
15+
This guide is a quick introduction to CSFLE using the Java driver. For in-depth information on how CSFLE works, see
16+
the :manual:`CSFLE reference </core/security-client-side-encryption/>` documentation. For a real-world scenario and
17+
implementation, see our `CSFLE Guide <https://docs.mongodb.com/drivers/security/client-side-field-level-encryption-guide>`_.
18+
19+
Installation
20+
------------
21+
22+
To get started with CSFLE in your client application, you need
23+
24+
- the MongoDB Java driver
25+
- ``mongodb-crypt``
26+
- ``mongocryptd`` if using automatic encryption (Enterprise or Atlas)
27+
28+
``mongodb-crypt``
29+
~~~~~~~~~~~~~~~~~
30+
31+
The ``mongodb-crypt`` binding is available as a separate JAR. Add it to your project using your desired dependency
32+
management tool.
33+
34+
.. tabs::
35+
36+
.. tab:: Maven
37+
:tabid: maven
38+
39+
.. include:: /includes/fundamentals/code-snippets/libmongocrypt-maven-versioned.rst
40+
41+
.. tab:: Gradle
42+
:tabid: gradle
43+
44+
.. include:: /includes/fundamentals/code-snippets/libmongocrypt-gradle-versioned.rst
45+
46+
47+
``mongocryptd``
48+
~~~~~~~~~~~~~~~
49+
50+
``mongocryptd`` is a binary run as a daemon / process that is used for automatic encryption.
51+
``mongodb-crypt`` communicates with ``mongocryptd`` to automatically encrypt the information specified by a user-provided
52+
:manual:`JSON Schema </reference/security-client-side-automatic-json-schema/>`.
53+
54+
For more detailed information on ``mongocryptd``, see the
55+
:manual:`mongocryptd reference documentation </reference/security-client-side-encryption-appendix/#mongocryptd>`
56+
57+
58+
Examples
59+
--------
60+
61+
The examples on this page use a local key, but you can also use integrated support for cloud-based key management
62+
services from AWS, Azure, and GCP. Each example program execution creates a new master key in memory and drops the
63+
``test.coll`` collection.
64+
65+
.. tip::
66+
67+
In the examples, the in-memory master key is lost when the application finishes running. If you'd like to retain
68+
and decrypt documents from previous runs, you can save the local master key to a file for reuse and remove the logic
69+
to drop the collection.
70+
71+
.. warning::
72+
73+
MongoDB recommends using local key management only for testing purposes, and using a remote key management service
74+
for production.
75+
76+
Automatic Encryption and Decryption
77+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78+
79+
The following example shows how to configure the ``AutoEncryptionSettings`` instance to create a new key and set the
80+
JSON schema map.
81+
82+
The data in the ``encryptedField`` field is automatically encrypted before insertion, and decrypted when calling ``find()``
83+
on the client side. Querying this collection from a client that isn't configured for CSFLE will return the document in
84+
encrypted form.
85+
86+
The full source is available at
87+
`ClientSideEncryptionAutoEncryptionSettingsTour.java <https://github.com/mongodb/mongo-java-driver/blob/master/driver-sync/src/examples/tour/ClientSideEncryptionAutoEncryptionSettingsTour.java>`_
88+
89+
.. note::
90+
91+
Auto encryption requires MongoDB **Enterprise** or **Atlas**.
92+
93+
.. code-block:: java
94+
95+
import com.mongodb.AutoEncryptionSettings;
96+
import com.mongodb.ClientEncryptionSettings;
97+
import com.mongodb.ConnectionString;
98+
import com.mongodb.MongoClientSettings;
99+
import com.mongodb.client.MongoClient;
100+
import com.mongodb.client.MongoClients;
101+
import com.mongodb.client.MongoCollection;
102+
import com.mongodb.client.model.vault.DataKeyOptions;
103+
import com.mongodb.client.vault.ClientEncryption;
104+
import com.mongodb.client.vault.ClientEncryptions;
105+
import org.bson.BsonBinary;
106+
import org.bson.BsonDocument;
107+
import org.bson.Document;
108+
109+
import java.security.SecureRandom;
110+
import java.util.Base64;
111+
import java.util.HashMap;
112+
import java.util.Map;
113+
114+
public class ClientSideEncryptionAutoEncryptionSettingsTour {
115+
116+
/**
117+
* Run this main method to see the output of this quick example.
118+
*
119+
* Requires the mongodb-crypt library in the class path and mongocryptd on the system path.
120+
* Assumes the schema has already been created in MongoDB.
121+
*
122+
* @param args ignored args
123+
*/
124+
public static void main(final String[] args) {
125+
126+
// This would have to be the same master key as was used to create the encryption key
127+
final byte[] localMasterKey = new byte[96];
128+
new SecureRandom().nextBytes(localMasterKey);
129+
130+
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>() {{
131+
put("local", new HashMap<String, Object>() {{
132+
put("key", localMasterKey);
133+
}});
134+
}};
135+
136+
String keyVaultNamespace = "admin.datakeys";
137+
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
138+
.keyVaultMongoClientSettings(MongoClientSettings.builder()
139+
.applyConnectionString(new ConnectionString("mongodb://localhost"))
140+
.build())
141+
.keyVaultNamespace(keyVaultNamespace)
142+
.kmsProviders(kmsProviders)
143+
.build();
144+
145+
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
146+
BsonBinary dataKeyId = clientEncryption.createDataKey("local", new DataKeyOptions());
147+
final String base64DataKeyId = Base64.getEncoder().encodeToString(dataKeyId.getData());
148+
149+
final String dbName = "test";
150+
final String collName = "coll";
151+
AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder()
152+
.keyVaultNamespace(keyVaultNamespace)
153+
.kmsProviders(kmsProviders)
154+
.schemaMap(new HashMap<String, BsonDocument>() {{
155+
put(dbName + "." + collName,
156+
// Need a schema that references the new data key
157+
BsonDocument.parse("{"
158+
+ " properties: {"
159+
+ " encryptedField: {"
160+
+ " encrypt: {"
161+
+ " keyId: [{"
162+
+ " \"$binary\": {"
163+
+ " \"base64\": \"" + base64DataKeyId + "\","
164+
+ " \"subType\": \"04\""
165+
+ " }"
166+
+ " }],"
167+
+ " bsonType: \"string\","
168+
+ " algorithm: \"AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic\""
169+
+ " }"
170+
+ " }"
171+
+ " },"
172+
+ " \"bsonType\": \"object\""
173+
+ "}"));
174+
}}).build();
175+
176+
MongoClientSettings clientSettings = MongoClientSettings.builder()
177+
.autoEncryptionSettings(autoEncryptionSettings)
178+
.build();
179+
180+
MongoClient mongoClient = MongoClients.create(clientSettings);
181+
MongoCollection<Document> collection = mongoClient.getDatabase("test").getCollection("coll");
182+
collection.drop(); // Clear old data
183+
184+
collection.insertOne(new Document("encryptedField", "9876564321"));
185+
186+
System.out.println(collection.find().first().toJson());
187+
188+
// release resources
189+
mongoClient.close();
190+
}
191+
}
192+
193+
Explicit Encryption and Decryption
194+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
195+
196+
The prior example demonstrated the automatic CSFLE feature. If your version of MongoDB does not offer automatic CSFLE,
197+
you can perform manual client-side field level encryption, which we call *explicit* encryption. This method does not
198+
require or use ``mongocryptd``. The ``ClientEncryption`` class contains methods you can use to perform explicit
199+
encryption.
200+
201+
This example prints out the document in encrypted form, and prints out the explicitly decrypted field value to demonstrate
202+
functionality.
203+
204+
The full source is available from
205+
`ClientSideEncryptionExplicitEncryptionAndDecryptionTour.java <https://github.com/mongodb/mongo-java-driver/tree/master/driver-sync/src/examples/tour/ClientSideEncryptionExplicitEncryptionAndDecryptionTour.java>`_
206+
207+
.. code-block:: java
208+
209+
// This would have to be the same master key as was used to create the encryption key
210+
final byte[] localMasterKey = new byte[96];
211+
new SecureRandom().nextBytes(localMasterKey);
212+
213+
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>() {{
214+
put("local", new HashMap<String, Object>() {{
215+
put("key", localMasterKey);
216+
}});
217+
}};
218+
219+
MongoClientSettings clientSettings = MongoClientSettings.builder().build();
220+
MongoClient mongoClient = MongoClients.create(clientSettings);
221+
222+
// Set up the key vault for this example
223+
MongoNamespace keyVaultNamespace = new MongoNamespace("encryption.testKeyVault");
224+
MongoCollection<Document> keyVaultCollection = mongoClient
225+
.getDatabase(keyVaultNamespace.getDatabaseName())
226+
.getCollection(keyVaultNamespace.getCollectionName());
227+
keyVaultCollection.drop();
228+
229+
// Ensure that two data keys cannot share the same keyAltName.
230+
keyVaultCollection.createIndex(Indexes.ascending("keyAltNames"),
231+
new IndexOptions().unique(true)
232+
.partialFilterExpression(Filters.exists("keyAltNames")));
233+
234+
MongoCollection<Document> collection = mongoClient.getDatabase("test").getCollection("coll");
235+
collection.drop(); // Clear old data
236+
237+
// Create the ClientEncryption instance
238+
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
239+
.keyVaultMongoClientSettings(MongoClientSettings.builder()
240+
.applyConnectionString(new ConnectionString("mongodb://localhost"))
241+
.build())
242+
.keyVaultNamespace(keyVaultNamespace.getFullName())
243+
.kmsProviders(kmsProviders)
244+
.build();
245+
246+
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
247+
248+
BsonBinary dataKeyId = clientEncryption.createDataKey("local", new DataKeyOptions());
249+
250+
// Explicitly encrypt a field
251+
BsonBinary encryptedFieldValue = clientEncryption.encrypt(new BsonString("123456789"),
252+
new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId));
253+
254+
collection.insertOne(new Document("encryptedField", encryptedFieldValue));
255+
256+
Document doc = collection.find().first();
257+
System.out.println(doc.toJson());
258+
259+
// Explicitly decrypt the field
260+
System.out.println(
261+
clientEncryption.decrypt(new BsonBinary(doc.get("encryptedField", Binary.class).getData()))
262+
);
263+
264+
Explicit Encryption and Auto Decryption
265+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
266+
267+
Although automatic encryption requires MongoDB Enterprise or MongoDB Atlas, automatic decryption is
268+
available in all MongoDB versions greater than or equal to 4.2.
269+
270+
To configure automatic decryption, set ``bypassAutoEncryption(true)`` in the ``autoEncryptionSettings`` builder.
271+
272+
The following example prints the inserted document out in unencrypted form. The document is automatically decrypted
273+
because ``autoEncryptionSettings`` have been configured.
274+
275+
The full source is available at
276+
`ClientSideEncryptionExplicitEncryptionOnlyTour.java <https://github.com/mongodb/mongo-java-driver/blob/master/driver-sync/src/examples/tour/ClientSideEncryptionExplicitEncryptionOnlyTour.java>`_.
277+
278+
279+
.. code-block:: java
280+
:emphasize-lines: 3
281+
282+
...
283+
MongoClientSettings clientSettings = MongoClientSettings.builder()
284+
.autoEncryptionSettings(AutoEncryptionSettings.builder()
285+
.keyVaultNamespace(keyVaultNamespace.getFullName())
286+
.kmsProviders(kmsProviders)
287+
.bypassAutoEncryption(true)
288+
.build())
289+
.build();
290+
MongoClient mongoClient = MongoClients.create(clientSettings);
291+
...
292+
293+
// Explicitly encrypt a field
294+
BsonBinary encryptedFieldValue = clientEncryption.encrypt(new BsonString("123456789"),
295+
new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId));
296+
297+
collection.insertOne(new Document("encryptedField", encryptedFieldValue));
298+
299+
// Automatically decrypts the encrypted field.
300+
System.out.println(collection.find().first().toJson());
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.. code-block:: groovy
2+
3+
dependencies {
4+
compile 'org.mongodb:mongodb-crypt:1.1.0'
5+
}
6+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.. code-block:: xml
2+
3+
<dependencies>
4+
<dependency>
5+
<groupId>org.mongodb</groupId>
6+
<artifactId>mongodb-crypt</artifactId>
7+
<version>1.1.0</version>
8+
</dependency>
9+
</dependencies>
10+

0 commit comments

Comments
 (0)