Skip to content

Commit 84fbc1f

Browse files
authored
PYTHON-3367 Add support for GCP attached service accounts when using GCP KMS (#1064)
1 parent 45b809e commit 84fbc1f

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

.evergreen/config.yml

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,43 @@ task_groups:
10351035
tasks:
10361036
- ".serverless"
10371037

1038+
- name: testgcpkms_task_group
1039+
setup_group_can_fail_task: true
1040+
setup_group_timeout_secs: 1800 # 30 minutes
1041+
setup_group:
1042+
- func: fetch source
1043+
- func: prepare resources
1044+
- func: fix absolute paths
1045+
- func: make files executable
1046+
- command: shell.exec
1047+
params:
1048+
shell: "bash"
1049+
script: |
1050+
${PREPARE_SHELL}
1051+
echo '${testgcpkms_key_file}' > /tmp/testgcpkms_key_file.json
1052+
export GCPKMS_KEYFILE=/tmp/testgcpkms_key_file.json
1053+
export GCPKMS_DRIVERS_TOOLS=$DRIVERS_TOOLS
1054+
export GCPKMS_SERVICEACCOUNT="${testgcpkms_service_account}"
1055+
export GCPKMS_MACHINETYPE="e2-standard-4"
1056+
$DRIVERS_TOOLS/.evergreen/csfle/gcpkms/create-and-setup-instance.sh
1057+
# Load the GCPKMS_GCLOUD, GCPKMS_INSTANCE, GCPKMS_REGION, and GCPKMS_ZONE expansions.
1058+
- command: expansions.update
1059+
params:
1060+
file: testgcpkms-expansions.yml
1061+
teardown_group:
1062+
- command: shell.exec
1063+
params:
1064+
shell: "bash"
1065+
script: |
1066+
${PREPARE_SHELL}
1067+
export GCPKMS_GCLOUD=${GCPKMS_GCLOUD}
1068+
export GCPKMS_PROJECT=${GCPKMS_PROJECT}
1069+
export GCPKMS_ZONE=${GCPKMS_ZONE}
1070+
export GCPKMS_INSTANCENAME=${GCPKMS_INSTANCENAME}
1071+
$DRIVERS_TOOLS/.evergreen/csfle/gcpkms/delete-instance.sh
1072+
tasks:
1073+
- testgcpkms-task
1074+
10381075
tasks:
10391076
# Wildcard task. Do you need to find out what tools are available and where?
10401077
# Throw it here, and execute this task on all buildvariants
@@ -1857,6 +1894,51 @@ tasks:
18571894
commands:
18581895
- func: "download and merge coverage"
18591896

1897+
- name: "testgcpkms-task"
1898+
commands:
1899+
- command: shell.exec
1900+
type: setup
1901+
params:
1902+
working_dir: "src"
1903+
shell: "bash"
1904+
script: |
1905+
${PREPARE_SHELL}
1906+
echo "Copying files ... begin"
1907+
export GCPKMS_GCLOUD=${GCPKMS_GCLOUD}
1908+
export GCPKMS_PROJECT=${GCPKMS_PROJECT}
1909+
export GCPKMS_ZONE=${GCPKMS_ZONE}
1910+
export GCPKMS_INSTANCENAME=${GCPKMS_INSTANCENAME}
1911+
tar czf /tmp/mongo-python-driver.tgz .
1912+
GCPKMS_SRC=/tmp/mongo-python-driver.tgz GCPKMS_DST=$GCPKMS_INSTANCENAME: $DRIVERS_TOOLS/.evergreen/csfle/gcpkms/copy-file.sh
1913+
echo "Copying files ... end"
1914+
echo "Untarring file ... begin"
1915+
GCPKMS_CMD="tar xf mongo-python-driver.tgz" $DRIVERS_TOOLS/.evergreen/csfle/gcpkms/run-command.sh
1916+
echo "Untarring file ... end"
1917+
- command: shell.exec
1918+
type: test
1919+
params:
1920+
working_dir: "src"
1921+
shell: "bash"
1922+
script: |
1923+
${PREPARE_SHELL}
1924+
export GCPKMS_GCLOUD=${GCPKMS_GCLOUD}
1925+
export GCPKMS_PROJECT=${GCPKMS_PROJECT}
1926+
export GCPKMS_ZONE=${GCPKMS_ZONE}
1927+
export GCPKMS_INSTANCENAME=${GCPKMS_INSTANCENAME}
1928+
GCPKMS_CMD="SUCCESS=true ./.evergreen/run-mongodb-fle-gcp-auto.sh mongodb://localhost:27017" $DRIVERS_TOOLS/.evergreen/csfle/gcpkms/run-command.sh
1929+
1930+
- name: "testgcpkms-fail-task"
1931+
# testgcpkms-fail-task runs in a non-GCE environment.
1932+
# It is expected to fail to obtain GCE credentials.
1933+
commands:
1934+
- command: shell.exec
1935+
type: test
1936+
params:
1937+
working_dir: "src"
1938+
shell: "bash"
1939+
script: |
1940+
${PREPARE_SHELL}
1941+
SUCCESS=false ./.evergreen/run-mongodb-fle-gcp-auto.sh mongodb://localhost:27017
18601942
18611943
axes:
18621944
# Choice of distro
@@ -2821,6 +2903,15 @@ buildvariants:
28212903
tasks:
28222904
- name: "load-balancer-test"
28232905

2906+
- name: testgcpkms-variant
2907+
display_name: "GCP KMS"
2908+
run_on:
2909+
- debian11-small
2910+
tasks:
2911+
- name: testgcpkms_task_group
2912+
batchtime: 20160 # Use a batchtime of 14 days as suggested by the CSFLE test README
2913+
- testgcpkms-fail-task
2914+
28242915
- name: Release
28252916
display_name: Release
28262917
batchtime: 20160 # 14 days
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/bash
2+
3+
set -o xtrace
4+
set -o errexit # Exit the script with error if any of the commands fail
5+
6+
# Supported/used environment variables:
7+
# MONGODB_URI Set the URI, including an optional username/password to use to connect to the server
8+
# SUCCESS Whether the authentication is expected to succeed or fail. One of "true" or "false"
9+
############################################
10+
# Main Program #
11+
############################################
12+
13+
if [[ -z "$1" ]]; then
14+
echo "usage: $0 <MONGODB_URI>"
15+
exit 1
16+
fi
17+
export MONGODB_URI="$1"
18+
19+
if echo "$MONGODB_URI" | grep -q "@"; then
20+
echo "MONGODB_URI unexpectedly contains user credentials in FLE GCP test!";
21+
exit 1
22+
fi
23+
# Now we can safely enable xtrace
24+
set -o xtrace
25+
26+
authtest () {
27+
echo "Running GCP Credential Acquisition Test with $PYTHON"
28+
$PYTHON --version
29+
$PYTHON -m pip install --upgrade wheel setuptools pip
30+
$PYTHON -m pip install '.[encryption]'
31+
$PYTHON -m pip install https://github.com/mongodb/libmongocrypt#subdirectory=bindings/python
32+
TEST_FLE_GCP_AUTO=1 $PYTHON test/test_on_demand_csfle.py
33+
}
34+
35+
PYTHON="python3" authtest

test/test_on_demand_csfle.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright 2022-present MongoDB, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Test client side encryption with on demand credentials."""
16+
import os
17+
import sys
18+
import unittest
19+
20+
sys.path[0:0] = [""]
21+
22+
from test import IntegrationTest, client_context
23+
24+
from bson.codec_options import CodecOptions
25+
from pymongo.encryption import _HAVE_PYMONGOCRYPT, ClientEncryption, EncryptionError
26+
27+
28+
class TestonDemandGCPCredentials(IntegrationTest):
29+
@classmethod
30+
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed")
31+
@client_context.require_version_min(4, 2, -1)
32+
def setUpClass(cls):
33+
super(TestonDemandGCPCredentials, cls).setUpClass()
34+
35+
def setUp(self):
36+
super(TestonDemandGCPCredentials, self).setUp()
37+
self.master_key = {
38+
"projectId": "devprod-drivers",
39+
"location": "global",
40+
"keyRing": "key-ring-csfle",
41+
"keyName": "key-name-csfle",
42+
}
43+
44+
@unittest.skipIf(not os.getenv("TEST_FLE_GCP_AUTO"), "Not testing FLE GCP auto")
45+
def test_01_failure(self):
46+
if os.environ["SUCCESS"].lower() == "true":
47+
self.skipTest("Expecting success")
48+
self.client_encryption = ClientEncryption(
49+
kms_providers={"gcp": {}},
50+
key_vault_namespace="keyvault.datakeys",
51+
key_vault_client=client_context.client,
52+
codec_options=CodecOptions(),
53+
)
54+
with self.assertRaises(EncryptionError):
55+
self.client_encryption.create_data_key("gcp", self.master_key)
56+
57+
@unittest.skipIf(not os.getenv("TEST_FLE_GCP_AUTO"), "Not testing FLE GCP auto")
58+
def test_02_success(self):
59+
if os.environ["SUCCESS"].lower() == "false":
60+
self.skipTest("Expecting failure")
61+
self.client_encryption = ClientEncryption(
62+
kms_providers={"gcp": {}},
63+
key_vault_namespace="keyvault.datakeys",
64+
key_vault_client=client_context.client,
65+
codec_options=CodecOptions(),
66+
)
67+
self.client_encryption.create_data_key("gcp", self.master_key)

0 commit comments

Comments
 (0)