Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRIVERS-2416 Add docs and tests for azure oidc #376

Merged
merged 38 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
bc63fd6
DRIVERS-2416 Add docs and tests for azure oidc
blink1073 Nov 29, 2023
fa0b449
fix callback handling
blink1073 Nov 29, 2023
f5ed2b0
add evg test for oidc azure
blink1073 Nov 29, 2023
1131382
fix config
blink1073 Nov 29, 2023
6a0ec67
cleanup config
blink1073 Nov 30, 2023
3415abf
fix directory
blink1073 Nov 30, 2023
9dd5811
fix commit command
blink1073 Nov 30, 2023
d9fea1f
try with a branch
blink1073 Nov 30, 2023
8a888a5
try again
blink1073 Nov 30, 2023
ef9ed57
try again
blink1073 Nov 30, 2023
88a1448
try without a branch
blink1073 Nov 30, 2023
7ec1adb
debug
blink1073 Nov 30, 2023
99ddbf1
more debug
blink1073 Nov 30, 2023
00c2be4
found it
blink1073 Nov 30, 2023
492ed9b
fix test cmd
blink1073 Nov 30, 2023
a6fc961
refactor variants
blink1073 Nov 30, 2023
4f8c670
add notes about the auth mech properties
blink1073 Nov 30, 2023
a1f3448
fix handling of run test
blink1073 Nov 30, 2023
f8b33a2
syntax error
blink1073 Nov 30, 2023
b2e8b57
more cleanup
blink1073 Nov 30, 2023
dd4ee4b
update test
blink1073 Nov 30, 2023
1074165
debug
blink1073 Nov 30, 2023
8827e67
try this
blink1073 Nov 30, 2023
985aeac
try this
blink1073 Nov 30, 2023
1ba879d
try this
blink1073 Nov 30, 2023
31a9d58
try this
blink1073 Nov 30, 2023
9ecc8c9
try this
blink1073 Nov 30, 2023
c6db6a2
add env variable
blink1073 Nov 30, 2023
507fa37
try this
blink1073 Nov 30, 2023
346e7ef
try this
blink1073 Nov 30, 2023
59c0dd8
extend shutdown time
blink1073 Nov 30, 2023
394720a
try handling date again
blink1073 Dec 1, 2023
7b4a499
fix local azure vm launch
blink1073 Dec 1, 2023
bee2521
fix handling of azure dir
blink1073 Dec 1, 2023
a8668a9
update readme
blink1073 Dec 1, 2023
11801f6
add more explanation in readme
blink1073 Dec 1, 2023
6fc7bca
merge from master
blink1073 Dec 14, 2023
14030a7
add a note
blink1073 Dec 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .evergreen/auth_oidc/azure/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Azure OIDC Testing

Testing OIDC with Azure integration involves launching an Azure VM,
pushing the code to the VM, running the OIDC tests for the driver,
and then tearing down the VM and its resources.

## Background

There are a set of scripts that facilitate these operations.
They build on top of the scripts used in `csfle/azurekms`.

See https://wiki.corp.mongodb.com/display/DRIVERS/Using+AWS+Secrets+Manager+to+Store+Testing+Secrets for more background
on how the secrets are managed for these tests. These secrets are used to log in to Azure, and the
rest of the secrets are fetched from the "OIDC-Key-Vault" in our Drivers Azure Subscription (https://portal.azure.com/#home).

See the Azure machine flows section of the OIDC Configuration [wiki](https://wiki.corp.mongodb.com/display/ENG/OIDC+Configuration#OIDCConfiguration-ServiceAccounts/ManagedIdentities/MachineFlows) for more information
about the Azure integration.

## Prerequisites

First, ensure you are running either locally or on an Evergreen host
that has the Azure CLI 2.25+ installed. At time of writing, distros with `az` installed include:

- debian10
- debian11
- ubuntu2004
- ubuntu2204

Locally, it can be installed as `brew install az`.

## Usage

To ensure proper setup and teardown, we use a task group in Evergreen config. The setup portion
should run the equivalent of the following, substituting your driver name:

```bash
export AZUREOIDC_VMNAME_PREFIX="PYTHON_DRIVER"
$DRIVERS_TOOLS/.evergreen/auth_oidc/azure/create-and-setup-vm.sh
```

This script can be run locally or in CI. The script also runs a self-test on the VM using the Python driver.

Next, compile/build and bundle our driver and test code, and run the test:

```bash
# Prep the source tarball - first make sure the patch changes are committed before using `git archive`.
git add .
git commit -m "add files"
export AZUREOIDC_DRIVERS_TAR_FILE=/tmp/mongo-python-driver.tgz
git archive -o $AZUREOIDC_DRIVERS_TAR_FILE HEAD
# Define the command to run on the VM.
# Ensure that we source the environment file created for us, set up any other variables we need,
# and then run our test suite on the vm.
export AZUREOIDC_TEST_CMD="source ./env.sh && OIDC_PROVIDER_NAME=azure ./.evergreen/run-mongodb-oidc-test.sh"
bash $DRIVERS_TOOLS/.evergreen/auth_oidc/azure/run-driver-test.sh
```

In your tests, you can use the environment variables in `env.sh` to define the `TOKEN_AUDIENCE` and `TOKEN_CLIENT_ID`
auth mechanism properties, e.g.

```python
TOKEN_AUDIENCE="api://" + os.environ["AZUREOIDC_CLIENTID"]
TOKEN_CLIENT_ID=os.environ["AZUREOIDC_TOKENCLIENT"] # For first user
TOKEN_CLIENT_ID=os.environ["AZUREOIDC_TOKENCLIENT2"] # For second user
```

Note: If you are creating a uri, you will have to escape `TOKEN_AUDIENCE` value, e.g.

```bash
MONGODB_URI="${MONGODB_URI}/?authMechanism=MONGODB-OIDC"
MONGODB_URI="${MONGODB_URI}&authMechanismProperties=PROVIDER_NAME:azure"
MONGODB_URI="${MONGODB_URI},TOKEN_AUDIENCE:api%3A%2F%2F${AZUREOIDC_CLIENTID}"
durran marked this conversation as resolved.
Show resolved Hide resolved
```

Note: since we will be testing with two different clients, the `TOKEN_CLIENT_ID` will need to be provided
as an argument to `MongoClient` in the prose tests.

Finally, we tear down the vm:

```bash
$DRIVERS_TOOLS/.evergreen/auth_oidc/azure/delete-vm.sh
```

### Environment Variables

Below is an explanantion of the environment variables stored in the Azure key vault.

- AZUREOIDC_AUTHPREFIX - The auth prefix used for DB user and role names.
- AZUREOIDC_AUTHCLAIM - The object ID of the Azure Group, used in the DB role name.
- AZUREOIDC_CLIENTID - The client ID of the Azure App registration, used for the `TOKEN_AUDIENCE` auth mechanism property.
- AZUREOIDC_TOKENCLIENT - The client ID of the first Azure Managed Identity, used for the `TOKEN_CLIENT_ID` auth mechanism property.
- AZUREOIDC_TOKENCLIENT2 - The client ID of the second Azure Managed Identity, used for the `TOKEN_CLIENT_ID` auth mechanism property.
- AZUREOIDC_TENANTID - The tenant ID of the Azure App registration, used to derive the `issuer` URI.
- AZUREKMS_IDENTITY - A space separated string with the two Resource IDs of the managed identities (`/subscriptions/... /subscriptions/...`). Used to assign the identities to the VM.
- AZUREOIDC_RESOURCEGROUP - The name of the Azure Resource Group, used when accessing the VM through the CLI.
41 changes: 16 additions & 25 deletions .evergreen/auth_oidc/azure/create-and-setup-vm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,32 @@ set -o errexit
set -o pipefail
set -o nounset

AZUREOIDC_DRIVERS_TOOLS=${AZUREOIDC_DRIVERS_TOOLS:-$DRIVERS_TOOLS}

if [ -z "${AZUREOIDC_VMNAME_PREFIX:-}" ] || \
[ -z "${AZUREOIDC_CLIENTID:-}" ] || \
[ -z "${AZUREOIDC_TENANTID:-}" ] || \
[ -z "${AZUREOIDC_SECRET:-}" ] || \
[ -z "${AZUREOIDC_DRIVERS_TOOLS:-}" ]; then
# Ensure required variables are set.
if [ -z "${AZUREOIDC_VMNAME_PREFIX:-}" ]; then
echo "Please set the following required environment variables"
echo " AZUREOIDC_VMNAME_PREFIX to an identifier string no spaces (e.g. CDRIVER)"
echo " AZUREOIDC_CLIENTID"
echo " AZUREOIDC_TENANTID"
echo " AZUREOIDC_SECRET"
echo " AZUREOIDC_DRIVERS_TOOLS"
exit 1
fi

# Set defaults.
AZUREOIDC_DRIVERS_TOOLS=${AZUREOIDC_DRIVERS_TOOLS:-$DRIVERS_TOOLS}
BASE_PATH="$AZUREOIDC_DRIVERS_TOOLS/.evergreen/auth_oidc"
export AZUREKMS_PUBLICKEYPATH="$BASE_PATH/azure/keyfile.pub"
export AZUREKMS_PRIVATEKEYPATH="$BASE_PATH/azure/keyfile"
export AZUREKMS_CLIENTID=$AZUREOIDC_CLIENTID
export AZUREKMS_VMNAME_PREFIX=$AZUREOIDC_VMNAME_PREFIX
export AZUREKMS_TENANTID=$AZUREOIDC_TENANTID
export AZUREKMS_SECRET=$AZUREOIDC_SECRET
export AZUREOIDC_ENVPATH="$BASE_PATH/azure/env.sh"
export AZUREKMS_IMAGE=${AZUREOIDC_IMAGE:-"Debian:debian-11:11:0.20221020.1174"}

# Handle secrets from vault.
cd $BASE_PATH
. ./activate-authoidcvenv.sh
bash ../auth_aws/setup_secrets.sh drivers/azureoidc
source secrets-export.sh

export AZUREKMS_TENANTID=$AZUREOIDC_TENANTID
export AZUREKMS_SECRET=$AZUREOIDC_SECRET
export AZUREKMS_CLIENTID=$AZUREOIDC_CLIENTID

# Check for Azure Command-Line Interface (`az`) version 2.25.0 or newer.
if ! command -v az &> /dev/null; then
echo "az not detected. See https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/csfle/azurekms/README.md for supported distros"
Expand All @@ -46,9 +45,7 @@ fi
# Login.
"$AZUREOIDC_DRIVERS_TOOLS"/.evergreen/csfle/azurekms/login.sh

# Handle secrets from vault.
cd $BASE_PATH
. ./activate-authoidcvenv.sh
# Get the rest of the secrets from the Azure vault.
python ./azure/handle_secrets.py
source $AZUREOIDC_ENVPATH

Expand Down Expand Up @@ -80,7 +77,7 @@ pushd $AZUREOIDC_DRIVERS_TOOLS
git archive --format=tar.gz -o $TARFILE --prefix=drivers-evergreen-tools/ HEAD
TARFILE_BASE=$(basename ${TARFILE})
AZUREKMS_SRC=${TARFILE} \
AZUREKMS_DST="~/" \
AZUREKMS_DST="./" \
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/copy-file.sh
echo "Copying files ... end"
echo "Untarring file ... begin"
Expand All @@ -94,11 +91,5 @@ AZUREKMS_CMD="./drivers-evergreen-tools/.evergreen/auth_oidc/azure/start-mongodb
"$AZUREOIDC_DRIVERS_TOOLS"/.evergreen/csfle/azurekms/run-command.sh

# Run the self-test
AZUREKMS_SRC="$AZUREOIDC_DRIVERS_TOOLS/.evergreen/auth_oidc/azure/test.py" \
AZUREKMS_DST="./" \
"$AZUREOIDC_DRIVERS_TOOLS"/.evergreen/csfle/azurekms/copy-file.sh
AZUREKMS_SRC="$AZUREOIDC_DRIVERS_TOOLS/.evergreen/auth_oidc/azure/run-test.sh" \
AZUREKMS_DST="./" \
"$AZUREOIDC_DRIVERS_TOOLS"/.evergreen/csfle/azurekms/copy-file.sh
AZUREKMS_CMD="./run-test.sh" \
AZUREKMS_CMD="./drivers-evergreen-tools/.evergreen/auth_oidc/azure/run-test.sh" \
"$AZUREOIDC_DRIVERS_TOOLS"/.evergreen/csfle/azurekms/run-command.sh
15 changes: 8 additions & 7 deletions .evergreen/auth_oidc/azure/run-driver-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ set -o errexit
set -o pipefail
set -o nounset

AZURE_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
pushd $AZURE_DIR

# Check for inputs.
if [ -z "${AZUREOIDC_DRIVERS_TAR_FILE:-}" ] || \
[ -z "${AZUREOIDC_TEST_CMD:-}" ]; then
Expand All @@ -13,26 +16,24 @@ if [ -z "${AZUREOIDC_DRIVERS_TAR_FILE:-}" ] || \
fi

# Read in the env variables.
DIR=$(dirname $0)
source $DIR/env.sh
source ./env.sh

# Set up variables.
DRIVERS_TOOLS=$AZUREOIDC_DRIVERS_TOOLS
export AZUREKMS_RESOURCEGROUP=$AZUREOIDC_RESOURCEGROUP
export AZUREKMS_VMNAME=$AZUREOIDC_VMNAME
export AZUREKMS_PRIVATEKEYPATH=$DIR/keyfile
export AZUREKMS_PRIVATEKEYPATH=$AZURE_DIR/keyfile

# Set up the remote driver checkout.
DRIVER_TARFILE_BASE=$(basename ${AZUREOIDC_DRIVERS_TAR_FILE})
AZUREKMS_SRC=${AZUREOIDC_DRIVERS_TAR_FILE} \
AZUREKMS_DST="~/" \
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/copy-file.sh
$AZURE_DIR/../../csfle/azurekms/copy-file.sh
echo "Copying files ... end"
echo "Untarring file ... begin"
AZUREKMS_CMD="tar xf ${DRIVER_TARFILE_BASE}" \
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/run-command.sh
$AZURE_DIR/../../csfle/azurekms/run-command.sh
echo "Untarring file ... end"

# Run the driver test.
AZUREKMS_CMD="${AZUREOIDC_TEST_CMD}" \
$DRIVERS_TOOLS/.evergreen/csfle/azurekms/run-command.sh
$AZURE_DIR/../../csfle/azurekms/run-command.sh
13 changes: 9 additions & 4 deletions .evergreen/auth_oidc/azure/test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from pymongo import MongoClient
from functools import partial
import os
import json
from urllib.request import urlopen, Request
Expand All @@ -10,7 +9,7 @@

app_id = os.environ['AZUREOIDC_CLIENTID']

def callback(client_id, client_info, server_info):
def _inner_callback(client_id, client_info, server_info):
url = "http://169.254.169.254/metadata/identity/oauth2/token"
url += "?api-version=2018-02-01"
url += f"&resource=api://{app_id}"
Expand Down Expand Up @@ -41,7 +40,13 @@ def callback(client_id, client_info, server_info):
raise ValueError(msg)
return dict(access_token=data['access_token'])

props = dict(request_token_callback=partial(callback(os.environ['AZUREOIDC_TOKENCLIENT'])))
def callback1(client_info, server_info):
return _inner_callback(os.environ['AZUREOIDC_TOKENCLIENT'], client_info, server_info)

def callback2(client_info, server_info):
return _inner_callback(os.environ['AZUREOIDC_TOKENCLIENT2'], client_info, server_info)

props = dict(request_token_callback=callback1)
print('Testing MONGODB-OIDC on azure...')
print('Testing resource 1...')
c = MongoClient('mongodb://localhost:27017/?authMechanism=MONGODB-OIDC', authMechanismProperties=props)
Expand All @@ -50,7 +55,7 @@ def callback(client_id, client_info, server_info):
print('Testing resource 1... done.')

print('Testing resource 2...')
props = dict(request_token_callback=partial(callback(os.environ['AZUREOIDC_TOKENCLIENT2'])))
props = dict(request_token_callback=callback2)
c = MongoClient('mongodb://localhost:27017/?authMechanism=MONGODB-OIDC', authMechanismProperties=props)
c.test.test.find_one({})
c.close()
Expand Down
59 changes: 56 additions & 3 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,19 @@ functions:
cd ${PROJECT_DIRECTORY}
make test

"run oidc azure test":
- command: shell.exec
params:
shell: bash
script: |-
set -o errexit
${PREPARE_SHELL}
cd $DRIVERS_TOOLS
export AZUREOIDC_DRIVERS_TAR_FILE=/tmp/drivers-tools.tgz
git archive -o $AZUREOIDC_DRIVERS_TAR_FILE HEAD
export AZUREOIDC_TEST_CMD="source ./env.sh && echo 'hello'"
bash $DRIVERS_TOOLS/.evergreen/auth_oidc/azure/run-driver-test.sh

"cleanup":
- command: shell.exec
params:
Expand Down Expand Up @@ -791,10 +804,14 @@ tasks:
- func: "run docker test"

- name: "test-oidc"
tags: ["latest", "docker"]
tags: ["latest", "oidc"]
commands:
- func: "run oidc test"

- name: "test-oidc-azure"
commands:
- func: "run oidc azure test"

# }}}


Expand Down Expand Up @@ -964,6 +981,35 @@ task_groups:
tasks:
- ".serverless"

- name: testazureoidc_task_group
tags: ["latest", "oidc"]
setup_group:
- func: fetch source
- func: prepare resources
- command: shell.exec
params:
shell: bash
script: |-
set -o errexit
${PREPARE_SHELL}
# ensure HEAD points to current commit
cd $DRIVERS_TOOLS
git add .
git commit -m "add files"
export AZUREOIDC_VMNAME_PREFIX="DRIVERS_TOOLS"
$DRIVERS_TOOLS/.evergreen/auth_oidc/azure/create-and-setup-vm.sh
teardown_group:
- command: shell.exec
params:
shell: bash
script: |-
${PREPARE_SHELL}
$DRIVERS_TOOLS/.evergreen/auth_oidc/azure/delete-vm.sh
setup_group_can_fail_task: true
setup_group_timeout_secs: 1800
tasks:
- test-oidc-azure

buildvariants:

# Test packaging and other release related routines
Expand All @@ -975,13 +1021,20 @@ buildvariants:
- ".releng" # Run all tasks with the "releng" tag

# Tests relating to docker images
- name: tests-docker-related
display_name: Docker Related
- name: tests-docker
display_name: Docker
run_on:
- ubuntu2004-large
tasks:
- ".docker" # Run all tasks with the "docker" tag

- name: tests-oidc
display_name: OIDC
run_on: ubuntu2004-small
tasks:
- "test-oidc"
- "testazureoidc_task_group"

- matrix_name: "tests-all"
matrix_spec: {"os-fully-featured": "*", auth: "*", ssl: "*" }
display_name: "${os-fully-featured} ${auth} ${ssl}"
Expand Down
7 changes: 7 additions & 0 deletions .evergreen/csfle/azurekms/create-vm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,11 @@ az vm create \
--nsg "$AZUREKMS_VMNAME-NSG" \
--assign-identity $AZUREKMS_IDENTITY \
>/dev/null

if [ $(uname -s) = "Darwin" ]; then
SHUTDOWN_TIME=$(date -u -v+1H +"%H%M")
else
SHUTDOWN_TIME=$(date -u -d "$(date) + 1 hours" +"%H%M")
fi
az vm auto-shutdown -g $AZUREKMS_RESOURCEGROUP -n $AZUREKMS_VMNAME --time $SHUTDOWN_TIME
echo "Creating a Virtual Machine ($AZUREKMS_VMNAME) ... end"
12 changes: 6 additions & 6 deletions .evergreen/csfle/azurekms/remote-scripts/setup-azure-vm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
set -o errexit
set -o pipefail
# Do not error on unset variables. run-orchestration.sh accesses unset variables.
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get update

echo "Install jq ... begin"
sudo apt-get -y -o DPkg::Lock::Timeout=-1 install jq
sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::Lock::Timeout=-1 install jq
echo "Install jq ... end"

echo "Installing MongoDB dependencies ... begin"
# Dependencies for mongod: https://www.mongodb.com/docs/manual/tutorial/install-mongodb-enterprise-on-debian-tarball/
sudo apt-get -y -o DPkg::Lock::Timeout=-1 install libcurl4 libgssapi-krb5-2 libldap-2.4-2 libwrap0 libsasl2-2 libsasl2-modules libsasl2-modules-gssapi-mit snmp openssl liblzma5
sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::Lock::Timeout=-1 install libcurl4 libgssapi-krb5-2 libldap-2.4-2 libwrap0 libsasl2-2 libsasl2-modules libsasl2-modules-gssapi-mit snmp openssl liblzma5
# Dependencies for run-orchestration.sh
sudo apt-get -y -o DPkg::Lock::Timeout=-1 install python3.9-venv
sudo apt-get -y -o DPkg::Lock::Timeout=-1 install python3-pip
sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::Lock::Timeout=-1 install python3.9-venv
sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::Lock::Timeout=-1 install python3-pip
# Install git.
sudo apt-get -y -o DPkg::Lock::Timeout=-1 install git
sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::Lock::Timeout=-1 install git
echo "Installing MongoDB dependencies ... end"
Loading