Skip to content

Commit d0064a7

Browse files
committed
feat(NODE-5050): support GCP automatic credential fetch for CSFLE
1 parent 0df03ef commit d0064a7

10 files changed

+386
-40
lines changed

.evergreen/config.in.yml

+90-1
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,58 @@ 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+
- func: "install dependencies"
1134+
- func: bootstrap mongo-orchestration
1135+
vars:
1136+
VERSION: latest
1137+
TOPOLOGY: server
1138+
AUTH: noauth
1139+
- command: subprocess.exec
1140+
type: test
1141+
params:
1142+
binary: bash
1143+
env:
1144+
EXPECTED_GCPKMS_OUTCOME: "failure"
1145+
args:
1146+
- src/.evergreen/run-gcp-kms-tests.sh
1147+
10961148
task_groups:
10971149
- name: serverless_task_group
10981150
setup_group_can_fail_task: true
@@ -1101,7 +1153,7 @@ task_groups:
11011153
- func: "fetch source"
11021154
- command: shell.exec
11031155
params:
1104-
shell: "bash"
1156+
shell: bash
11051157
script: |
11061158
${PREPARE_SHELL}
11071159
set +o xtrace
@@ -1128,6 +1180,43 @@ task_groups:
11281180
tasks:
11291181
- ".serverless"
11301182

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

.evergreen/config.yml

+85
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,51 @@ 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+
- func: install dependencies
1066+
- func: bootstrap mongo-orchestration
1067+
vars:
1068+
VERSION: latest
1069+
TOPOLOGY: server
1070+
AUTH: noauth
1071+
- command: subprocess.exec
1072+
type: test
1073+
params:
1074+
binary: bash
1075+
env:
1076+
EXPECTED_GCPKMS_OUTCOME: failure
1077+
args:
1078+
- src/.evergreen/run-gcp-kms-tests.sh
10341079
- name: test-latest-server
10351080
tags:
10361081
- latest
@@ -3002,6 +3047,40 @@ task_groups:
30023047
bash ${DRIVERS_TOOLS}/.evergreen/serverless/delete-instance.sh
30033048
tasks:
30043049
- .serverless
3050+
- name: test_gcpkms_task_group
3051+
setup_group_can_fail_task: true
3052+
setup_group_timeout_secs: 1800
3053+
setup_group:
3054+
- func: fetch source
3055+
- command: subprocess.exec
3056+
params:
3057+
working_dir: src
3058+
binary: bash
3059+
add_expansions_to_env: true
3060+
env:
3061+
testgcpkms_key_file: ${gcpkms_key_file}
3062+
GCPKMS_SERVICEACCOUNT: ${gcpkms_service_account}
3063+
GCPKMS_DRIVERS_TOOLS: ${DRIVERS_TOOLS}
3064+
GCPKMS_MACHINETYPE: e2-standard-4
3065+
args:
3066+
- .evergreen/setup-gcp-instance.sh
3067+
- command: expansions.update
3068+
params:
3069+
file: src/testgcpkms-expansions.yml
3070+
teardown_group:
3071+
- command: subprocess.exec
3072+
params:
3073+
binary: bash
3074+
add_expansions_to_env: true
3075+
env:
3076+
GCPKMS_GCLOUD: ${GCPKMS_GCLOUD}
3077+
GCPKMS_PROJECT: ${GCPKMS_PROJECT}
3078+
GCPKMS_ZONE: ${GCPKMS_ZONE}
3079+
GCPKMS_INSTANCENAME: ${GCPKMS_INSTANCENAME}
3080+
args:
3081+
- ${DRIVERS_TOOLS}/.evergreen/csfle/gcpkms/delete-instance.sh
3082+
tasks:
3083+
- test-gcpkms-task
30053084
pre:
30063085
- func: fetch source
30073086
- func: windows fix
@@ -3461,6 +3540,12 @@ buildvariants:
34613540
NODE_LTS_NAME: fermium
34623541
tasks:
34633542
- serverless_task_group
3543+
- name: rhel8-test-gcp-kms
3544+
display_name: GCP KMS Test
3545+
run_on: debian11-small
3546+
tasks:
3547+
- test_gcpkms_task_group
3548+
- test-gcpkms-fail-task
34643549
- name: rhel8-no-auth-tests
34653550
display_name: No Auth Tests
34663551
run_on: rhel80-large

.evergreen/generate_evergreen_tasks.js

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

666+
BUILD_VARIANTS.push({
667+
name: 'rhel8-test-gcp-kms',
668+
display_name: 'GCP KMS Test',
669+
run_on: 'debian11-small',
670+
tasks: ['test_gcpkms_task_group', 'test-gcpkms-fail-task']
671+
});
672+
666673
BUILD_VARIANTS.push({
667674
name: 'rhel8-no-auth-tests',
668675
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)