summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/audit.h2
-rw-r--r--src/mongo/db/auth/sasl_commands.cpp12
-rw-r--r--src/mongo/db/commands.cpp24
-rw-r--r--src/mongo/db/commands.h4
-rw-r--r--src/mongo/db/commands/tenant_migration_donor_cmds.cpp9
-rw-r--r--src/mongo/db/commands/tenant_migration_donor_cmds.idl10
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp8
-rw-r--r--src/mongo/db/repl/SConscript2
-rw-r--r--src/mongo/db/repl/tenant_migration_donor_service.cpp66
-rw-r--r--src/mongo/db/repl/tenant_migration_pem_payload.idl50
-rw-r--r--src/mongo/db/repl/tenant_migration_state_machine.idl11
-rw-r--r--src/mongo/db/repl/tenant_migration_util.h13
12 files changed, 151 insertions, 60 deletions
diff --git a/src/mongo/db/audit.h b/src/mongo/db/audit.h
index 364ac43cae7..c01619ed580 100644
--- a/src/mongo/db/audit.h
+++ b/src/mongo/db/audit.h
@@ -62,7 +62,7 @@ namespace audit {
class CommandInterface {
public:
virtual ~CommandInterface() = default;
- virtual StringData sensitiveFieldName() const = 0;
+ virtual std::set<StringData> sensitiveFieldNames() const = 0;
virtual void snipForLogging(mutablebson::Document* cmdObj) const = 0;
virtual StringData getName() const = 0;
virtual NamespaceString ns() const = 0;
diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp
index f0b3783cb1f..e5e00a6b160 100644
--- a/src/mongo/db/auth/sasl_commands.cpp
+++ b/src/mongo/db/auth/sasl_commands.cpp
@@ -67,6 +67,8 @@ const bool autoAuthorizeDefault = true;
class CmdSaslStart : public BasicCommand {
public:
+ static constexpr StringData kPayloadField = "payload"_sd;
+
CmdSaslStart();
virtual ~CmdSaslStart();
@@ -78,8 +80,8 @@ public:
const BSONObj&,
std::vector<Privilege>*) const {}
- StringData sensitiveFieldName() const final {
- return "payload"_sd;
+ std::set<StringData> sensitiveFieldNames() const final {
+ return {kPayloadField};
}
virtual bool run(OperationContext* opCtx,
@@ -101,6 +103,8 @@ public:
class CmdSaslContinue : public BasicCommand {
public:
+ static constexpr StringData kPayloadField = "payload"_sd;
+
CmdSaslContinue();
virtual ~CmdSaslContinue();
@@ -111,8 +115,8 @@ public:
const BSONObj&,
std::vector<Privilege>*) const {}
- StringData sensitiveFieldName() const final {
- return "payload"_sd;
+ std::set<StringData> sensitiveFieldNames() const final {
+ return {kPayloadField};
}
virtual bool run(OperationContext* opCtx,
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 025def0f609..6b279d1ebfe 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -214,11 +214,11 @@ void CommandHelpers::auditLogAuthEvent(OperationContext* opCtx,
}
}
- StringData sensitiveFieldName() const override {
+ std::set<StringData> sensitiveFieldNames() const override {
if (_invocation) {
- return _invocation->definition()->sensitiveFieldName();
+ return _invocation->definition()->sensitiveFieldNames();
}
- return StringData{};
+ return {};
}
StringData getName() const override {
@@ -898,15 +898,15 @@ private:
Command::~Command() = default;
void Command::snipForLogging(mutablebson::Document* cmdObj) const {
- StringData sensitiveField = sensitiveFieldName();
- if (!sensitiveField.empty()) {
-
- for (mutablebson::Element pwdElement =
- mutablebson::findFirstChildNamed(cmdObj->root(), sensitiveField);
- pwdElement.ok();
- pwdElement =
- mutablebson::findElementNamed(pwdElement.rightSibling(), sensitiveField)) {
- uassertStatusOK(pwdElement.setValueString("xxx"));
+ auto sensitiveFields = sensitiveFieldNames();
+ if (!sensitiveFields.empty()) {
+ for (auto& sensitiveField : sensitiveFields) {
+ for (mutablebson::Element element =
+ mutablebson::findFirstChildNamed(cmdObj->root(), sensitiveField);
+ element.ok();
+ element = mutablebson::findElementNamed(element.rightSibling(), sensitiveField)) {
+ uassertStatusOK(element.setValueString("xxx"));
+ }
}
}
}
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index 140d7bccee4..dfb4cdba633 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -484,8 +484,8 @@ public:
* The default snipForLogging shall remove these field names. Auditing shall not
* include these fields in audit outputs.
*/
- virtual StringData sensitiveFieldName() const {
- return StringData{};
+ virtual std::set<StringData> sensitiveFieldNames() const {
+ return {};
}
/**
diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp
index a4a838277b3..eacf88bde84 100644
--- a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp
+++ b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp
@@ -44,6 +44,11 @@ public:
using Request = DonorStartMigration;
using Response = DonorStartMigrationResponse;
+ std::set<StringData> sensitiveFieldNames() const final {
+ return {Request::kDonorCertificateForRecipientFieldName,
+ Request::kRecipientCertificateForDonorFieldName};
+ }
+
class Invocation : public InvocationBase {
public:
@@ -61,7 +66,9 @@ public:
TenantMigrationDonorDocument(requestBody.getMigrationId(),
requestBody.getRecipientConnectionString().toString(),
requestBody.getReadPreference(),
- requestBody.getTenantId().toString())
+ requestBody.getTenantId().toString(),
+ requestBody.getDonorCertificateForRecipient(),
+ requestBody.getRecipientCertificateForDonor())
.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 c26b4848b26..ed211a408a4 100644
--- a/src/mongo/db/commands/tenant_migration_donor_cmds.idl
+++ b/src/mongo/db/commands/tenant_migration_donor_cmds.idl
@@ -74,6 +74,16 @@ commands:
readPreference:
description: "The read preference settings that the donor will pass on to the recipient."
type: readPreference
+ donorCertificateForRecipient:
+ description: >-
+ The SSL certificate and private key that the donor should use to authenticate to the
+ recipient.
+ type: TenantMigrationPEMPayload
+ recipientCertificateForDonor:
+ description: >-
+ The SSL certificate and private key that the recipient should use to authenticate to the
+ donor.
+ type: TenantMigrationPEMPayload
donorForgetMigration:
description: "Parser for the 'donorForgetMigration' command."
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index c19b3ab9efc..f88e75fc929 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -968,8 +968,8 @@ class CmdCreateUser : public CmdUMCTyped<CreateUserCommand, void> {
public:
static constexpr StringData kPwdField = "pwd"_sd;
- StringData sensitiveFieldName() const final {
- return kPwdField;
+ std::set<StringData> sensitiveFieldNames() const final {
+ return {kPwdField};
}
} cmdCreateUser;
@@ -1077,8 +1077,8 @@ class CmdUpdateUser : public CmdUMCTyped<UpdateUserCommand, void> {
public:
static constexpr StringData kPwdField = "pwd"_sd;
- StringData sensitiveFieldName() const final {
- return kPwdField;
+ std::set<StringData> sensitiveFieldNames() const final {
+ return {kPwdField};
}
} cmdUpdateUser;
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript
index e3e5c2a4e11..7b9492f4ebf 100644
--- a/src/mongo/db/repl/SConscript
+++ b/src/mongo/db/repl/SConscript
@@ -1269,6 +1269,7 @@ env.Library(
env.Library(
target='tenant_migration_state_machine_idl',
source=[
+ 'tenant_migration_pem_payload.idl',
'tenant_migration_state_machine.idl',
],
LIBDEPS=[
@@ -1276,6 +1277,7 @@ env.Library(
'$BUILD_DIR/mongo/client/connection_string',
'$BUILD_DIR/mongo/client/read_preference',
'$BUILD_DIR/mongo/idl/idl_parser',
+ '$BUILD_DIR/mongo/util/net/ssl_manager',
'optime',
'repl_coordinator_interface',
],
diff --git a/src/mongo/db/repl/tenant_migration_donor_service.cpp b/src/mongo/db/repl/tenant_migration_donor_service.cpp
index 039d622f908..981fe7aada8 100644
--- a/src/mongo/db/repl/tenant_migration_donor_service.cpp
+++ b/src/mongo/db/repl/tenant_migration_donor_service.cpp
@@ -221,24 +221,21 @@ ExecutorFuture<repl::OpTime> TenantMigrationDonorService::Instance::_insertState
return AsyncTry([this, self = shared_from_this()] {
auto opCtxHolder = cc().makeOperationContext();
auto opCtx = opCtxHolder.get();
- DBDirectClient client(opCtx);
- auto commandResponse = client.runCommand([&] {
- write_ops::Update updateOp(_stateDocumentsNS);
- auto updateModification =
- write_ops::UpdateModification::parseFromClassicUpdate(_stateDoc.toBSON());
- write_ops::UpdateOpEntry updateEntry(
- BSON(TenantMigrationDonorDocument::kIdFieldName << _stateDoc.getId()),
- updateModification);
- updateEntry.setMulti(false);
- updateEntry.setUpsert(true);
- updateOp.setUpdates({updateEntry});
+ AutoGetCollection collection(opCtx, _stateDocumentsNS, MODE_IX);
- return updateOp.serialize({});
- }());
+ writeConflictRetry(
+ opCtx, "tenantMigrationInsertStateDoc", _stateDocumentsNS.ns(), [&] {
+ const auto filter =
+ BSON(TenantMigrationDonorDocument::kIdFieldName << _stateDoc.getId());
+ const auto updateMod = BSON("$setOnInsert" << _stateDoc.toBSON());
+ auto updateResult = Helpers::upsert(
+ opCtx, _stateDocumentsNS.ns(), filter, updateMod, /*fromMigrate=*/false);
- const auto commandReply = commandResponse->getCommandReply();
- uassertStatusOK(getStatusFromWriteCommandReply(commandReply));
+ // '$setOnInsert' update operator can never modify an existing on-disk state
+ // doc.
+ invariant(!updateResult.numDocsModified);
+ });
return repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp();
})
@@ -348,31 +345,28 @@ ExecutorFuture<repl::OpTime> TenantMigrationDonorService::Instance::_updateState
ExecutorFuture<repl::OpTime>
TenantMigrationDonorService::Instance::_markStateDocumentAsGarbageCollectable(
std::shared_ptr<executor::ScopedTaskExecutor> executor, const CancelationToken& token) {
+ _stateDoc.setExpireAt(_serviceContext->getFastClockSource()->now() +
+ Milliseconds{repl::tenantMigrationGarbageCollectionDelayMS.load()});
+
return AsyncTry([this, self = shared_from_this()] {
auto opCtxHolder = cc().makeOperationContext();
auto opCtx = opCtxHolder.get();
- DBDirectClient client(opCtx);
- _stateDoc.setExpireAt(
- _serviceContext->getFastClockSource()->now() +
- Milliseconds{repl::tenantMigrationGarbageCollectionDelayMS.load()});
-
- auto commandResponse = client.runCommand([&] {
- write_ops::Update updateOp(_stateDocumentsNS);
- auto updateModification =
- write_ops::UpdateModification::parseFromClassicUpdate(_stateDoc.toBSON());
- write_ops::UpdateOpEntry updateEntry(
- BSON(TenantMigrationDonorDocument::kIdFieldName << _stateDoc.getId()),
- updateModification);
- updateEntry.setMulti(false);
- updateEntry.setUpsert(false);
- updateOp.setUpdates({updateEntry});
-
- return updateOp.serialize({});
- }());
-
- const auto commandReply = commandResponse->getCommandReply();
- uassertStatusOK(getStatusFromWriteCommandReply(commandReply));
+ AutoGetCollection collection(opCtx, _stateDocumentsNS, MODE_IX);
+
+ writeConflictRetry(
+ opCtx,
+ "tenantMigrationDonorMarkStateDocAsGarbageCollectable",
+ _stateDocumentsNS.ns(),
+ [&] {
+ const auto filter =
+ BSON(TenantMigrationDonorDocument::kIdFieldName << _stateDoc.getId());
+ const auto updateMod = _stateDoc.toBSON();
+ auto updateResult = Helpers::upsert(
+ opCtx, _stateDocumentsNS.ns(), filter, updateMod, /*fromMigrate=*/false);
+
+ invariant(updateResult.numDocsModified == 1);
+ });
return repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp();
})
diff --git a/src/mongo/db/repl/tenant_migration_pem_payload.idl b/src/mongo/db/repl/tenant_migration_pem_payload.idl
new file mode 100644
index 00000000000..2e4aa666c62
--- /dev/null
+++ b/src/mongo/db/repl/tenant_migration_pem_payload.idl
@@ -0,0 +1,50 @@
+# Copyright (C) 2020-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+global:
+ cpp_namespace: "mongo"
+ cpp_includes:
+ - "mongo/db/repl/tenant_migration_util.h"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+structs:
+ TenantMigrationPEMPayload:
+ description: "Contains SSL certificate and private key PEM blobs for a replica set."
+ strict: true
+ fields:
+ certificate:
+ type: string
+ description: "Certificate PEM blob."
+ validator:
+ callback: "validateCertificatePEMPayload"
+ privateKey:
+ type: string
+ description: "Private key PEM blob."
+ validator:
+ callback: "validatePrivateKeyPEMPayload"
diff --git a/src/mongo/db/repl/tenant_migration_state_machine.idl b/src/mongo/db/repl/tenant_migration_state_machine.idl
index 2f444f9f9f2..ea808921f2a 100644
--- a/src/mongo/db/repl/tenant_migration_state_machine.idl
+++ b/src/mongo/db/repl/tenant_migration_state_machine.idl
@@ -34,6 +34,7 @@ global:
imports:
- "mongo/client/read_preference_setting.idl"
- "mongo/db/repl/replication_types.idl"
+ - "mongo/db/repl/tenant_migration_pem_payload.idl"
- "mongo/idl/basic_types.idl"
enums:
@@ -106,6 +107,16 @@ structs:
The wall-clock time at which the state machine document should be
removed by the TTL monitor.
optional: true
+ donorCertificateForRecipient:
+ description: >-
+ The SSL certificate and private key that the donor should use to authenticate
+ to the recipient.
+ type: TenantMigrationPEMPayload
+ recipientCertificateForDonor:
+ description: >-
+ The SSL certificate and private key that the recipient should use to
+ authenticate to the donor.
+ type: TenantMigrationPEMPayload
tenantMigrationRecipientDocument:
description: "Represents an in-progress tenant migration on the migration recipient."
diff --git a/src/mongo/db/repl/tenant_migration_util.h b/src/mongo/db/repl/tenant_migration_util.h
index 1e5d1a5000f..1fd136fecc4 100644
--- a/src/mongo/db/repl/tenant_migration_util.h
+++ b/src/mongo/db/repl/tenant_migration_util.h
@@ -34,6 +34,7 @@
#include "mongo/bson/timestamp.h"
#include "mongo/client/mongo_uri.h"
#include "mongo/db/repl/replication_coordinator.h"
+#include "mongo/util/net/ssl_util.h"
#include "mongo/util/str.h"
namespace mongo {
@@ -98,4 +99,16 @@ inline Status validateConnectionString(const StringData& donorOrRecipientConnect
return Status::OK();
}
+inline Status validateCertificatePEMPayload(const StringData& payload) {
+ auto swBlob =
+ ssl_util::findPEMBlob(payload, "CERTIFICATE"_sd, 0 /* position */, false /* allowEmpty */);
+ return swBlob.getStatus().withContext("Invalid certificate field");
+}
+
+inline Status validatePrivateKeyPEMPayload(const StringData& payload) {
+ auto swBlob =
+ ssl_util::findPEMBlob(payload, "PRIVATE KEY"_sd, 0 /* position */, false /* allowEmpty */);
+ return swBlob.getStatus().withContext("Invalid private key field");
+}
+
} // namespace mongo