Skip to content

Commit acd5e6b

Browse files
authored
feat(data-service): add CSFLE options in ConnectionOptions COMPASS-5640 (#2923)
1 parent 19f2535 commit acd5e6b

File tree

3 files changed

+181
-9
lines changed

3 files changed

+181
-9
lines changed

packages/data-service/src/connection-options.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { AutoEncryptionOptions } from 'mongodb';
2+
13
export interface ConnectionOptions {
24
/**
35
* The connection string to connect to the MongoDB instance including all options set by the user.
@@ -13,6 +15,23 @@ export interface ConnectionOptions {
1315
* If true, the connection uses the system CA store instead of tlsCAFile or the default Node.js store.
1416
*/
1517
useSystemCA?: boolean;
18+
19+
/**
20+
* Options related to client-side field-level encryption.
21+
*/
22+
fleOptions?: ConnectionFleOptions;
23+
}
24+
25+
export interface ConnectionFleOptions {
26+
/**
27+
* Whether to store KMS credentials to disk or not.
28+
*/
29+
storeCredentials: boolean;
30+
31+
/**
32+
* Encryption options passed to the driver verbatim.
33+
*/
34+
autoEncryption: AutoEncryptionOptions;
1635
}
1736

1837
export interface ConnectionSshOptions {

packages/data-service/src/connection-secrets.spec.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,58 @@ describe('connection secrets', function () {
147147
port: 22,
148148
identityKeyPassphrase: 'passphrase',
149149
},
150+
fleOptions: {
151+
storeCredentials: true,
152+
autoEncryption: {
153+
keyVaultNamespace: 'keyVaultNamespace',
154+
kmsProviders: {
155+
aws: {
156+
accessKeyId: 'accessKeyId',
157+
secretAccessKey: 'secretAccessKey',
158+
sessionToken: 'sessionToken',
159+
},
160+
local: {
161+
key: 'key',
162+
},
163+
azure: {
164+
tenantId: 'tenantId',
165+
clientId: 'clientId',
166+
clientSecret: 'clientSecret',
167+
identityPlatformEndpoint: 'identityPlatformEndpoint',
168+
},
169+
gcp: {
170+
email: 'email',
171+
privateKey: 'privateKey',
172+
endpoint: 'endpoint',
173+
},
174+
kmip: {
175+
endpoint: 'endpoint',
176+
},
177+
},
178+
tlsOptions: {
179+
aws: {
180+
tlsCertificateKeyFile: 'file',
181+
tlsCertificateKeyFilePassword: 'pwd',
182+
},
183+
local: {
184+
tlsCertificateKeyFile: 'file',
185+
tlsCertificateKeyFilePassword: 'pwd',
186+
},
187+
azure: {
188+
tlsCertificateKeyFile: 'file',
189+
tlsCertificateKeyFilePassword: 'pwd',
190+
},
191+
gcp: {
192+
tlsCertificateKeyFile: 'file',
193+
tlsCertificateKeyFilePassword: 'pwd',
194+
},
195+
kmip: {
196+
tlsCertificateKeyFile: 'file',
197+
tlsCertificateKeyFilePassword: 'pwd',
198+
},
199+
},
200+
},
201+
},
150202
},
151203
};
152204

@@ -163,6 +215,47 @@ describe('connection secrets', function () {
163215
username: 'user',
164216
port: 22,
165217
},
218+
fleOptions: {
219+
storeCredentials: true,
220+
autoEncryption: {
221+
keyVaultNamespace: 'keyVaultNamespace',
222+
kmsProviders: {
223+
aws: {
224+
accessKeyId: 'accessKeyId',
225+
},
226+
local: {},
227+
azure: {
228+
tenantId: 'tenantId',
229+
clientId: 'clientId',
230+
identityPlatformEndpoint: 'identityPlatformEndpoint',
231+
},
232+
gcp: {
233+
email: 'email',
234+
endpoint: 'endpoint',
235+
},
236+
kmip: {
237+
endpoint: 'endpoint',
238+
},
239+
},
240+
tlsOptions: {
241+
aws: {
242+
tlsCertificateKeyFile: 'file',
243+
},
244+
local: {
245+
tlsCertificateKeyFile: 'file',
246+
},
247+
azure: {
248+
tlsCertificateKeyFile: 'file',
249+
},
250+
gcp: {
251+
tlsCertificateKeyFile: 'file',
252+
},
253+
kmip: {
254+
tlsCertificateKeyFile: 'file',
255+
},
256+
},
257+
},
258+
},
166259
},
167260
} as ConnectionInfo);
168261

@@ -173,6 +266,40 @@ describe('connection secrets', function () {
173266
sshTunnelPassphrase: 'passphrase',
174267
tlsCertificateKeyFilePassword: 'tlsCertPassword',
175268
proxyPassword: 'bar',
269+
autoEncryption: {
270+
kmsProviders: {
271+
aws: {
272+
secretAccessKey: 'secretAccessKey',
273+
sessionToken: 'sessionToken',
274+
},
275+
local: {
276+
key: 'key',
277+
},
278+
azure: {
279+
clientSecret: 'clientSecret',
280+
},
281+
gcp: {
282+
privateKey: 'privateKey',
283+
},
284+
},
285+
tlsOptions: {
286+
aws: {
287+
tlsCertificateKeyFilePassword: 'pwd',
288+
},
289+
local: {
290+
tlsCertificateKeyFilePassword: 'pwd',
291+
},
292+
azure: {
293+
tlsCertificateKeyFilePassword: 'pwd',
294+
},
295+
gcp: {
296+
tlsCertificateKeyFilePassword: 'pwd',
297+
},
298+
kmip: {
299+
tlsCertificateKeyFilePassword: 'pwd',
300+
},
301+
},
302+
},
176303
} as ConnectionSecrets);
177304
});
178305
});

packages/data-service/src/connection-secrets.ts

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import ConnectionString, {
33
CommaAndColonSeparatedRecord,
44
} from 'mongodb-connection-string-url';
55
import type { ConnectionInfo } from './connection-info';
6-
import type { MongoClientOptions, AuthMechanismProperties } from 'mongodb';
6+
import type {
7+
MongoClientOptions,
8+
AuthMechanismProperties,
9+
AutoEncryptionOptions,
10+
} from 'mongodb';
711

812
export interface ConnectionSecrets {
913
password?: string;
@@ -12,6 +16,7 @@ export interface ConnectionSecrets {
1216
awsSessionToken?: string;
1317
tlsCertificateKeyFilePassword?: string;
1418
proxyPassword?: string;
19+
autoEncryption?: AutoEncryptionOptions;
1520
}
1621

1722
export function mergeSecrets(
@@ -27,10 +32,7 @@ export function mergeSecrets(
2732
const connectionOptions = connectionInfoWithSecrets.connectionOptions;
2833

2934
const uri = new ConnectionString(connectionOptions.connectionString);
30-
// can remove the proxyPassword addition once we have NODE-3633
31-
const searchParams = uri.typedSearchParams<
32-
MongoClientOptions & { proxyPassword?: string }
33-
>();
35+
const searchParams = uri.typedSearchParams<MongoClientOptions>();
3436

3537
if (secrets.password) {
3638
uri.password = secrets.password;
@@ -45,6 +47,13 @@ export function mergeSecrets(
4547
secrets.sshTunnelPassphrase;
4648
}
4749

50+
if (secrets.autoEncryption && connectionOptions.fleOptions?.autoEncryption) {
51+
_.merge(
52+
connectionOptions.fleOptions?.autoEncryption,
53+
secrets.autoEncryption
54+
);
55+
}
56+
4857
if (secrets.tlsCertificateKeyFilePassword) {
4958
searchParams.set(
5059
'tlsCertificateKeyFilePassword',
@@ -84,10 +93,7 @@ export function extractSecrets(connectionInfo: Readonly<ConnectionInfo>): {
8493

8594
const connectionOptions = connectionInfoWithoutSecrets.connectionOptions;
8695
const uri = new ConnectionString(connectionOptions.connectionString);
87-
// can remove the proxyPassword addition once we have NODE-3633
88-
const searchParams = uri.typedSearchParams<
89-
MongoClientOptions & { proxyPassword?: string }
90-
>();
96+
const searchParams = uri.typedSearchParams<MongoClientOptions>();
9197

9298
if (uri.password) {
9399
secrets.password = uri.password;
@@ -137,5 +143,25 @@ export function extractSecrets(connectionInfo: Readonly<ConnectionInfo>): {
137143

138144
connectionInfoWithoutSecrets.connectionOptions.connectionString = uri.href;
139145

146+
if (connectionOptions.fleOptions?.autoEncryption) {
147+
const { autoEncryption } = connectionOptions.fleOptions;
148+
const kmsProviders = ['aws', 'local', 'azure', 'gcp', 'kmip'] as const;
149+
const secretPaths = [
150+
'kmsProviders.aws.secretAccessKey',
151+
'kmsProviders.aws.sessionToken',
152+
'kmsProviders.local.key',
153+
'kmsProviders.azure.clientSecret',
154+
'kmsProviders.gcp.privateKey',
155+
...kmsProviders.map(
156+
(p) => `tlsOptions.${p}.tlsCertificateKeyFilePassword`
157+
),
158+
];
159+
connectionOptions.fleOptions.autoEncryption = _.omit(
160+
autoEncryption,
161+
secretPaths
162+
);
163+
secrets.autoEncryption = _.pick(autoEncryption, secretPaths);
164+
}
165+
140166
return { connectionInfo: connectionInfoWithoutSecrets, secrets };
141167
}

0 commit comments

Comments
 (0)