From 7efbefcb7e0ca995fcda98f20d61b10317a36b58 Mon Sep 17 00:00:00 2001 From: Adam Rayner Date: Mon, 16 Oct 2023 17:57:29 +0000 Subject: [PATCH] SERVER-77907 Add Azure OIDC machine flow tests --- .eslintrc.yml | 1 + .../suites/external_auth_oidc_azure.yml | 10 +++++ etc/burn_in_tests.yml | 3 ++ etc/evergreen_yml_components/definitions.yml | 30 +++++++++++++ .../variants/misc_release.yml | 1 + evergreen/external_auth_azure_setup.sh | 44 +++++++++++++++++++ evergreen/external_auth_azure_teardown.sh | 6 +++ .../automated_idp_authn_simulator_azure.py | 1 + src/mongo/shell/program_runner.cpp | 16 ++++--- src/mongo/shell/program_runner.h | 2 +- src/mongo/shell/shell_utils_launcher.cpp | 16 +++++-- 11 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 buildscripts/resmokeconfig/suites/external_auth_oidc_azure.yml create mode 100644 evergreen/external_auth_azure_setup.sh create mode 100644 evergreen/external_auth_azure_teardown.sh diff --git a/.eslintrc.yml b/.eslintrc.yml index a15823b5621..e4d7e3c9473 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -161,6 +161,7 @@ globals: runProgram: true runMongoProgram: true runNonMongoProgram: true + runNonMongoProgramQuietly: true _runMongoProgram: true _startMongoProgram: true startMongoProgram: true diff --git a/buildscripts/resmokeconfig/suites/external_auth_oidc_azure.yml b/buildscripts/resmokeconfig/suites/external_auth_oidc_azure.yml new file mode 100644 index 00000000000..e0d23550d3a --- /dev/null +++ b/buildscripts/resmokeconfig/suites/external_auth_oidc_azure.yml @@ -0,0 +1,10 @@ +test_kind: js_test + +selector: + roots: + - src/mongo/db/modules/enterprise/jstests/external_auth_oidc_azure/*.js + +executor: + config: + shell_options: + nodb: '' diff --git a/etc/burn_in_tests.yml b/etc/burn_in_tests.yml index e43a165e08f..994af24f895 100644 --- a/etc/burn_in_tests.yml +++ b/etc/burn_in_tests.yml @@ -9,3 +9,6 @@ selector: exclude_tests: # Requires external_auth_oidc.sh to run beforehand. - src/mongo/db/modules/enterprise/jstests/external_auth_oidc/oidc_e2e_okta.js + #Requres external_auth_azure_setup.sh to run before, and external_auth_azure_teardown.sh to run after + - src/mongo/db/modules/enterprise/jstests/external_auth_oidc_azure/oidc_e2e_azure.js + - src/mongo/db/modules/enterprise/jstests/external_auth_oidc_azure/oidc_e2e_azure_machine.js diff --git a/etc/evergreen_yml_components/definitions.yml b/etc/evergreen_yml_components/definitions.yml index 2a60d4e3be4..a28aed655c9 100644 --- a/etc/evergreen_yml_components/definitions.yml +++ b/etc/evergreen_yml_components/definitions.yml @@ -5716,6 +5716,25 @@ tasks: vars: resmoke_jobs_max: ${external_auth_oidc_jobs_max|1} +- <<: *task_template + name: external_auth_oidc_azure + tags: [] + commands: + - *f_expansions_write + - func: "do setup" + - func: "f_expansions_write" + - command: subprocess.exec + params: + binary: bash + args: + - "src/evergreen/external_auth_azure_setup.sh" + - func: "run tests" + - command: subprocess.exec + params: + binary: bash + args: + - "src/evergreen/external_auth_azure_teardown.sh" + - <<: *task_template name: external_auth_windows tags: [] @@ -9199,6 +9218,17 @@ task_groups: tasks: - iwyu_self_test +- <<: *compile_task_group_template + name: external_auth_oidc_azure_TG + tasks: + - external_auth_oidc_azure + teardown_task: + - command: subprocess.exec + params: + binary: bash + args: + - "src/evergreen/external_auth_azure_teardown.sh" + - <<: *compile_task_group_template name: compile_ninja_TG tasks: diff --git a/etc/evergreen_yml_components/variants/misc_release.yml b/etc/evergreen_yml_components/variants/misc_release.yml index d7eb48551bc..c50f3939b91 100644 --- a/etc/evergreen_yml_components/variants/misc_release.yml +++ b/etc/evergreen_yml_components/variants/misc_release.yml @@ -2187,6 +2187,7 @@ buildvariants: - name: .encrypt !.aggregation !.replica_sets !.sharding !.jscore - name: external_auth - name: external_auth_aws + - name: external_auth_oidc_azure - name: .jscore .common !.decimal !.sharding !.feature_flag_guarded - name: jsCore_auth - name: .jstestfuzz .common diff --git a/evergreen/external_auth_azure_setup.sh b/evergreen/external_auth_azure_setup.sh new file mode 100644 index 00000000000..c0bbe4519a5 --- /dev/null +++ b/evergreen/external_auth_azure_setup.sh @@ -0,0 +1,44 @@ +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)" +. "$DIR/prelude.sh" + +cd src + +set -o errexit +cat << EOF > $HOME/azure_e2e_config.json +{ + "tD548GwE1@outlook.com" : "${oidc_azure_test_user_account_one_secret}", + "tD548GwE2@outlook.com" : "${oidc_azure_test_user_account_two_secret}", + "tD548GwE3@outlook.com" : "${oidc_azure_test_user_account_three_secret}", + + "oidc_azure_client_secret_id" : "${oidc_azure_client_secret_id}", + "oidc_azure_client_secret_val" : "${oidc_azure_client_secret_val}", + "oidc_azure_client_id" : "${oidc_azure_client_id}", + "oidc_azure_tenant_id" : "${oidc_azure_tenant_id}", + "oidc_azure_subscription_id" : "${oidc_azure_subscription_id}", + "oidc_azure_group_name" : "${oidc_azure_group_name}", + "oidc_azure_container_app_name" : "${oidc_azure_container_app_name}", + "oidc_azure_container_port" : "${oidc_azure_container_port}", + "oidc_azure_api_version" : "${oidc_azure_api_version}", + "oidc_azure_resource_name" : "${oidc_azure_resource_name}", + "oidc_azure_object_id" : "${oidc_azure_object_id}", + "oidc_azure_managed_identity_api_version": "${oidc_azure_managed_identity_api_version}" +} +EOF +cat << EOF > $HOME/azure_remote_key +${oidc_azure_container_key} +EOF + +# EVG project variables do not preserve line breaks - rather these are replaced with spaces, so we will need to convert our pem back into proper format +sed s/\ OPENSSH\ PRIVATE\ KEY/OPENSSHPRIVATEKEY/g $HOME/azure_remote_key | sed s/\ /\\n/g | sed s/OPENSSHPRIVATEKEY/\ OPENSSH\ PRIVATE\ KEY/g > $HOME/azure_remote_key + +# SSH will complain and fail if the private key permissions are too lenient (by default it is created with 644), so modify to run the test +chmod 600 $HOME/azure_remote_key + +# Log some basic information about our SSH version and the final permissions and user/group of the private key file for debugging +ssh -V +ls -al $HOME/azure_remote_key + +# This script enables ingress on the Azure Container App instance that we will use to obtain our managed identity token, +# restrict ingress to the local, publicly-facing IP of the host we are running on, and then output the hostname of the container app into a local file +# so that it can be dynamically consumed by subsequent test steps (such as get_token.py) +python src/mongo/db/modules/enterprise/jstests/external_auth_oidc_azure/lib/toggle_ingress.py enable --config_file=$HOME/azure_e2e_config.json --debug | tee $HOME/azure_remote_host diff --git a/evergreen/external_auth_azure_teardown.sh b/evergreen/external_auth_azure_teardown.sh new file mode 100644 index 00000000000..81d547f21ac --- /dev/null +++ b/evergreen/external_auth_azure_teardown.sh @@ -0,0 +1,6 @@ +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)" +. "$DIR/prelude.sh" + +cd src + +python src/mongo/db/modules/enterprise/jstests/external_auth_oidc_azure/lib/toggle_ingress.py disable --config_file=$HOME/azure_e2e_config.json diff --git a/jstests/auth/lib/automated_idp_authn_simulator_azure.py b/jstests/auth/lib/automated_idp_authn_simulator_azure.py index 2f82dee9698..ca92b95020a 100644 --- a/jstests/auth/lib/automated_idp_authn_simulator_azure.py +++ b/jstests/auth/lib/automated_idp_authn_simulator_azure.py @@ -78,6 +78,7 @@ def authenticate_azure(activation_endpoint, userCode, username, test_credentials landing_header = WebDriverWait(driver, 30).until( EC.presence_of_element_located((By.XPATH, "//p[@id='message'][@class='text-block-body no-margin-top']")) ) + assert landing_header is not None and "You have signed in" in landing_header.text except Exception as e: diff --git a/src/mongo/shell/program_runner.cpp b/src/mongo/shell/program_runner.cpp index 44413031f96..e830135c87b 100644 --- a/src/mongo/shell/program_runner.cpp +++ b/src/mongo/shell/program_runner.cpp @@ -458,7 +458,7 @@ ProgramRunner::ProgramRunner(BSONObj args, BSONObj env, bool isMongo, ProgramReg _port < 0 || !_parentRegistry->isPortRegistered(_port)); } -void ProgramRunner::start() { +void ProgramRunner::start(bool shouldLogArgs) { int pipeEnds[2]; { @@ -520,11 +520,15 @@ void ProgramRunner::start() { _pipe = pipeEnds[0]; - LOGV2_INFO(22810, - "shell: Started program", - "pid"_attr = _pid, - "port"_attr = _port, - "argv"_attr = _argv); + logv2::DynamicAttributes attrs; + attrs.add("pid", _pid); + attrs.add("port", _port); + + if (shouldLogArgs) { + attrs.add("argv", _argv); + } + + LOGV2_INFO(22810, "shell: Started program", attrs); } void ProgramRunner::operator()(ProgramOutputMultiplexer* multiplexer, bool shouldLogOutput) { diff --git a/src/mongo/shell/program_runner.h b/src/mongo/shell/program_runner.h index 2d5e9ec0680..070e4aaed36 100644 --- a/src/mongo/shell/program_runner.h +++ b/src/mongo/shell/program_runner.h @@ -138,7 +138,7 @@ public: class ProgramRunner { public: /** Launch the program. */ - void start(); + void start(bool shouldLogArgs = true); /** Reads the program's output into the provided instance of ProgramOutputMultiplexer. * Note that the passed-in multiplexer will typically be the global programOutputLogger so that diff --git a/src/mongo/shell/shell_utils_launcher.cpp b/src/mongo/shell/shell_utils_launcher.cpp index 281a76ae181..3b1e1f07683 100644 --- a/src/mongo/shell/shell_utils_launcher.cpp +++ b/src/mongo/shell/shell_utils_launcher.cpp @@ -246,13 +246,15 @@ BSONObj StartMongoProgram(const BSONObj& a, void* data) { return BSON(string("") << runner.pid().asLongLong()); } -BSONObj RunProgram(const BSONObj& a, void* data, bool isMongo) { +BSONObj RunProgram(const BSONObj& a, void* data, bool isMongo, bool isQuiet = false) { BSONObj env{}; auto registry = ProgramRegistry::get(getGlobalServiceContext()); auto runner = registry->createProgramRunner(a, env, isMongo); - runner.start(); + + runner.start(!isQuiet); + invariant(registry->isPidRegistered(runner.pid())); - stdx::thread t(runner, registry->getProgramOutputMultiplexer(), true /* shouldLogOutput */); + stdx::thread t(runner, registry->getProgramOutputMultiplexer(), !isQuiet /* shouldLogOutput */); registry->registerReaderThread(runner.pid(), std::move(t)); int exit_code = -123456; // sentinel value registry->waitForPid(runner.pid(), true, &exit_code); @@ -267,6 +269,13 @@ BSONObj RunNonMongoProgram(const BSONObj& a, void* data) { return RunProgram(a, data, false); } +// This function is identical to RunNonMongoProgram except that it enables flags that +// disable logging of program outputs and vargs in order to prevent sensitive data from +// inadvertently being output to logs. +BSONObj RunNonMongoProgramQuietly(const BSONObj& a, void* data) { + return RunProgram(a, data, false, true); +} + BSONObj ResetDbpath(const BSONObj& a, void* data) { uassert(ErrorCodes::FailedToParse, "Expected 1 field", a.nFields() == 1); string path = a.firstElement().str(); @@ -946,6 +955,7 @@ void installShellUtilsLauncher(Scope& scope) { scope.injectNative("run", RunMongoProgram); scope.injectNative("_runMongoProgram", RunMongoProgram); scope.injectNative("runNonMongoProgram", RunNonMongoProgram); + scope.injectNative("runNonMongoProgramQuietly", RunNonMongoProgramQuietly); scope.injectNative("_stopMongoProgram", StopMongoProgram); scope.injectNative("stopMongoProgramByPid", StopMongoProgramByPid); scope.injectNative("rawMongoProgramOutput", RawMongoProgramOutput);