diff options
author | Cheahuychou Mao <mao.cheahuychou@gmail.com> | 2021-01-29 15:36:29 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-02 10:02:35 +0000 |
commit | 8baad6fdb799b24bbc999089773698a10bfeaecc (patch) | |
tree | 0bb2f389723bcd8434ece650fffb050b1dbed8f1 | |
parent | 739d938be8bb992190b01004f39eecc2658c5c38 (diff) | |
download | mongo-8baad6fdb799b24bbc999089773698a10bfeaecc.tar.gz |
SERVER-54084 Add server parameter tenantMigrationDisableX509Auth to enable keyfile auth testing
13 files changed, 516 insertions, 196 deletions
diff --git a/jstests/replsets/tenant_migration_ssl_configuration.js b/jstests/replsets/tenant_migration_ssl_configuration.js index 96363e89b1c..ebab8c01041 100644 --- a/jstests/replsets/tenant_migration_ssl_configuration.js +++ b/jstests/replsets/tenant_migration_ssl_configuration.js @@ -1,5 +1,6 @@ /** - * Test that tenant migration commands require certificate fields and SSL to be enabled. + * Test that tenant migration commands only require and use certificate fields, and require SSL to + * to be enabled when 'tenantMigrationDisableX509Auth' server parameter is false (default). * * @tags: [requires_fcv_47, requires_majority_read_concern, incompatible_with_eft] */ @@ -14,11 +15,17 @@ const kTenantId = "testTenantId"; const kReadPreference = { mode: "primary" }; -const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForTest(); +const kValidMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForTest(); +const kExpiredMigrationCertificates = { + donorCertificateForRecipient: TenantMigrationUtil.getCertificateAndPrivateKey( + "jstests/libs/rs0_tenant_migration_expired.pem"), + recipientCertificateForDonor: TenantMigrationUtil.getCertificateAndPrivateKey( + "jstests/libs/rs1_tenant_migration_expired.pem") +}; (() => { - jsTest.log("Test that certificate fields are required fields for donorStartMigration and " + - "recipientSyncData"); + jsTest.log( + "Test that certificate fields are required when tenantMigrationDisableX509Auth=false"); const tenantMigrationTest = new TenantMigrationTest({name: jsTestName()}); if (!tenantMigrationTest.isFeatureFlagEnabled()) { jsTestLog("Skipping test because the tenant migrations feature flag is disabled"); @@ -28,32 +35,32 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT const donorPrimary = tenantMigrationTest.getDonorPrimary(); const recipientPrimary = tenantMigrationTest.getRecipientPrimary(); - jsTest.log( - "Test that 'donorCertificateForRecipient' is a required field for donorStartMigration"); + jsTest.log("Test that donorStartMigration requires 'donorCertificateForRecipient' when " + + "tenantMigrationDisableX509Auth=false"); assert.commandFailedWithCode(donorPrimary.adminCommand({ donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), tenantId: kTenantId, readPreference: kReadPreference, - recipientCertificateForDonor: kMigrationCertificates.recipientCertificateForDonor, + recipientCertificateForDonor: kValidMigrationCertificates.recipientCertificateForDonor, }), - 40414); + ErrorCodes.InvalidOptions); - jsTest.log( - "Test that 'recipientCertificateForDonor' is a required field for donorStartMigration"); + jsTest.log("Test that donorStartMigration requires 'recipientCertificateForDonor' when " + + "tenantMigrationDisableX509Auth=false"); assert.commandFailedWithCode(donorPrimary.adminCommand({ donorStartMigration: 1, migrationId: UUID(), recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), tenantId: kTenantId, readPreference: kReadPreference, - donorCertificateForRecipient: kMigrationCertificates.donorCertificateForRecipient, + donorCertificateForRecipient: kValidMigrationCertificates.donorCertificateForRecipient, }), - 40414); + ErrorCodes.InvalidOptions); - jsTest.log( - "Test that 'recipientCertificateForDonor' is a required field for recipientSyncData"); + jsTest.log("Test that recipientSyncData requires 'recipientCertificateForDonor' when " + + "tenantMigrationDisableX509Auth=false"); assert.commandFailedWithCode(recipientPrimary.adminCommand({ recipientSyncData: 1, migrationId: UUID(), @@ -61,10 +68,10 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT tenantId: kTenantId, readPreference: kReadPreference }), - 40414); + ErrorCodes.InvalidOptions); - jsTest.log( - "Test that 'recipientCertificateForDonor' is a required field for recipientForgetMigration"); + jsTest.log("Test that recipientForgetMigration requires 'recipientCertificateForDonor' when " + + "tenantMigrationDisableX509Auth=false"); assert.commandFailedWithCode(recipientPrimary.adminCommand({ recipientForgetMigration: 1, migrationId: UUID(), @@ -72,13 +79,14 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT tenantId: kTenantId, readPreference: kReadPreference }), - 40414); + ErrorCodes.InvalidOptions); tenantMigrationTest.stop(); })(); (() => { - jsTest.log("Test that donorStartMigration fails if SSL is not enabled on the donor"); + jsTest.log("Test that donorStartMigration fails if SSL is not enabled on the donor and " + + "tenantMigrationDisableX509Auth=false"); const donorRst = new ReplSetTest({nodes: 1, name: "donor"}); donorRst.startSet(); donorRst.initiate(); @@ -98,8 +106,8 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), tenantId: kTenantId, readPreference: kReadPreference, - donorCertificateForRecipient: kMigrationCertificates.donorCertificateForRecipient, - recipientCertificateForDonor: kMigrationCertificates.recipientCertificateForDonor, + donorCertificateForRecipient: kValidMigrationCertificates.donorCertificateForRecipient, + recipientCertificateForDonor: kValidMigrationCertificates.recipientCertificateForDonor, }), ErrorCodes.IllegalOperation); @@ -108,7 +116,8 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT })(); (() => { - jsTest.log("Test that recipientSyncData fails if SSL is not enabled on the recipient"); + jsTest.log("Test that recipientSyncData fails if SSL is not enabled on the recipient and " + + "tenantMigrationDisableX509Auth=false"); const recipientRst = new ReplSetTest({nodes: 1, name: "recipient"}); recipientRst.startSet(); recipientRst.initiate(); @@ -128,7 +137,7 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT donorConnectionString: tenantMigrationTest.getDonorRst().getURL(), tenantId: kTenantId, readPreference: kReadPreference, - recipientCertificateForDonor: kMigrationCertificates.recipientCertificateForDonor, + recipientCertificateForDonor: kValidMigrationCertificates.recipientCertificateForDonor, }), ErrorCodes.IllegalOperation); @@ -137,7 +146,8 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT })(); (() => { - jsTest.log("Test that donorStartMigration fails if SSL is not enabled on the recipient"); + jsTest.log("Test that donorStartMigration fails if SSL is not enabled on the recipient and " + + "tenantMigrationDisableX509Auth=false"); const recipientRst = new ReplSetTest({nodes: 1, name: "recipient"}); recipientRst.startSet(); recipientRst.initiate(); @@ -157,8 +167,8 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), tenantId: kTenantId, readPreference: kReadPreference, - donorCertificateForRecipient: kMigrationCertificates.donorCertificateForRecipient, - recipientCertificateForDonor: kMigrationCertificates.recipientCertificateForDonor, + donorCertificateForRecipient: kValidMigrationCertificates.donorCertificateForRecipient, + recipientCertificateForDonor: kValidMigrationCertificates.recipientCertificateForDonor, }; const stateRes = assert.commandWorked(TenantMigrationUtil.runTenantMigrationCommand( @@ -174,4 +184,228 @@ const kMigrationCertificates = TenantMigrationUtil.makeMigrationCertificatesForT recipientRst.stopSet(); tenantMigrationTest.stop(); })(); + +(() => { + jsTest.log("Test that recipientSyncData doesn't require 'recipientCertificateForDonor' when " + + "tenantMigrationDisableX509Auth=true"); + const migrationX509Options = TenantMigrationUtil.makeX509OptionsForTest(); + const recipientRst = new ReplSetTest({ + nodes: 1, + name: "recipient", + nodeOptions: Object.assign(migrationX509Options.recipient, + {setParameter: {tenantMigrationDisableX509Auth: true}}) + }); + + recipientRst.startSet(); + recipientRst.initiate(); + + const tenantMigrationTest = new TenantMigrationTest({name: jsTestName(), recipientRst}); + if (!tenantMigrationTest.isFeatureFlagEnabled()) { + jsTestLog("Skipping test because the tenant migrations feature flag is disabled"); + recipientRst.stopSet(); + return; + } + + const recipientPrimary = tenantMigrationTest.getRecipientPrimary(); + + assert.commandWorked(recipientPrimary.adminCommand({ + recipientSyncData: 1, + migrationId: UUID(), + donorConnectionString: tenantMigrationTest.getDonorRst().getURL(), + tenantId: kTenantId, + readPreference: kReadPreference + })); + + recipientRst.stopSet(); + tenantMigrationTest.stop(); +})(); + +(() => { + jsTest.log( + "Test that recipientForgetMigration doesn't require 'recipientCertificateForDonor' when " + + "tenantMigrationDisableX509Auth=true"); + const migrationX509Options = TenantMigrationUtil.makeX509OptionsForTest(); + const recipientRst = new ReplSetTest({ + nodes: 1, + name: "recipient", + nodeOptions: Object.assign(migrationX509Options.recipient, + {setParameter: {tenantMigrationDisableX509Auth: true}}) + }); + + recipientRst.startSet(); + recipientRst.initiate(); + + const tenantMigrationTest = new TenantMigrationTest({name: jsTestName(), recipientRst}); + if (!tenantMigrationTest.isFeatureFlagEnabled()) { + jsTestLog("Skipping test because the tenant migrations feature flag is disabled"); + recipientRst.stopSet(); + return; + } + + const recipientPrimary = tenantMigrationTest.getRecipientPrimary(); + + assert.commandWorked(recipientPrimary.adminCommand({ + recipientForgetMigration: 1, + migrationId: UUID(), + donorConnectionString: tenantMigrationTest.getDonorRst().getURL(), + tenantId: kTenantId, + readPreference: kReadPreference + })); + + recipientRst.stopSet(); + tenantMigrationTest.stop(); +})(); + +(() => { + jsTest.log("Test that donorStartMigration doesn't require certificate fields when " + + "tenantMigrationDisableX509Auth=true"); + const migrationX509Options = TenantMigrationUtil.makeX509OptionsForTest(); + const donorRst = new ReplSetTest({ + nodes: 1, + name: "donor", + nodeOptions: Object.assign(migrationX509Options.donor, + {setParameter: {tenantMigrationDisableX509Auth: true}}) + }); + const recipientRst = new ReplSetTest({ + nodes: 1, + name: "recipient", + nodeOptions: Object.assign(migrationX509Options.recipient, + {setParameter: {tenantMigrationDisableX509Auth: true}}) + }); + + donorRst.startSet(); + donorRst.initiate(); + + recipientRst.startSet(); + recipientRst.initiate(); + + const tenantMigrationTest = + new TenantMigrationTest({name: jsTestName(), donorRst, recipientRst}); + if (!tenantMigrationTest.isFeatureFlagEnabled()) { + jsTestLog("Skipping test because the tenant migrations feature flag is disabled"); + donorRst.stopSet(); + recipientRst.stopSet(); + return; + } + + const migrationId = UUID(); + const donorStartMigrationCmdObj = { + donorStartMigration: 1, + migrationId: migrationId, + recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), + tenantId: kTenantId, + readPreference: kReadPreference + }; + const stateRes = assert.commandWorked(TenantMigrationUtil.runTenantMigrationCommand( + donorStartMigrationCmdObj, + donorRst, + false /* retryOnRetryableErrors */, + TenantMigrationUtil.isMigrationCompleted /* shouldStopFunc */)); + assert.eq(stateRes.state, TenantMigrationTest.State.kCommitted); + assert.commandWorked( + donorRst.getPrimary().adminCommand({donorForgetMigration: 1, migrationId: migrationId})); +})(); + +(() => { + jsTest.log("Test that tenant migration doesn't fail if SSL is not enabled on the donor and " + + "the recipient and tenantMigrationDisableX509Auth=true"); + + const donorRst = new ReplSetTest({ + nodes: 1, + name: "donor", + nodeOptions: {setParameter: {tenantMigrationDisableX509Auth: true}} + }); + const recipientRst = new ReplSetTest({ + nodes: 1, + name: "recipient", + nodeOptions: {setParameter: {tenantMigrationDisableX509Auth: true}} + }); + + donorRst.startSet(); + donorRst.initiate(); + + recipientRst.startSet(); + recipientRst.initiate(); + + const tenantMigrationTest = + new TenantMigrationTest({name: jsTestName(), donorRst, recipientRst}); + if (!tenantMigrationTest.isFeatureFlagEnabled()) { + jsTestLog("Skipping test because the tenant migrations feature flag is disabled"); + donorRst.stopSet(); + recipientRst.stopSet(); + return; + } + + const donorStartMigrationCmdObj = { + donorStartMigration: 1, + migrationId: UUID(), + recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), + tenantId: kTenantId, + readPreference: kReadPreference + }; + + const stateRes = assert.commandWorked(TenantMigrationUtil.runTenantMigrationCommand( + donorStartMigrationCmdObj, + donorRst, + false /* retryOnRetryableErrors */, + TenantMigrationUtil.isMigrationCompleted /* shouldStopFunc */)); + assert.eq(stateRes.state, TenantMigrationTest.State.kCommitted); + + donorRst.stopSet(); + recipientRst.stopSet(); + tenantMigrationTest.stop(); +})(); + +(() => { + jsTest.log( + "Test that input certificate fields are not used when tenantMigrationDisableX509Auth=true"); + const migrationX509Options = TenantMigrationUtil.makeX509OptionsForTest(); + const donorRst = new ReplSetTest({ + nodes: 1, + name: "donor", + nodeOptions: Object.assign(migrationX509Options.donor, + {setParameter: {tenantMigrationDisableX509Auth: true}}) + }); + const recipientRst = new ReplSetTest({ + nodes: 1, + name: "recipient", + nodeOptions: Object.assign(migrationX509Options.recipient, + {setParameter: {tenantMigrationDisableX509Auth: true}}) + }); + + donorRst.startSet(); + donorRst.initiate(); + + recipientRst.startSet(); + recipientRst.initiate(); + + const tenantMigrationTest = + new TenantMigrationTest({name: jsTestName(), donorRst, recipientRst}); + if (!tenantMigrationTest.isFeatureFlagEnabled()) { + jsTestLog("Skipping test because the tenant migrations feature flag is disabled"); + donorRst.stopSet(); + recipientRst.stopSet(); + return; + } + + const donorStartMigrationCmdObj = { + donorStartMigration: 1, + migrationId: UUID(), + recipientConnectionString: tenantMigrationTest.getRecipientRst().getURL(), + tenantId: kTenantId, + readPreference: kReadPreference, + donorCertificateForRecipient: kExpiredMigrationCertificates.donorCertificateForRecipient, + recipientCertificateForDonor: kExpiredMigrationCertificates.recipientCertificateForDonor, + }; + const stateRes = assert.commandWorked(TenantMigrationUtil.runTenantMigrationCommand( + donorStartMigrationCmdObj, + donorRst, + false /* retryOnRetryableErrors */, + TenantMigrationUtil.isMigrationCompleted /* shouldStopFunc */)); + assert.eq(stateRes.state, TenantMigrationTest.State.kCommitted); + + donorRst.stopSet(); + recipientRst.stopSet(); + tenantMigrationTest.stop(); +})(); })(); diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp index add2ef18e6a..1570f370213 100644 --- a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp @@ -64,13 +64,24 @@ public: const auto& cmd = request(); - const TenantMigrationDonorDocument stateDoc( - cmd.getMigrationId(), - cmd.getRecipientConnectionString().toString(), - cmd.getReadPreference(), - cmd.getTenantId().toString(), - cmd.getDonorCertificateForRecipient(), - cmd.getRecipientCertificateForDonor()); + TenantMigrationDonorDocument stateDoc(cmd.getMigrationId(), + cmd.getRecipientConnectionString().toString(), + cmd.getReadPreference(), + cmd.getTenantId().toString()); + + if (!repl::tenantMigrationDisableX509Auth) { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "'" << Request::kDonorCertificateForRecipientFieldName + << "' is a required field", + cmd.getDonorCertificateForRecipient()); + uassert(ErrorCodes::InvalidOptions, + str::stream() << "'" << Request::kRecipientCertificateForDonorFieldName + << "' is a required field", + cmd.getRecipientCertificateForDonor()); + stateDoc.setDonorCertificateForRecipient(cmd.getDonorCertificateForRecipient()); + stateDoc.setRecipientCertificateForDonor(cmd.getRecipientCertificateForDonor()); + } + const auto stateDocBson = stateDoc.toBSON(); auto donorService = diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.idl b/src/mongo/db/commands/tenant_migration_donor_cmds.idl index f81b718cffa..3ba8a06ecca 100644 --- a/src/mongo/db/commands/tenant_migration_donor_cmds.idl +++ b/src/mongo/db/commands/tenant_migration_donor_cmds.idl @@ -80,11 +80,15 @@ commands: The SSL certificate and private key that the donor should use to authenticate to the recipient. type: TenantMigrationPEMPayload + # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + optional: true recipientCertificateForDonor: description: >- The SSL certificate and private key that the recipient should use to authenticate to the donor. type: TenantMigrationPEMPayload + # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + optional: true donorForgetMigration: description: "Parser for the 'donorForgetMigration' command." diff --git a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp index c963bb35017..0dc4c19db20 100644 --- a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp @@ -64,14 +64,20 @@ public: const auto& cmd = request(); - const TenantMigrationRecipientDocument stateDoc( - cmd.getMigrationId(), - cmd.getDonorConnectionString().toString(), - cmd.getTenantId().toString(), - cmd.getReadPreference(), - cmd.getRecipientCertificateForDonor()); - const auto stateDocBson = stateDoc.toBSON(); + TenantMigrationRecipientDocument stateDoc(cmd.getMigrationId(), + cmd.getDonorConnectionString().toString(), + cmd.getTenantId().toString(), + cmd.getReadPreference()); + + if (!repl::tenantMigrationDisableX509Auth) { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "'" << Request::kRecipientCertificateForDonorFieldName + << "' is a required field", + cmd.getRecipientCertificateForDonor()); + stateDoc.setRecipientCertificateForDonor(cmd.getRecipientCertificateForDonor()); + } + const auto stateDocBson = stateDoc.toBSON(); if (MONGO_unlikely(returnResponseOkForRecipientSyncDataCmd.shouldFail())) { LOGV2(4879608, @@ -169,12 +175,17 @@ public: // recipientSyncData. But even if that's the case, we still need to create an instance // and persist a state document that's marked garbage collectable (which is done by the // main chain). - const TenantMigrationRecipientDocument stateDoc( - cmd.getMigrationId(), - cmd.getDonorConnectionString().toString(), - cmd.getTenantId().toString(), - cmd.getReadPreference(), - cmd.getRecipientCertificateForDonor()); + TenantMigrationRecipientDocument stateDoc(cmd.getMigrationId(), + cmd.getDonorConnectionString().toString(), + cmd.getTenantId().toString(), + cmd.getReadPreference()); + if (!repl::tenantMigrationDisableX509Auth) { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "'" << Request::kRecipientCertificateForDonorFieldName + << "' is a required field", + cmd.getRecipientCertificateForDonor()); + stateDoc.setRecipientCertificateForDonor(cmd.getRecipientCertificateForDonor()); + } auto recipientInstance = repl::TenantMigrationRecipientService::Instance::getOrCreate( opCtx, recipientService, stateDoc.toBSON()); diff --git a/src/mongo/db/commands/tenant_migration_recipient_cmds.idl b/src/mongo/db/commands/tenant_migration_recipient_cmds.idl index a3c4fb991d2..71a5eb68f7b 100644 --- a/src/mongo/db/commands/tenant_migration_recipient_cmds.idl +++ b/src/mongo/db/commands/tenant_migration_recipient_cmds.idl @@ -79,6 +79,8 @@ structs: The SSL certificate and private key that the recipient should use to authenticate to the donor. type: TenantMigrationPEMPayload + # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + optional: true commands: recipientSyncData: diff --git a/src/mongo/db/repl/repl_server_parameters.idl b/src/mongo/db/repl/repl_server_parameters.idl index a1c56d2c6f7..e58efd020c0 100644 --- a/src/mongo/db/repl/repl_server_parameters.idl +++ b/src/mongo/db/repl/repl_server_parameters.idl @@ -444,6 +444,15 @@ server_parameters: validator: gte: 1 + # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + tenantMigrationDisableX509Auth: + description: >- + Disable x509 authentication for all ingoing and outgoing tenant migrations. + set_at: [ startup ] + cpp_vartype: bool + cpp_varname: tenantMigrationDisableX509Auth + default: false + feature_flags: featureFlagTenantMigrations: description: >- diff --git a/src/mongo/db/repl/tenant_migration_donor_service.cpp b/src/mongo/db/repl/tenant_migration_donor_service.cpp index 19e6ed500bf..9e42924363d 100644 --- a/src/mongo/db/repl/tenant_migration_donor_service.cpp +++ b/src/mongo/db/repl/tenant_migration_donor_service.cpp @@ -129,7 +129,9 @@ TenantMigrationDonorService::Instance::Instance(ServiceContext* const serviceCon _stateDoc(tenant_migration_access_blocker::parseDonorStateDocument(initialState)), _instanceName(kServiceName + "-" + _stateDoc.getTenantId()), _recipientUri( - uassertStatusOK(MongoURI::parse(_stateDoc.getRecipientConnectionString().toString()))) { + uassertStatusOK(MongoURI::parse(_stateDoc.getRecipientConnectionString().toString()))), + _sslMode(repl::tenantMigrationDisableX509Auth ? transport::kGlobalSSLMode + : transport::kEnableSSL) { _recipientCmdExecutor = _makeRecipientCmdExecutor(); _recipientCmdExecutor->startup(); @@ -192,20 +194,31 @@ TenantMigrationDonorService::Instance::_makeRecipientCmdExecutor() { auto hookList = std::make_unique<rpc::EgressMetadataHookList>(); auto connPoolOptions = executor::ConnectionPool::Options(); -#ifdef MONGO_CONFIG_SSL - uassert(ErrorCodes::IllegalOperation, - "Cannot run tenant migration as SSL is not enabled", - getSSLGlobalParams().sslMode.load() != SSLParams::SSLMode_disabled); auto donorCertificate = _stateDoc.getDonorCertificateForRecipient(); - auto donorSSLClusterPEMPayload = donorCertificate.getCertificate().toString() + "\n" + - donorCertificate.getPrivateKey().toString(); - connPoolOptions.transientSSLParams = - TransientSSLParams{_recipientUri.connectionString(), std::move(donorSSLClusterPEMPayload)}; + auto recipientCertificate = _stateDoc.getRecipientCertificateForDonor(); + if (donorCertificate) { + invariant(!repl::tenantMigrationDisableX509Auth); + invariant(recipientCertificate); + invariant(_sslMode == transport::kEnableSSL); +#ifdef MONGO_CONFIG_SSL + uassert(ErrorCodes::IllegalOperation, + "Cannot run tenant migration with x509 authentication as SSL is not enabled", + getSSLGlobalParams().sslMode.load() != SSLParams::SSLMode_disabled); + auto donorSSLClusterPEMPayload = donorCertificate->getCertificate().toString() + "\n" + + donorCertificate->getPrivateKey().toString(); + connPoolOptions.transientSSLParams = TransientSSLParams{ + _recipientUri.connectionString(), std::move(donorSSLClusterPEMPayload)}; #else - // If SSL is not supported, the donorStartMigration command should have failed certificate field - // validation. - MONGO_UNREACHABLE; + // If SSL is not supported, the donorStartMigration command should have failed certificate + // field validation. + MONGO_UNREACHABLE; #endif + } else { + invariant(repl::tenantMigrationDisableX509Auth); + invariant(!recipientCertificate); + invariant(_sslMode == transport::kGlobalSSLMode); + } + return std::make_shared<executor::ThreadPoolTaskExecutor>( std::make_unique<ThreadPool>(threadPoolOptions), executor::makeNetworkInterface( @@ -359,7 +372,7 @@ TenantMigrationDonorService::Instance::_fetchAndStoreRecipientClusterTimeKeyDocs executor::RemoteCommandRequest::kNoTimeout, /* getMoreNetworkTimeout */ RemoteCommandRetryScheduler::makeRetryPolicy<ErrorCategory::RetriableError>( kMaxRecipientKeyDocsFindAttempts, executor::RemoteCommandRequest::kNoTimeout), - transport::kEnableSSL); + _sslMode); uassertStatusOK(fetcher->schedule()); { @@ -596,7 +609,7 @@ ExecutorFuture<void> TenantMigrationDonorService::Instance::_sendCommandToRecipi rpc::makeEmptyMetadata(), nullptr, kRecipientSyncDataTimeout); - request.sslMode = transport::kEnableSSL; + request.sslMode = _sslMode; return (_recipientCmdExecutor) ->scheduleRemoteCommand(std::move(request), @@ -629,13 +642,17 @@ ExecutorFuture<void> TenantMigrationDonorService::Instance::_sendRecipientSyncDa const auto cmdObj = [&] { auto donorConnString = repl::ReplicationCoordinator::get(opCtx)->getConfig().getConnectionString(); + RecipientSyncData request; request.setDbName(NamespaceString::kAdminDb); - request.setMigrationRecipientCommonData({_stateDoc.getId(), - donorConnString.toString(), - _stateDoc.getTenantId().toString(), - _stateDoc.getReadPreference(), - _stateDoc.getRecipientCertificateForDonor()}); + + MigrationRecipientCommonData commonData(_stateDoc.getId(), + donorConnString.toString(), + _stateDoc.getTenantId().toString(), + _stateDoc.getReadPreference()); + commonData.setRecipientCertificateForDonor(_stateDoc.getRecipientCertificateForDonor()); + request.setMigrationRecipientCommonData(commonData); + request.setReturnAfterReachingDonorTimestamp(_stateDoc.getBlockTimestamp()); return request.toBSON(BSONObj()); }(); @@ -652,13 +669,17 @@ ExecutorFuture<void> TenantMigrationDonorService::Instance::_sendRecipientForget auto donorConnString = repl::ReplicationCoordinator::get(opCtx)->getConfig().getConnectionString(); + RecipientForgetMigration request; request.setDbName(NamespaceString::kAdminDb); - request.setMigrationRecipientCommonData({_stateDoc.getId(), - donorConnString.toString(), - _stateDoc.getTenantId().toString(), - _stateDoc.getReadPreference(), - _stateDoc.getRecipientCertificateForDonor()}); + + MigrationRecipientCommonData commonData(_stateDoc.getId(), + donorConnString.toString(), + _stateDoc.getTenantId().toString(), + _stateDoc.getReadPreference()); + commonData.setRecipientCertificateForDonor(_stateDoc.getRecipientCertificateForDonor()); + request.setMigrationRecipientCommonData(commonData); + return _sendCommandToRecipient(executor, recipientTargeterRS, request.toBSON(BSONObj())); } diff --git a/src/mongo/db/repl/tenant_migration_donor_service.h b/src/mongo/db/repl/tenant_migration_donor_service.h index 8854b736987..3c33846cc54 100644 --- a/src/mongo/db/repl/tenant_migration_donor_service.h +++ b/src/mongo/db/repl/tenant_migration_donor_service.h @@ -149,8 +149,9 @@ public: const NamespaceString _stateDocumentsNS = NamespaceString::kTenantMigrationDonorsNamespace; /** - * Makes a task executor for executing commands against the recipient on an SSL connection - * that uses the migration certificate. + * Makes a task executor for executing commands against the recipient. If the server + * parameter 'tenantMigrationDisableX509Auth' is false, configures the executor to use the + * migration certificate to establish an SSL connection to the recipient. */ std::shared_ptr<executor::ThreadPoolTaskExecutor> _makeRecipientCmdExecutor(); @@ -226,6 +227,8 @@ public: TenantMigrationDonorDocument _stateDoc; const std::string _instanceName; const MongoURI _recipientUri; + // TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + const transport::ConnectSSLMode _sslMode; // Task executor used for executing commands against the recipient. std::shared_ptr<executor::TaskExecutor> _recipientCmdExecutor; diff --git a/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp b/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp index 5246696ed02..fff534b61c0 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_entry_helpers_test.cpp @@ -113,8 +113,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat migrationUUID, "donor-rs0/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + activeTenantAStateDoc.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), activeTenantAStateDoc)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), activeTenantAStateDoc)); @@ -122,8 +122,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc1(migrationUUID, "donor-rs1/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc1.setRecipientCertificateForDonor(kRecipientPEMPayload); auto status = insertStateDoc(opCtx.get(), stateDoc1); ASSERT_EQUALS(ErrorCodes::ConflictingOperationInProgress, status.code()); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), activeTenantAStateDoc)); @@ -132,8 +132,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc2(migrationUUID, "donor-rs0/localhost:12345", "tenantB", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc2.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( insertStateDoc(opCtx.get(), stateDoc2), DBException, ErrorCodes::DuplicateKey); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), activeTenantAStateDoc)); @@ -142,8 +142,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc3(UUID::gen(), "donor-rs0/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc3.setRecipientCertificateForDonor(kRecipientPEMPayload); status = insertStateDoc(opCtx.get(), stateDoc3); ASSERT_EQUALS(ErrorCodes::ConflictingOperationInProgress, status.code()); ASSERT_FALSE(checkStateDocPersisted(opCtx.get(), stateDoc3)); @@ -152,8 +152,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, AddTenantMigrationRecipientStat TenantMigrationRecipientDocument stateDoc4(UUID::gen(), "donor-rs0/localhost:12345", "tenantB", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc4.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc4)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), stateDoc4)); } @@ -167,8 +167,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, migrationUUID, "donor-rs0/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + inactiveTenantAStateDoc.setRecipientCertificateForDonor(kRecipientPEMPayload); inactiveTenantAStateDoc.setExpireAt(Date_t::now()); ASSERT_OK(insertStateDoc(opCtx.get(), inactiveTenantAStateDoc)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), inactiveTenantAStateDoc)); @@ -177,8 +177,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc1(migrationUUID, "donor-rs1/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc1.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( insertStateDoc(opCtx.get(), stateDoc1), DBException, ErrorCodes::DuplicateKey); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), inactiveTenantAStateDoc)); @@ -187,8 +187,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc2(migrationUUID, "donor-rs0/localhost:12345", "tenantB", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc2.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_THROWS_CODE( insertStateDoc(opCtx.get(), stateDoc2), DBException, ErrorCodes::DuplicateKey); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), inactiveTenantAStateDoc)); @@ -197,8 +197,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc3(UUID::gen(), "donor-rs0/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc3.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc3)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), stateDoc3)); @@ -206,8 +206,8 @@ TEST_F(TenantMigrationRecipientEntryHelpersTest, TenantMigrationRecipientDocument stateDoc4(UUID::gen(), "donor-rs0/localhost:12345", "tenantC", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + stateDoc4.setRecipientCertificateForDonor(kRecipientPEMPayload); ASSERT_OK(insertStateDoc(opCtx.get(), stateDoc4)); ASSERT_TRUE(checkStateDocPersisted(opCtx.get(), stateDoc4)); } diff --git a/src/mongo/db/repl/tenant_migration_recipient_service.cpp b/src/mongo/db/repl/tenant_migration_recipient_service.cpp index 8d893821f25..4d61601a2bf 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_service.cpp @@ -199,21 +199,27 @@ TenantMigrationRecipientService::Instance::Instance( _donorConnectionString(_stateDoc.getDonorConnectionString().toString()), _donorUri(uassertStatusOK(MongoURI::parse(_stateDoc.getDonorConnectionString().toString()))), _readPreference(_stateDoc.getReadPreference()), - _transientSSLParams([&]() -> TransientSSLParams { + _transientSSLParams([&]() -> boost::optional<TransientSSLParams> { + if (auto recipientCertificate = _stateDoc.getRecipientCertificateForDonor()) { + invariant(!repl::tenantMigrationDisableX509Auth); #ifdef MONGO_CONFIG_SSL - uassert(ErrorCodes::IllegalOperation, - "Cannot run tenant migration as SSL is not enabled", - getSSLGlobalParams().sslMode.load() != SSLParams::SSLMode_disabled); - auto recipientCertificate = _stateDoc.getRecipientCertificateForDonor(); - auto recipientSSLClusterPEMPayload = recipientCertificate.getCertificate().toString() + - "\n" + recipientCertificate.getPrivateKey().toString(); - return TransientSSLParams{_donorUri.connectionString(), - std::move(recipientSSLClusterPEMPayload)}; + uassert(ErrorCodes::IllegalOperation, + "Cannot run tenant migration with x509 authentication as SSL is not enabled", + getSSLGlobalParams().sslMode.load() != SSLParams::SSLMode_disabled); + auto recipientSSLClusterPEMPayload = + recipientCertificate->getCertificate().toString() + "\n" + + recipientCertificate->getPrivateKey().toString(); + return TransientSSLParams{_donorUri.connectionString(), + std::move(recipientSSLClusterPEMPayload)}; #else - // If SSL is not supported, the recipientSyncData command should have failed certificate - // field validation. - MONGO_UNREACHABLE; + // If SSL is not supported, the recipientSyncData command should have failed + // certificate field validation. + MONGO_UNREACHABLE; #endif + } else { + invariant(repl::tenantMigrationDisableX509Auth); + return boost::none; + } }()) { } @@ -323,7 +329,7 @@ std::unique_ptr<DBClientConnection> TenantMigrationRecipientService::Instance::_ 0 /* socketTimeout */, nullptr /* uri */, nullptr /* apiParameters */, - &_transientSSLParams); + _transientSSLParams ? &_transientSSLParams.get() : nullptr); if (!swClientBase.isOK()) { LOGV2_ERROR(4880400, "Failed to connect to migration donor", @@ -335,12 +341,20 @@ std::unique_ptr<DBClientConnection> TenantMigrationRecipientService::Instance::_ uassertStatusOK(swClientBase.getStatus()); } + auto clientBase = swClientBase.getValue().release(); + // ConnectionString::connect() always returns a DBClientConnection in a unique_ptr of // DBClientBase type. - std::unique_ptr<DBClientConnection> client( - checked_cast<DBClientConnection*>(swClientBase.getValue().release())); - - if (MONGO_likely(!skipTenantMigrationRecipientAuth.shouldFail())) { + std::unique_ptr<DBClientConnection> client(checked_cast<DBClientConnection*>(clientBase)); + + // Authenticate connection to the donor. + if (!_transientSSLParams) { + uassertStatusOK( + replAuthenticate(clientBase) + .withContext(str::stream() + << "TenantMigrationRecipientService failed to authenticate to " + << serverAddress)); + } else if (MONGO_likely(!skipTenantMigrationRecipientAuth.shouldFail())) { client->auth(auth::createInternalX509AuthDocument()); } diff --git a/src/mongo/db/repl/tenant_migration_recipient_service.h b/src/mongo/db/repl/tenant_migration_recipient_service.h index a5c4317924b..58d0197b6d9 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service.h +++ b/src/mongo/db/repl/tenant_migration_recipient_service.h @@ -289,8 +289,10 @@ public: SemiFuture<void> _markStateDocAsGarbageCollectable(); /** - * Creates a client, connects it to the donor, and authenticates it using the migration - * certificate. Throws a user assertion on failure. + * Creates a client, connects it to the donor. If '_transientSSLParams' is not none, uses + * the migration certificate to do SSL authentication. Otherwise, uses the default + * authentication mode. Throws a user assertion on failure. + * */ std::unique_ptr<DBClientConnection> _connectAndAuth(const HostAndPort& serverAddress, StringData applicationName); @@ -414,12 +416,15 @@ public: // This data is provided in the initial state doc and never changes. We keep copies to // avoid having to obtain the mutex to access them. - const std::string _tenantId; // (R) - const UUID _migrationUuid; // (R) - const std::string _donorConnectionString; // (R) - const MongoURI _donorUri; // (R) - const ReadPreferenceSetting _readPreference; // (R) - const TransientSSLParams _transientSSLParams; // (R) + const std::string _tenantId; // (R) + const UUID _migrationUuid; // (R) + const std::string _donorConnectionString; // (R) + const MongoURI _donorUri; // (R) + const ReadPreferenceSetting _readPreference; // (R) + // TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + // Transient SSL params created based on the state doc if the server parameter + // 'tenantMigrationDisableX509Auth' is false. + const boost::optional<TransientSSLParams> _transientSSLParams = boost::none; // (R) std::shared_ptr<ReplicaSetMonitor> _donorReplicaSetMonitor; // (M) diff --git a/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp b/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp index 62719125707..b6bdd2c83fb 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_service_test.cpp @@ -414,8 +414,8 @@ TEST_F(TenantMigrationRecipientServiceTest, BasicTenantMigrationRecipientService migrationUUID, "donor-rs/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly()), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly())); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -439,8 +439,8 @@ TEST_F(TenantMigrationRecipientServiceTest, InstanceReportsErrorOnFailureWhilePe migrationUUID, "donor-rs/localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly()), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly, TagSet::primaryOnly())); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -471,8 +471,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -519,8 +519,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_S migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::SecondaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::SecondaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -572,8 +572,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -627,8 +627,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. auto hangFp = @@ -699,8 +699,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. auto hangFp = @@ -766,8 +766,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::Nearest), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::Nearest)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. auto hangFp = @@ -841,8 +841,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryPreferred), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. auto hangFp = @@ -907,8 +907,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryPreferred), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Hang the migration before attempting to connect to clients. auto hangFp = @@ -978,8 +978,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_P migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryPreferred), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryPreferred)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -1021,8 +1021,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientConnection_B migrationUUID, "broken,connect,string,no,set,name", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -1042,8 +1042,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, "localhost:12345", "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -1066,8 +1066,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientGetStartOpTi migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -1103,8 +1103,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -1145,8 +1145,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientGetStartOpTi migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -1189,8 +1189,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -1223,8 +1223,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. Fail to populate the remote oplog mock. auto opCtx = makeOperationContext(); @@ -1256,8 +1256,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientStartOplogFe migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto opCtx = makeOperationContext(); std::shared_ptr<TenantMigrationRecipientService::Instance> instance; @@ -1309,8 +1309,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientStartsCloner migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto opCtx = makeOperationContext(); std::shared_ptr<TenantMigrationRecipientService::Instance> instance; @@ -1362,8 +1362,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherFailsDuringOplogApplicat migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. MockRemoteDBServer* const _donorServer = @@ -1416,8 +1416,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherResumesFromTopOfOplogBuf migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing // migration on startup and will resume oplog fetching from the appropriate optime. @@ -1519,8 +1519,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogFetcherNoDocInBufferToResumeFro migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing // migration on startup and will attempt to resume oplog fetching from the appropriate optime. @@ -1624,8 +1624,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierResumesFromLastNoOpOplog migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing // migration on startup and will attempt to resume oplog fetching from the appropriate optime. @@ -1743,8 +1743,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierResumesFromStartDonorApp migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing // migration on startup and will attempt to resume oplog fetching from the appropriate optime. @@ -1897,8 +1897,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // We skip cloning here as a way to simulate that the recipient service has detected an existing // migration on startup and will resume oplog fetching from the appropriate optime. @@ -2001,8 +2001,8 @@ TEST_F(TenantMigrationRecipientServiceTest, OplogApplierFails) { migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. MockRemoteDBServer* const _donorServer = @@ -2065,8 +2065,8 @@ TEST_F(TenantMigrationRecipientServiceTest, StoppingApplierAllowsCompletion) { migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. MockRemoteDBServer* const _donorServer = @@ -2118,8 +2118,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientAddResumeTok migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. MockRemoteDBServer* const _donorServer = @@ -2218,8 +2218,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_BeforeRun) migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto fp = globalFailPointRegistry().find("pauseBeforeRunTenantMigrationRecipientInstance"); fp->setMode(FailPoint::alwaysOn); @@ -2253,8 +2253,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_FailToIniti migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto opCtx = makeOperationContext(); auto instance = repl::TenantMigrationRecipientService::Instance::getOrCreate( @@ -2285,8 +2285,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_WaitUntilSt migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); auto fp = globalFailPointRegistry().find("pauseAfterRunTenantMigrationRecipientInstance"); auto initialTimesEntered = fp->setMode(FailPoint::alwaysOn); @@ -2365,8 +2365,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterStartO migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -2426,8 +2426,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterConsis migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. MockRemoteDBServer* const _donorServer = @@ -2512,8 +2512,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_AfterFail) migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Skip the cloners in this test, so we provide an empty list of databases. MockRemoteDBServer* const _donorServer = @@ -2591,8 +2591,8 @@ TEST_F(TenantMigrationRecipientServiceTest, RecipientForgetMigration_FailToMarkG migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -2640,8 +2640,8 @@ TEST_F(TenantMigrationRecipientServiceTest, TenantMigrationRecipientServiceRecor migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Create and start the instance. auto opCtx = makeOperationContext(); @@ -2672,8 +2672,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Add an FCV value as if it was from a previous attempt. auto currentFCV = serverGlobalParams.featureCompatibility.getVersion(); @@ -2708,8 +2708,8 @@ TEST_F(TenantMigrationRecipientServiceTest, migrationUUID, replSet.getConnectionString(), "tenantA", - ReadPreferenceSetting(ReadPreference::PrimaryOnly), - kRecipientPEMPayload); + ReadPreferenceSetting(ReadPreference::PrimaryOnly)); + initialStateDocument.setRecipientCertificateForDonor(kRecipientPEMPayload); // Add an FCV value as if it was from a previous attempt, making sure we set a different // version from the one we currently have. diff --git a/src/mongo/db/repl/tenant_migration_state_machine.idl b/src/mongo/db/repl/tenant_migration_state_machine.idl index 6b458f3d8b5..31e4e4f60a4 100644 --- a/src/mongo/db/repl/tenant_migration_state_machine.idl +++ b/src/mongo/db/repl/tenant_migration_state_machine.idl @@ -113,11 +113,15 @@ structs: The SSL certificate and private key that the donor should use to authenticate to the recipient. type: TenantMigrationPEMPayload + # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + optional: true recipientCertificateForDonor: description: >- The SSL certificate and private key that the recipient should use to authenticate to the donor. type: TenantMigrationPEMPayload + # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + optional: true tenantMigrationRecipientDocument: description: "Represents an in-progress tenant migration on the migration recipient." @@ -183,10 +187,12 @@ structs: The SSL certificate and private key that the recipient should use to authenticate to the donor. type: TenantMigrationPEMPayload + # TODO (SERVER-54085): Remove server parameter tenantMigrationDisableX509Auth. + optional: true recipientPrimaryStartingFCV: description: >- The featureCompatibilityVersion of the recipient as recorded at the beginning of a migration attempt. Implicitly includes information on current upgrade or downgrade state. type: fcv_string - optional: true
\ No newline at end of file + optional: true |