Skip to content

Commit d2e92fc

Browse files
committed
feat(NODE-5050): support GCP automatic credential fetch for CSFLE
1 parent 9ce0bcc commit d2e92fc

10 files changed

+372
-40
lines changed

.evergreen/config.in.yml

+84-1
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,52 @@ tasks:
10931093
params:
10941094
file: src/results.json
10951095

1096+
- name: "test-gcpkms-task"
1097+
commands:
1098+
- func: "install dependencies"
1099+
# Upload node driver to a GCP instance
1100+
- command: subprocess.exec
1101+
type: setup
1102+
params:
1103+
binary: bash
1104+
add_expansions_to_env: true
1105+
env:
1106+
DRIVERS_TOOLS: ${DRIVERS_TOOLS}
1107+
GCPKMS_GCLOUD: ${GCPKMS_GCLOUD}
1108+
GCPKMS_PROJECT: ${GCPKMS_PROJECT}
1109+
GCPKMS_ZONE: ${GCPKMS_ZONE}
1110+
GCPKMS_INSTANCENAME: ${GCPKMS_INSTANCENAME}
1111+
args:
1112+
- src/.evergreen/setup-gcp-testing.sh
1113+
# Run Mocha test over on GCE instance
1114+
- command: subprocess.exec
1115+
type: test
1116+
params:
1117+
working_dir: src
1118+
binary: bash
1119+
env:
1120+
GCPKMS_GCLOUD: ${GCPKMS_GCLOUD}
1121+
GCPKMS_PROJECT: ${GCPKMS_PROJECT}
1122+
GCPKMS_ZONE: ${GCPKMS_ZONE}
1123+
GCPKMS_INSTANCENAME: ${GCPKMS_INSTANCENAME}
1124+
GCPKMS_CMD: "env EXPECTED_GCPKMS_OUTCOME=success bash src/.evergreen/run-gcp-kms-tests.sh"
1125+
args:
1126+
- ${DRIVERS_TOOLS}/.evergreen/csfle/gcpkms/run-command.sh
1127+
1128+
1129+
- name: "test-gcpkms-fail-task"
1130+
# test-gcpkms-fail-task runs in a non-GCE environment.
1131+
# It is expected to fail to obtain GCE credentials.
1132+
commands:
1133+
- command: subprocess.exec
1134+
type: test
1135+
params:
1136+
binary: bash
1137+
env:
1138+
EXPECTED_GCPKMS_OUTCOME: "failure"
1139+
args:
1140+
- .evergreen/run-gcp-kms-tests.sh
1141+
10961142
task_groups:
10971143
- name: serverless_task_group
10981144
setup_group_can_fail_task: true
@@ -1101,7 +1147,7 @@ task_groups:
11011147
- func: "fetch source"
11021148
- command: shell.exec
11031149
params:
1104-
shell: "bash"
1150+
shell: bash
11051151
script: |
11061152
${PREPARE_SHELL}
11071153
set +o xtrace
@@ -1128,6 +1174,43 @@ task_groups:
11281174
tasks:
11291175
- ".serverless"
11301176

1177+
- name: test_gcpkms_task_group
1178+
setup_group_can_fail_task: true
1179+
setup_group_timeout_secs: 1800 # 30 minutes
1180+
setup_group:
1181+
- func: fetch source
1182+
- command: subprocess.exec
1183+
params:
1184+
working_dir: "src"
1185+
binary: bash
1186+
add_expansions_to_env: true
1187+
env:
1188+
testgcpkms_key_file: ${gcpkms_key_file}
1189+
GCPKMS_SERVICEACCOUNT: ${gcpkms_service_account}
1190+
GCPKMS_DRIVERS_TOOLS: ${DRIVERS_TOOLS}
1191+
GCPKMS_MACHINETYPE: "e2-standard-4"
1192+
args:
1193+
- .evergreen/setup-gcp-instance.sh
1194+
- command: expansions.update
1195+
# Load the GCPKMS_GCLOUD, GCPKMS_INSTANCE, GCPKMS_REGION, and GCPKMS_ZONE expansions.
1196+
params:
1197+
file: src/testgcpkms-expansions.yml
1198+
1199+
teardown_group:
1200+
- command: subprocess.exec
1201+
params:
1202+
binary: bash
1203+
add_expansions_to_env: true
1204+
env:
1205+
GCPKMS_GCLOUD: ${GCPKMS_GCLOUD}
1206+
GCPKMS_PROJECT: ${GCPKMS_PROJECT}
1207+
GCPKMS_ZONE: ${GCPKMS_ZONE}
1208+
GCPKMS_INSTANCENAME: ${GCPKMS_INSTANCENAME}
1209+
args:
1210+
- ${DRIVERS_TOOLS}/.evergreen/csfle/gcpkms/delete-instance.sh
1211+
tasks:
1212+
- test-gcpkms-task
1213+
11311214
pre:
11321215
- func: "fetch source"
11331216
- func: "windows fix"

.evergreen/config.yml

+79
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,45 @@ tasks:
10311031
- command: perf.send
10321032
params:
10331033
file: src/results.json
1034+
- name: test-gcpkms-task
1035+
commands:
1036+
- func: install dependencies
1037+
- command: subprocess.exec
1038+
type: setup
1039+
params:
1040+
binary: bash
1041+
add_expansions_to_env: true
1042+
env:
1043+
DRIVERS_TOOLS: ${DRIVERS_TOOLS}
1044+
GCPKMS_GCLOUD: ${GCPKMS_GCLOUD}
1045+
GCPKMS_PROJECT: ${GCPKMS_PROJECT}
1046+
GCPKMS_ZONE: ${GCPKMS_ZONE}
1047+
GCPKMS_INSTANCENAME: ${GCPKMS_INSTANCENAME}
1048+
args:
1049+
- src/.evergreen/setup-gcp-testing.sh
1050+
- command: subprocess.exec
1051+
type: test
1052+
params:
1053+
working_dir: src
1054+
binary: bash
1055+
env:
1056+
GCPKMS_GCLOUD: ${GCPKMS_GCLOUD}
1057+
GCPKMS_PROJECT: ${GCPKMS_PROJECT}
1058+
GCPKMS_ZONE: ${GCPKMS_ZONE}
1059+
GCPKMS_INSTANCENAME: ${GCPKMS_INSTANCENAME}
1060+
GCPKMS_CMD: env EXPECTED_GCPKMS_OUTCOME=success bash src/.evergreen/run-gcp-kms-tests.sh
1061+
args:
1062+
- ${DRIVERS_TOOLS}/.evergreen/csfle/gcpkms/run-command.sh
1063+
- name: test-gcpkms-fail-task
1064+
commands:
1065+
- command: subprocess.exec
1066+
type: test
1067+
params:
1068+
binary: bash
1069+
env:
1070+
EXPECTED_GCPKMS_OUTCOME: failure
1071+
args:
1072+
- .evergreen/run-gcp-kms-tests.sh
10341073
- name: test-latest-server
10351074
tags:
10361075
- latest
@@ -3018,6 +3057,40 @@ task_groups:
30183057
bash ${DRIVERS_TOOLS}/.evergreen/serverless/delete-instance.sh
30193058
tasks:
30203059
- .serverless
3060+
- name: test_gcpkms_task_group
3061+
setup_group_can_fail_task: true
3062+
setup_group_timeout_secs: 1800
3063+
setup_group:
3064+
- func: fetch source
3065+
- command: subprocess.exec
3066+
params:
3067+
working_dir: src
3068+
binary: bash
3069+
add_expansions_to_env: true
3070+
env:
3071+
testgcpkms_key_file: ${gcpkms_key_file}
3072+
GCPKMS_SERVICEACCOUNT: ${gcpkms_service_account}
3073+
GCPKMS_DRIVERS_TOOLS: ${DRIVERS_TOOLS}
3074+
GCPKMS_MACHINETYPE: e2-standard-4
3075+
args:
3076+
- .evergreen/setup-gcp-instance.sh
3077+
- command: expansions.update
3078+
params:
3079+
file: src/testgcpkms-expansions.yml
3080+
teardown_group:
3081+
- command: subprocess.exec
3082+
params:
3083+
binary: bash
3084+
add_expansions_to_env: true
3085+
env:
3086+
GCPKMS_GCLOUD: ${GCPKMS_GCLOUD}
3087+
GCPKMS_PROJECT: ${GCPKMS_PROJECT}
3088+
GCPKMS_ZONE: ${GCPKMS_ZONE}
3089+
GCPKMS_INSTANCENAME: ${GCPKMS_INSTANCENAME}
3090+
args:
3091+
- ${DRIVERS_TOOLS}/.evergreen/csfle/gcpkms/delete-instance.sh
3092+
tasks:
3093+
- test-gcpkms-task
30213094
pre:
30223095
- func: fetch source
30233096
- func: windows fix
@@ -3481,6 +3554,12 @@ buildvariants:
34813554
NODE_LTS_NAME: fermium
34823555
tasks:
34833556
- serverless_task_group
3557+
- name: rhel8-test-gcp-kms
3558+
display_name: GCP KMS Test
3559+
run_on: debian11-small
3560+
tasks:
3561+
- test_gcpkms_task_group
3562+
- test-gcpkms-fail-task
34843563
- name: rhel8-no-auth-tests
34853564
display_name: No Auth Tests
34863565
run_on: rhel80-large

.evergreen/generate_evergreen_tasks.js

+7
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,13 @@ BUILD_VARIANTS.push({
661661
tasks: ['serverless_task_group']
662662
});
663663

664+
BUILD_VARIANTS.push({
665+
name: 'rhel8-test-gcp-kms',
666+
display_name: 'GCP KMS Test',
667+
run_on: 'debian11-small',
668+
tasks: ['test_gcpkms_task_group', 'test-gcpkms-fail-task']
669+
});
670+
664671
BUILD_VARIANTS.push({
665672
name: 'rhel8-no-auth-tests',
666673
display_name: 'No Auth Tests',

.evergreen/run-gcp-kms-tests.sh

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#! /usr/bin/env bash
2+
3+
set -o errexit
4+
5+
pushd "src"
6+
PROJECT_DIRECTORY="$(pwd)"
7+
export PROJECT_DIRECTORY
8+
source ".evergreen/init-nvm.sh"
9+
10+
set -o xtrace
11+
12+
npm install '[email protected]'
13+
npm install 'gcp-metadata'
14+
15+
export MONGODB_URI="mongodb://localhost:27017"
16+
17+
export EXPECTED_GCPKMS_OUTCOME=${EXPECTED_GCPKMS_OUTCOME:-omitted}
18+
export TEST_CSFLE=true
19+
export CSFLE_KMS_PROVIDERS='not json'
20+
21+
npx mocha --config test/mocha_mongodb.json test/integration/client-side-encryption/client_side_encryption.prose.17.on_demand_gcp.test.ts

.evergreen/setup-gcp-instance.sh

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#! /usr/bin/env bash
2+
3+
set -o errexit
4+
if [ -z ${testgcpkms_key_file+omitted} ]; then echo "testgcpkms_key_file is unset" && exit 1; fi
5+
6+
echo "${testgcpkms_key_file}" > ./testgcpkms_key_file.json
7+
export GCPKMS_KEYFILE=./testgcpkms_key_file.json
8+
9+
"$GCPKMS_DRIVERS_TOOLS/.evergreen/csfle/gcpkms/create-and-setup-instance.sh"

.evergreen/setup-gcp-testing.sh

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#! /usr/bin/env bash
2+
3+
# Assert required environment variables are present without printing them
4+
if [ -z ${GCPKMS_GCLOUD+omitted} ]; then echo "GCPKMS_GCLOUD is unset" && exit 1; fi
5+
if [ -z ${GCPKMS_PROJECT+omitted} ]; then echo "GCPKMS_PROJECT is unset" && exit 1; fi
6+
if [ -z ${GCPKMS_ZONE+omitted} ]; then echo "GCPKMS_ZONE is unset" && exit 1; fi
7+
if [ -z ${GCPKMS_INSTANCENAME+omitted} ]; then echo "GCPKMS_INSTANCENAME is unset" && exit 1; fi
8+
9+
set -o errexit
10+
11+
source "${PROJECT_DIRECTORY}/.evergreen/init-nvm.sh"
12+
13+
export GCPKMS_SRC=node-driver-source.tgz
14+
export GCPKMS_DST=$GCPKMS_INSTANCENAME:
15+
16+
# Box up the entire driver and it's node_modules
17+
echo "compressing node driver source ... begin"
18+
tar -czf $GCPKMS_SRC src
19+
echo "compressing node driver source ... end"
20+
21+
echo "copying node driver tar ... begin"
22+
"${DRIVERS_TOOLS}/.evergreen/csfle/gcpkms/copy-file.sh"
23+
echo "copying node driver tar ... end"
24+
25+
echo "decompressing node driver tar on gcp ... begin"
26+
export GCPKMS_CMD="tar -xzf $GCPKMS_SRC"
27+
"${DRIVERS_TOOLS}/.evergreen/csfle/gcpkms/run-command.sh"
28+
echo "decompressing node driver tar on gcp ... end"

src/deps.ts

+54-37
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,19 @@ export interface AutoEncryptionOptions {
223223
/** Configuration options that are used by specific KMS providers during key generation, encryption, and decryption. */
224224
kmsProviders?: {
225225
/** Configuration options for using 'aws' as your KMS provider */
226-
aws?: {
227-
/** The access key used for the AWS KMS provider */
228-
accessKeyId: string;
229-
/** The secret access key used for the AWS KMS provider */
230-
secretAccessKey: string;
231-
/**
232-
* An optional AWS session token that will be used as the
233-
* X-Amz-Security-Token header for AWS requests.
234-
*/
235-
sessionToken?: string;
236-
};
226+
aws?:
227+
| {
228+
/** The access key used for the AWS KMS provider */
229+
accessKeyId: string;
230+
/** The secret access key used for the AWS KMS provider */
231+
secretAccessKey: string;
232+
/**
233+
* An optional AWS session token that will be used as the
234+
* X-Amz-Security-Token header for AWS requests.
235+
*/
236+
sessionToken?: string;
237+
}
238+
| Record<string, never>;
237239
/** Configuration options for using 'local' as your KMS provider */
238240
local?: {
239241
/**
@@ -243,33 +245,48 @@ export interface AutoEncryptionOptions {
243245
key: Buffer | string;
244246
};
245247
/** Configuration options for using 'azure' as your KMS provider */
246-
azure?: {
247-
/** The tenant ID identifies the organization for the account */
248-
tenantId: string;
249-
/** The client ID to authenticate a registered application */
250-
clientId: string;
251-
/** The client secret to authenticate a registered application */
252-
clientSecret: string;
253-
/**
254-
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
255-
* This is optional, and only needed if customer is using a non-commercial Azure instance
256-
* (e.g. a government or China account, which use different URLs).
257-
* Defaults to "login.microsoftonline.com"
258-
*/
259-
identityPlatformEndpoint?: string | undefined;
260-
};
248+
azure?:
249+
| {
250+
/** The tenant ID identifies the organization for the account */
251+
tenantId: string;
252+
/** The client ID to authenticate a registered application */
253+
clientId: string;
254+
/** The client secret to authenticate a registered application */
255+
clientSecret: string;
256+
/**
257+
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
258+
* This is optional, and only needed if customer is using a non-commercial Azure instance
259+
* (e.g. a government or China account, which use different URLs).
260+
* Defaults to "login.microsoftonline.com"
261+
*/
262+
identityPlatformEndpoint?: string | undefined;
263+
}
264+
| {
265+
/**
266+
* If present, an access token to authenticate with Azure.
267+
*/
268+
accessToken: string;
269+
};
261270
/** Configuration options for using 'gcp' as your KMS provider */
262-
gcp?: {
263-
/** The service account email to authenticate */
264-
email: string;
265-
/** A PKCS#8 encrypted key. This can either be a base64 string or a binary representation */
266-
privateKey: string | Buffer;
267-
/**
268-
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
269-
* Defaults to "oauth2.googleapis.com"
270-
*/
271-
endpoint?: string | undefined;
272-
};
271+
gcp?:
272+
| {
273+
/** The service account email to authenticate */
274+
email: string;
275+
/** A PKCS#8 encrypted key. This can either be a base64 string or a binary representation */
276+
privateKey: string | Buffer;
277+
/**
278+
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
279+
* Defaults to "oauth2.googleapis.com"
280+
*/
281+
endpoint?: string | undefined;
282+
}
283+
| {
284+
/**
285+
* If present, an access token to authenticate with GCP.
286+
*/
287+
accessToken: string;
288+
}
289+
| Record<string, never>;
273290
/**
274291
* Configuration options for using 'kmip' as your KMS provider
275292
*/

0 commit comments

Comments
 (0)