Skip to content

Commit bcb0ac0

Browse files
authored
PYTHON-3396 Support the Azure VM-assigned Managed Identity for Automatic KMS Credentials (#1105)
1 parent 1abcd3f commit bcb0ac0

File tree

4 files changed

+180
-39
lines changed

4 files changed

+180
-39
lines changed

.evergreen/config.yml

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,50 @@ task_groups:
10721072
tasks:
10731073
- testgcpkms-task
10741074

1075+
- name: testazurekms_task_group
1076+
setup_group:
1077+
- func: fetch source
1078+
- func: prepare resources
1079+
- func: fix absolute paths
1080+
- func: make files executable
1081+
- command: shell.exec
1082+
params:
1083+
silent: true
1084+
shell: bash
1085+
script: |-
1086+
set -o errexit
1087+
${PREPARE_SHELL}
1088+
echo '${testazurekms_publickey}' > /tmp/testazurekms_publickey
1089+
echo '${testazurekms_privatekey}' > /tmp/testazurekms_privatekey
1090+
# Set 600 permissions on private key file. Otherwise ssh / scp may error with permissions "are too open".
1091+
chmod 600 /tmp/testazurekms_privatekey
1092+
export AZUREKMS_CLIENTID="${testazurekms_clientid}"
1093+
export AZUREKMS_TENANTID="${testazurekms_tenantid}"
1094+
export AZUREKMS_SECRET="${testazurekms_secret}"
1095+
export AZUREKMS_DRIVERS_TOOLS="$DRIVERS_TOOLS"
1096+
export AZUREKMS_RESOURCEGROUP="${testazurekms_resourcegroup}"
1097+
export AZUREKMS_PUBLICKEYPATH="/tmp/testazurekms_publickey"
1098+
export AZUREKMS_PRIVATEKEYPATH="/tmp/testazurekms_privatekey"
1099+
export AZUREKMS_SCOPE="${testazurekms_scope}"
1100+
export AZUREKMS_VMNAME_PREFIX="PYTHON_DRIVER"
1101+
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/create-and-setup-vm.sh
1102+
- command: expansions.update
1103+
params:
1104+
file: testazurekms-expansions.yml
1105+
teardown_group:
1106+
- command: shell.exec
1107+
params:
1108+
shell: bash
1109+
script: |-
1110+
${PREPARE_SHELL}
1111+
export AZUREKMS_VMNAME=${AZUREKMS_VMNAME}
1112+
export AZUREKMS_RESOURCEGROUP=${testazurekms_resourcegroup}
1113+
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/delete-vm.sh
1114+
setup_group_can_fail_task: true
1115+
setup_group_timeout_secs: 1800
1116+
tasks:
1117+
- testazurekms-task
1118+
10751119
tasks:
10761120
# Wildcard task. Do you need to find out what tools are available and where?
10771121
# Throw it here, and execute this task on all buildvariants
@@ -1925,20 +1969,83 @@ tasks:
19251969
export GCPKMS_PROJECT=${GCPKMS_PROJECT}
19261970
export GCPKMS_ZONE=${GCPKMS_ZONE}
19271971
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
1972+
GCPKMS_CMD="SUCCESS=true TEST_FLE_GCP_AUTO=1 LIBMONGOCRYPT_URL=https://s3.amazonaws.com/mciuploads/libmongocrypt/debian10/master/latest/libmongocrypt.tar.gz ./.evergreen/run-tests.sh" $DRIVERS_TOOLS/.evergreen/csfle/gcpkms/run-command.sh
19291973
19301974
- name: "testgcpkms-fail-task"
19311975
# testgcpkms-fail-task runs in a non-GCE environment.
19321976
# It is expected to fail to obtain GCE credentials.
19331977
commands:
1978+
- func: "bootstrap mongo-orchestration"
1979+
vars:
1980+
VERSION: "latest"
1981+
TOPOLOGY: "server"
19341982
- command: shell.exec
19351983
type: test
19361984
params:
19371985
working_dir: "src"
19381986
shell: "bash"
19391987
script: |
19401988
${PREPARE_SHELL}
1941-
SUCCESS=false ./.evergreen/run-mongodb-fle-gcp-auto.sh mongodb://localhost:27017
1989+
export LIBMONGOCRYPT_URL=https://s3.amazonaws.com/mciuploads/libmongocrypt/ubuntu1804-64/master/latest/libmongocrypt.tar.gz
1990+
SUCCESS=false TEST_FLE_GCP_AUTO=1 ./.evergreen/run-tests.sh
1991+
1992+
- name: testazurekms-task
1993+
commands:
1994+
- command: shell.exec
1995+
params:
1996+
shell: bash
1997+
script: |-
1998+
set -o errexit
1999+
${PREPARE_SHELL}
2000+
cd src
2001+
echo "Copying files ... begin"
2002+
export AZUREKMS_RESOURCEGROUP=${testazurekms_resourcegroup}
2003+
export AZUREKMS_VMNAME=${AZUREKMS_VMNAME}
2004+
export AZUREKMS_PRIVATEKEYPATH=/tmp/testazurekms_privatekey
2005+
tar czf /tmp/mongo-python-driver.tgz .
2006+
AZUREKMS_SRC="/tmp/mongo-python-driver.tgz" \
2007+
AZUREKMS_DST="~/" \
2008+
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/copy-file.sh
2009+
echo "Copying files ... end"
2010+
echo "Untarring file ... begin"
2011+
AZUREKMS_CMD="tar xf mongo-python-driver.tgz" \
2012+
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/run-command.sh
2013+
echo "Untarring file ... end"
2014+
- command: shell.exec
2015+
type: test
2016+
params:
2017+
shell: bash
2018+
script: |-
2019+
set -o errexit
2020+
${PREPARE_SHELL}
2021+
export AZUREKMS_RESOURCEGROUP=${testazurekms_resourcegroup}
2022+
export AZUREKMS_VMNAME=${AZUREKMS_VMNAME}
2023+
export AZUREKMS_PRIVATEKEYPATH=/tmp/testazurekms_privatekey
2024+
AZUREKMS_CMD="KEY_NAME='${testazurekms_keyname}' KEY_VAULT_ENDPOINT='${testazurekms_keyvaultendpoint}' LIBMONGOCRYPT_URL=https://s3.amazonaws.com/mciuploads/libmongocrypt/debian10/master/latest/libmongocrypt.tar.gz SUCCESS=true TEST_FLE_AZURE_AUTO=1 ./.evergreen/run-tests.sh" \
2025+
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/run-command.sh
2026+
2027+
- name: testazurekms-fail-task
2028+
commands:
2029+
- func: fetch source
2030+
- func: make files executable
2031+
- func: "bootstrap mongo-orchestration"
2032+
vars:
2033+
VERSION: "latest"
2034+
TOPOLOGY: "server"
2035+
- command: shell.exec
2036+
type: test
2037+
params:
2038+
shell: bash
2039+
script: |-
2040+
set -o errexit
2041+
${PREPARE_SHELL}
2042+
cd src
2043+
PYTHON_BINARY=
2044+
KEY_NAME='${testazurekms_keyname}' \
2045+
KEY_VAULT_ENDPOINT='${testazurekms_keyvaultendpoint}' \
2046+
LIBMONGOCRYPT_URL=https://s3.amazonaws.com/mciuploads/libmongocrypt/ubuntu1804-64/master/latest/libmongocrypt.tar.gz \
2047+
SUCCESS=false TEST_FLE_AZURE_AUTO=1 \
2048+
./.evergreen/run-tests.sh
19422049
19432050
axes:
19442051
# Choice of distro
@@ -2920,12 +3027,20 @@ buildvariants:
29203027
- name: testgcpkms-variant
29213028
display_name: "GCP KMS"
29223029
run_on:
2923-
- debian11-small
3030+
- ubuntu1804-test
29243031
tasks:
29253032
- name: testgcpkms_task_group
29263033
batchtime: 20160 # Use a batchtime of 14 days as suggested by the CSFLE test README
29273034
- testgcpkms-fail-task
29283035

3036+
- name: testazurekms-variant
3037+
display_name: "Azure KMS"
3038+
run_on: ubuntu1804-test
3039+
tasks:
3040+
- name: testazurekms_task_group
3041+
batchtime: 20160 # Use a batchtime of 14 days as suggested by the CSFLE test README
3042+
- testazurekms-fail-task
3043+
29293044
- name: Release
29303045
display_name: Release
29313046
batchtime: 20160 # 14 days

.evergreen/run-mongodb-fle-gcp-auto.sh

Lines changed: 0 additions & 35 deletions
This file was deleted.

.evergreen/run-tests.sh

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ if [ -n "$TEST_PYOPENSSL" ]; then
101101
python -m pip install --prefer-binary pyopenssl requests service_identity
102102
fi
103103

104-
if [ -n "$TEST_ENCRYPTION" ]; then
104+
if [ -n "$TEST_ENCRYPTION" ] || [ -n "$TEST_FLE_AZURE_AUTO" ] || [ -n "$TEST_FLE_GCP_AUTO" ]; then
105+
105106
createvirtualenv $PYTHON venv-encryption
106107
trap "deactivate; rm -rf venv-encryption" EXIT HUP
107108
PYTHON=python
@@ -146,7 +147,9 @@ if [ -n "$TEST_ENCRYPTION" ]; then
146147
python -c "import pymongocrypt; print('pymongocrypt version: '+pymongocrypt.__version__)"
147148
python -c "import pymongocrypt; print('libmongocrypt version: '+pymongocrypt.libmongocrypt_version())"
148149
# PATH is updated by PREPARE_SHELL for access to mongocryptd.
150+
fi
149151

152+
if [ -n "$TEST_ENCRYPTION" ]; then
150153
# Need aws dependency for On-Demand KMS Credentials.
151154
python -m pip install '.[aws]'
152155

@@ -171,6 +174,20 @@ if [ -n "$TEST_ENCRYPTION" ]; then
171174
TEST_ARGS="-s test.test_encryption"
172175
fi
173176

177+
if [ -n "$TEST_FLE_AZURE_AUTO" ] || [ -n "$TEST_FLE_GCP_AUTO" ]; then
178+
if [[ -z "$SUCCESS" ]]; then
179+
echo "Must define SUCCESS"
180+
exit 1
181+
fi
182+
183+
if echo "$MONGODB_URI" | grep -q "@"; then
184+
echo "MONGODB_URI unexpectedly contains user credentials in FLE test!";
185+
exit 1
186+
fi
187+
188+
TEST_ARGS="-s test.test_on_demand_csfle"
189+
fi
190+
174191
if [ -n "$DATA_LAKE" ]; then
175192
TEST_ARGS="-s test.test_data_lake"
176193
fi

test/test_on_demand_csfle.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,47 @@ def test_02_success(self):
6565
codec_options=CodecOptions(),
6666
)
6767
self.client_encryption.create_data_key("gcp", self.master_key)
68+
69+
70+
class TestonDemandAzureCredentials(IntegrationTest):
71+
@classmethod
72+
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed")
73+
@client_context.require_version_min(4, 2, -1)
74+
def setUpClass(cls):
75+
super(TestonDemandAzureCredentials, cls).setUpClass()
76+
77+
def setUp(self):
78+
super(TestonDemandAzureCredentials, self).setUp()
79+
self.master_key = {
80+
"keyVaultEndpoint": "https://keyvault-drivers-2411.vault.azure.net/keys/",
81+
"keyName": "KEY-NAME",
82+
}
83+
84+
@unittest.skipIf(not os.getenv("TEST_FLE_AZURE_AUTO"), "Not testing FLE Azure auto")
85+
def test_01_failure(self):
86+
if os.environ["SUCCESS"].lower() == "true":
87+
self.skipTest("Expecting success")
88+
self.client_encryption = ClientEncryption(
89+
kms_providers={"azure": {}},
90+
key_vault_namespace="keyvault.datakeys",
91+
key_vault_client=client_context.client,
92+
codec_options=CodecOptions(),
93+
)
94+
with self.assertRaises(EncryptionError):
95+
self.client_encryption.create_data_key("azure", self.master_key)
96+
97+
@unittest.skipIf(not os.getenv("TEST_FLE_AZURE_AUTO"), "Not testing FLE Azure auto")
98+
def test_02_success(self):
99+
if os.environ["SUCCESS"].lower() == "false":
100+
self.skipTest("Expecting failure")
101+
self.client_encryption = ClientEncryption(
102+
kms_providers={"azure": {}},
103+
key_vault_namespace="keyvault.datakeys",
104+
key_vault_client=client_context.client,
105+
codec_options=CodecOptions(),
106+
)
107+
self.client_encryption.create_data_key("azure", self.master_key)
108+
109+
110+
if __name__ == "__main__":
111+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)