diff options
author | Andrew Shuvalov <andrew.shuvalov@mongodb.com> | 2020-11-19 21:11:30 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-11-20 14:58:12 +0000 |
commit | d3faf32669a87871992a8534cffab58d83377d79 (patch) | |
tree | 0e3302ac5eeffb47c237f609ad2328af91b4d2e9 | |
parent | 1cabc1efdd46b045bd85189e142fd9b3fa65dc1a (diff) | |
download | mongo-d3faf32669a87871992a8534cffab58d83377d79.tar.gz |
SERVER-52710: wire up transient SSL parameters up to the NetworkInterface
20 files changed, 325 insertions, 46 deletions
diff --git a/buildscripts/resmokeconfig/suites/integration_tests_replset_ssl.yml b/buildscripts/resmokeconfig/suites/integration_tests_replset_ssl.yml new file mode 100644 index 00000000000..fff837dee67 --- /dev/null +++ b/buildscripts/resmokeconfig/suites/integration_tests_replset_ssl.yml @@ -0,0 +1,35 @@ +# This suite is a clone of buildscripts/resmokeconfig/suites/integration_tests_replset.yml +# with TLS options added. The inclusion and exclusion lists are expected to be similar. +test_kind: cpp_integration_test + +selector: + root: build/integration_tests.txt + exclude_files: + - build/**/mongo/client/client_dbclient_connection_integration_test* # Needs connection to single host. + - build/install/bin/client_dbclient_connection_integration_test* # Needs connection to single host. + +executor: + archive: + hooks: + - CheckReplDBHash + - CheckReplOplogs + - ValidateCollections + config: {} + hooks: + # The CheckReplDBHash hook waits until all operations have replicated to and have been applied + # on the secondaries, so we run the ValidateCollections hook after it to ensure we're + # validating the entire contents of the collection. + - class: CheckReplOplogs + - class: CheckReplDBHash + - class: ValidateCollections + fixture: + class: ReplicaSetFixture + mongod_options: + set_parameters: + logComponentVerbosity: + command: 2 + enableTestCommands: 1 + tlsMode: preferTLS + tlsCAFile: jstests/libs/ca.pem + tlsCertificateKeyFile: jstests/libs/server.pem + num_nodes: 2 diff --git a/src/mongo/executor/connection_pool.cpp b/src/mongo/executor/connection_pool.cpp index 36275566ce0..63f30325638 100644 --- a/src/mongo/executor/connection_pool.cpp +++ b/src/mongo/executor/connection_pool.cpp @@ -450,15 +450,12 @@ auto ConnectionPool::SpecificPool::make(std::shared_ptr<ConnectionPool> parent, const Status ConnectionPool::kConnectionStateUnknown = Status(ErrorCodes::InternalError, "Connection is in an unknown state"); -ConnectionPool::ConnectionPool( - std::shared_ptr<DependentTypeFactoryInterface> impl, - std::string name, - Options options, - std::shared_ptr<const transport::SSLConnectionContext> transientSSLContext) +ConnectionPool::ConnectionPool(std::shared_ptr<DependentTypeFactoryInterface> impl, + std::string name, + Options options) : _name(std::move(name)), _factory(std::move(impl)), _options(std::move(options)), - _transientSSLContext(std::move(transientSSLContext)), _controller(_options.controllerFactory()), _manager(options.egressTagCloserManager) { if (_manager) { @@ -1037,6 +1034,7 @@ void ConnectionPool::SpecificPool::spawnConnections() { "Spawning connections", "connAllowance"_attr = allowance, "hostAndPort"_attr = _hostAndPort); + for (decltype(allowance) i = 0; i < allowance; ++i) { OwnedConnection handle; try { diff --git a/src/mongo/executor/connection_pool.h b/src/mongo/executor/connection_pool.h index 64ee4c22cbb..9391dcbba12 100644 --- a/src/mongo/executor/connection_pool.h +++ b/src/mongo/executor/connection_pool.h @@ -236,11 +236,9 @@ public: bool canShutdown = false; }; - explicit ConnectionPool( - std::shared_ptr<DependentTypeFactoryInterface> impl, - std::string name, - Options options = Options{}, - std::shared_ptr<const transport::SSLConnectionContext> transientSSLContext = {}); + explicit ConnectionPool(std::shared_ptr<DependentTypeFactoryInterface> impl, + std::string name, + Options options = Options{}); ~ConnectionPool(); @@ -271,9 +269,6 @@ private: const std::shared_ptr<DependentTypeFactoryInterface> _factory; const Options _options; - // SSL context for the connections that require non-default SSL paramaeters. - std::shared_ptr<const transport::SSLConnectionContext> _transientSSLContext; - std::shared_ptr<ControllerInterface> _controller; // The global mutex for specific pool access and the generation counter diff --git a/src/mongo/executor/connection_pool_tl.cpp b/src/mongo/executor/connection_pool_tl.cpp index 4ae4faf570a..dd04a67368b 100644 --- a/src/mongo/executor/connection_pool_tl.cpp +++ b/src/mongo/executor/connection_pool_tl.cpp @@ -400,7 +400,8 @@ std::shared_ptr<ConnectionPool::ConnectionInterface> TLTypeFactory::makeConnecti sslMode, generation, _onConnectHook.get(), - _connPoolOptions.skipAuthentication); + _connPoolOptions.skipAuthentication, + _transientSSLContext); fasten(conn.get()); return conn; } diff --git a/src/mongo/executor/connection_pool_tl.h b/src/mongo/executor/connection_pool_tl.h index a147071f54d..5cdb3036fd7 100644 --- a/src/mongo/executor/connection_pool_tl.h +++ b/src/mongo/executor/connection_pool_tl.h @@ -51,16 +51,19 @@ public: TLTypeFactory(transport::ReactorHandle reactor, transport::TransportLayer* tl, std::unique_ptr<NetworkConnectionHook> onConnectHook, - const ConnectionPool::Options& connPoolOptions) + const ConnectionPool::Options& connPoolOptions, + std::shared_ptr<const transport::SSLConnectionContext> transientSSLContext) : _executor(std::move(reactor)), _tl(tl), _onConnectHook(std::move(onConnectHook)), - _connPoolOptions(connPoolOptions) {} + _connPoolOptions(connPoolOptions), + _transientSSLContext(transientSSLContext) {} std::shared_ptr<ConnectionPool::ConnectionInterface> makeConnection( const HostAndPort& hostAndPort, transport::ConnectSSLMode sslMode, size_t generation) override; + std::shared_ptr<ConnectionPool::TimerInterface> makeTimer() override; const std::shared_ptr<OutOfLineExecutor>& getExecutor() override { return _executor; @@ -79,7 +82,9 @@ private: std::shared_ptr<OutOfLineExecutor> _executor; // This is always a transport::Reactor transport::TransportLayer* _tl; std::unique_ptr<NetworkConnectionHook> _onConnectHook; + // Options originated from instance of NetworkInterfaceTL. const ConnectionPool::Options _connPoolOptions; + std::shared_ptr<const transport::SSLConnectionContext> _transientSSLContext; mutable Mutex _mutex = MONGO_MAKE_LATCH(HierarchicalAcquisitionLevel(0), "TLTypeFactory::_mutex"); @@ -154,6 +159,7 @@ public: _sslMode(sslMode), _onConnectHook(onConnectHook), _transientSSLContext(transientSSLContext) {} + ~TLConnection() { // Release must be the first expression of this dtor release(); @@ -192,7 +198,7 @@ private: transport::ConnectSSLMode _sslMode; NetworkConnectionHook* const _onConnectHook; // SSL context to use intead of the default one for this pool. - std::shared_ptr<const transport::SSLConnectionContext> _transientSSLContext; + const std::shared_ptr<const transport::SSLConnectionContext> _transientSSLContext; AsyncDBClient::Handle _client; }; diff --git a/src/mongo/executor/network_interface_tl.cpp b/src/mongo/executor/network_interface_tl.cpp index f50ae202bc5..28ef98de1e1 100644 --- a/src/mongo/executor/network_interface_tl.cpp +++ b/src/mongo/executor/network_interface_tl.cpp @@ -45,6 +45,7 @@ #include "mongo/util/net/socket_utils.h" #include "mongo/util/testing_proctor.h" + namespace mongo { namespace executor { @@ -126,25 +127,20 @@ NetworkInterfaceTL::NetworkInterfaceTL(std::string instanceName, } std::shared_ptr<const transport::SSLConnectionContext> transientSSLContext; - #ifdef MONGO_CONFIG_SSL if (_connPoolOpts.transientSSLParams) { - // TODO: uncomment when changes for SERVER-51599 are submitted. - // auto statusOrContext = _tl->createTransientSSLContext( - // _connPoolOpts.transientSSLParams.get(), nullptr, true /* asyncOCSPStaple */); - // uassertStatusOK(statusOrContext.getStatus()); - // transientSSLContext = std::make_shared<const transport::SSLConnectionContext>( - // std::move(statusOrContext.getValue())); + auto statusOrContext = + _tl->createTransientSSLContext(_connPoolOpts.transientSSLParams.get(), nullptr); + uassertStatusOK(statusOrContext.getStatus()); + transientSSLContext = std::move(statusOrContext.getValue()); } #endif _reactor = _tl->getReactor(transport::TransportLayer::kNewReactor); auto typeFactory = std::make_unique<connection_pool_tl::TLTypeFactory>( - _reactor, _tl, std::move(_onConnectHook), _connPoolOpts); - _pool = std::make_shared<ConnectionPool>(std::move(typeFactory), - std::string("NetworkInterfaceTL-") + _instanceName, - _connPoolOpts, - transientSSLContext); + _reactor, _tl, std::move(_onConnectHook), _connPoolOpts, transientSSLContext); + _pool = std::make_shared<ConnectionPool>( + std::move(typeFactory), std::string("NetworkInterfaceTL-") + _instanceName, _connPoolOpts); if (TestingProctor::instance().isEnabled()) { _counters = std::make_unique<SynchronizedCounters>(); diff --git a/src/mongo/executor/network_interface_tl.h b/src/mongo/executor/network_interface_tl.h index 4dde6c8fdfd..646ebfbb11f 100644 --- a/src/mongo/executor/network_interface_tl.h +++ b/src/mongo/executor/network_interface_tl.h @@ -45,6 +45,7 @@ #include "mongo/util/hierarchical_acquisition.h" #include "mongo/util/strong_weak_finish_line.h" + namespace mongo { namespace executor { diff --git a/src/mongo/transport/session_asio.h b/src/mongo/transport/session_asio.h index a6864b37189..df83ab40d2a 100644 --- a/src/mongo/transport/session_asio.h +++ b/src/mongo/transport/session_asio.h @@ -114,6 +114,16 @@ public: _remote = HostAndPort(_remoteAddr.toString(true)); #ifdef MONGO_CONFIG_SSL _sslContext = transientSSLContext ? transientSSLContext : *tl->_sslContext; + if (transientSSLContext) { + logv2::DynamicAttributes attrs; + if (transientSSLContext->targetClusterURI) { + attrs.add("targetClusterURI", *transientSSLContext->targetClusterURI); + } + attrs.add("isIngress", isIngressSession); + attrs.add("connectionId", id()); + attrs.add("remote", remote()); + LOGV2(5271001, "Initializing the ASIOSession with transient SSL context", attrs); + } #endif } catch (const DBException&) { throw; diff --git a/src/mongo/transport/ssl_connection_context.h b/src/mongo/transport/ssl_connection_context.h index 2de1f98c647..0ab7c23091d 100644 --- a/src/mongo/transport/ssl_connection_context.h +++ b/src/mongo/transport/ssl_connection_context.h @@ -53,6 +53,11 @@ struct SSLConnectionContext { std::unique_ptr<asio::ssl::context> ingress; std::unique_ptr<asio::ssl::context> egress; std::shared_ptr<SSLManagerInterface> manager; + // If this Context was created from transient SSL params this contains the URI of the target + // cluster. It can also be used to determine if the context is indeed transient. + std::optional<std::string> targetClusterURI; + + ~SSLConnectionContext(); }; #endif diff --git a/src/mongo/transport/transport_layer.h b/src/mongo/transport/transport_layer.h index 126b6ec7898..10745f16198 100644 --- a/src/mongo/transport/transport_layer.h +++ b/src/mongo/transport/transport_layer.h @@ -42,6 +42,7 @@ #include "mongo/util/future.h" #include "mongo/util/out_of_line_executor.h" #include "mongo/util/time_support.h" + #ifdef MONGO_CONFIG_SSL #include "mongo/util/net/ssl_manager.h" #endif @@ -133,6 +134,16 @@ public: /** Rotate the in-use certificates for new connections. */ virtual Status rotateCertificates(std::shared_ptr<SSLManagerInterface> manager, bool asyncOCSPStaple) = 0; + + /** + * Creates a transient SSL context using targeted (non default) SSL params. + * @param transientSSLParams overrides any value in stored SSLConnectionContext. + * @param optionalManager provides an optional SSL manager, otherwise the default one will be + * used. + */ + virtual StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> + createTransientSSLContext(const TransientSSLParams& transientSSLParams, + const SSLManagerInterface* optionalManager) = 0; #endif private: diff --git a/src/mongo/transport/transport_layer_asio.cpp b/src/mongo/transport/transport_layer_asio.cpp index 4fd4df156bc..670ea496bc9 100644 --- a/src/mongo/transport/transport_layer_asio.cpp +++ b/src/mongo/transport/transport_layer_asio.cpp @@ -99,6 +99,9 @@ boost::optional<Status> maybeTcpFastOpenStatus; MONGO_FAIL_POINT_DEFINE(transportLayerASIOasyncConnectTimesOut); + +SSLConnectionContext::~SSLConnectionContext() = default; + class ASIOReactorTimer final : public ReactorTimer { public: explicit ASIOReactorTimer(asio::io_context& ctx) @@ -1189,17 +1192,33 @@ SSLParams::SSLModes TransportLayerASIO::_sslMode() const { Status TransportLayerASIO::rotateCertificates(std::shared_ptr<SSLManagerInterface> manager, bool asyncOCSPStaple) { - auto newSSLContext = std::make_shared<SSLConnectionContext>(); + + auto contextOrStatus = + _createSSLContext(manager, _sslMode(), TransientSSLParams(), asyncOCSPStaple); + if (!contextOrStatus.isOK()) { + return contextOrStatus.getStatus(); + } + _sslContext = std::move(contextOrStatus.getValue()); + return Status::OK(); +} + +StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> +TransportLayerASIO::_createSSLContext(std::shared_ptr<SSLManagerInterface>& manager, + SSLParams::SSLModes sslMode, + TransientSSLParams transientEgressSSLParams, + bool asyncOCSPStaple) const { + + std::shared_ptr<SSLConnectionContext> newSSLContext = std::make_shared<SSLConnectionContext>(); newSSLContext->manager = manager; const auto& sslParams = getSSLGlobalParams(); - if (_sslMode() != SSLParams::SSLMode_disabled && _listenerOptions.isIngress()) { + if (sslMode != SSLParams::SSLMode_disabled && _listenerOptions.isIngress()) { newSSLContext->ingress = std::make_unique<asio::ssl::context>(asio::ssl::context::sslv23); Status status = newSSLContext->manager->initSSLContext( newSSLContext->ingress->native_handle(), sslParams, - TransientSSLParams(), + TransientSSLParams(), // Ingress is not using transient params, they are egress. SSLManagerInterface::ConnectionDirection::kIncoming); if (!status.isOK()) { return status; @@ -1220,15 +1239,33 @@ Status TransportLayerASIO::rotateCertificates(std::shared_ptr<SSLManagerInterfac Status status = newSSLContext->manager->initSSLContext( newSSLContext->egress->native_handle(), sslParams, - TransientSSLParams(), + transientEgressSSLParams, SSLManagerInterface::ConnectionDirection::kOutgoing); if (!status.isOK()) { return status; } + if (!transientEgressSSLParams.sslClusterPEMPayload.empty()) { + if (transientEgressSSLParams.targetedClusterConnectionString) { + newSSLContext->targetClusterURI = + transientEgressSSLParams.targetedClusterConnectionString.toString(); + } + } } - _sslContext = std::move(newSSLContext); - return Status::OK(); + return newSSLContext; +} + +StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> +TransportLayerASIO::createTransientSSLContext(const TransientSSLParams& transientSSLParams, + const SSLManagerInterface* optionalManager) { + + auto manager = getSSLManager(); + if (!manager) { + return Status(ErrorCodes::InvalidSSLConfiguration, "TransportLayerASIO has no SSL manager"); + } + + return _createSSLContext(manager, _sslMode(), transientSSLParams, true /* asyncOCSPStaple */); } + #endif #ifdef __linux__ diff --git a/src/mongo/transport/transport_layer_asio.h b/src/mongo/transport/transport_layer_asio.h index d710ec1c89e..6eac75fae2f 100644 --- a/src/mongo/transport/transport_layer_asio.h +++ b/src/mongo/transport/transport_layer_asio.h @@ -152,8 +152,22 @@ public: bool asyncOCSPStaple) override; std::shared_ptr<SSLManagerInterface> getSSLManager() { - return _sslContext.get()->manager; + auto sslContext = _sslContext.get(); + if (!sslContext) { + return std::shared_ptr<SSLManagerInterface>{}; + } + return sslContext->manager; } + + /** + * Creates a transient SSL context using targeted (non default) SSL params. + * @param transientSSLParams overrides any value in stored SSLConnectionContext. + * @param optionalManager provides an optional SSL manager, otherwise the default one will be + * used. + */ + StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> createTransientSSLContext( + const TransientSSLParams& transientSSLParams, + const SSLManagerInterface* optionalManager) override; #endif private: @@ -172,6 +186,12 @@ private: const HostAndPort& peer, const Milliseconds& timeout); + StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> _createSSLContext( + std::shared_ptr<SSLManagerInterface>& manager, + SSLParams::SSLModes sslMode, + TransientSSLParams transientEgressSSLParams, + bool asyncOCSPStaple) const; + void _runListener() noexcept; #ifdef MONGO_CONFIG_SSL diff --git a/src/mongo/transport/transport_layer_manager.cpp b/src/mongo/transport/transport_layer_manager.cpp index 272a9ac391d..fd386560a44 100644 --- a/src/mongo/transport/transport_layer_manager.cpp +++ b/src/mongo/transport/transport_layer_manager.cpp @@ -45,6 +45,7 @@ #include "mongo/transport/service_executor_synchronous.h" #include "mongo/transport/session.h" #include "mongo/transport/transport_layer_asio.h" +#include "mongo/util/net/ssl/context.hpp" #include "mongo/util/net/ssl_types.h" #include "mongo/util/time_support.h" @@ -154,6 +155,23 @@ Status TransportLayerManager::rotateCertificates(std::shared_ptr<SSLManagerInter } return Status::OK(); } + +StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> +TransportLayerManager::createTransientSSLContext(const TransientSSLParams& transientSSLParams, + const SSLManagerInterface* optionalManager) { + + Status firstError(ErrorCodes::InvalidSSLConfiguration, + "Failure creating transient SSL context"); + for (auto&& tl : _tls) { + auto statusOrContext = tl->createTransientSSLContext(transientSSLParams, optionalManager); + if (statusOrContext.isOK()) { + return std::move(statusOrContext.getValue()); + } + firstError = statusOrContext.getStatus(); + } + return firstError; +} + #endif } // namespace transport diff --git a/src/mongo/transport/transport_layer_manager.h b/src/mongo/transport/transport_layer_manager.h index a4fd33cd863..b561a67f591 100644 --- a/src/mongo/transport/transport_layer_manager.h +++ b/src/mongo/transport/transport_layer_manager.h @@ -56,8 +56,8 @@ class TransportLayerManager final : public TransportLayer { TransportLayerManager& operator=(const TransportLayerManager&) = delete; public: - TransportLayerManager(std::vector<std::unique_ptr<TransportLayer>> tls, - const WireSpec& wireSpec = WireSpec::instance()) + explicit TransportLayerManager(std::vector<std::unique_ptr<TransportLayer>> tls, + const WireSpec& wireSpec = WireSpec::instance()) : TransportLayer(wireSpec), _tls(std::move(tls)) {} explicit TransportLayerManager(const WireSpec& wireSpec = WireSpec::instance()) @@ -107,6 +107,10 @@ public: #ifdef MONGO_CONFIG_SSL Status rotateCertificates(std::shared_ptr<SSLManagerInterface> manager, bool asyncOCSPStaple) override; + + StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> createTransientSSLContext( + const TransientSSLParams& transientSSLParams, + const SSLManagerInterface* optionalManager) override; #endif private: template <typename Callable> diff --git a/src/mongo/transport/transport_layer_mock.cpp b/src/mongo/transport/transport_layer_mock.cpp index 6fca645649d..dc11e6f06e9 100644 --- a/src/mongo/transport/transport_layer_mock.cpp +++ b/src/mongo/transport/transport_layer_mock.cpp @@ -102,5 +102,11 @@ TransportLayerMock::~TransportLayerMock() { shutdown(); } +StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> +TransportLayerMock::createTransientSSLContext(const TransientSSLParams& transientSSLParams, + const SSLManagerInterface* optionalManager) { + return Status(ErrorCodes::InvalidSSLConfiguration, "Failure creating transient SSL context"); +} + } // namespace transport } // namespace mongo diff --git a/src/mongo/transport/transport_layer_mock.h b/src/mongo/transport/transport_layer_mock.h index b1e778e1e8c..a376f66fc95 100644 --- a/src/mongo/transport/transport_layer_mock.h +++ b/src/mongo/transport/transport_layer_mock.h @@ -83,6 +83,10 @@ public: bool asyncOCSPStaple) override { return Status::OK(); } + + StatusWith<std::shared_ptr<const transport::SSLConnectionContext>> createTransientSSLContext( + const TransientSSLParams& transientSSLParams, + const SSLManagerInterface* optionalManager) override; #endif private: diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript index adf8b0ec033..71c46e22df6 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -230,6 +230,7 @@ if get_option('ssl') == 'on': 'sock_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/client/connection_string', '$BUILD_DIR/mongo/db/server_options_servers', '$BUILD_DIR/mongo/transport/transport_layer', '$BUILD_DIR/mongo/util/cmdline_utils/cmdline_utils', @@ -239,3 +240,23 @@ if get_option('ssl') == 'on': 'ssl_options_server', ], ) + +if get_option('ssl') == 'on': + env.CppIntegrationTest( + target='network_interface_ssl_test', + source=[ + 'network_interface_ssl_test.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/client/connection_string', + '$BUILD_DIR/mongo/executor/network_interface', + '$BUILD_DIR/mongo/executor/network_interface_factory', + '$BUILD_DIR/mongo/executor/network_interface_fixture', + '$BUILD_DIR/mongo/executor/network_interface_thread_pool', + '$BUILD_DIR/mongo/executor/thread_pool_task_executor', + '$BUILD_DIR/mongo/transport/transport_layer_egress_init', + '$BUILD_DIR/mongo/util/concurrency/thread_pool', + '$BUILD_DIR/mongo/util/version_impl', + ], +) + diff --git a/src/mongo/util/net/network_interface_ssl_test.cpp b/src/mongo/util/net/network_interface_ssl_test.cpp new file mode 100644 index 00000000000..8e3b446bdfe --- /dev/null +++ b/src/mongo/util/net/network_interface_ssl_test.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2018-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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest + +#include <fstream> + +#include "mongo/platform/basic.h" + +#include "mongo/executor/network_interface_integration_fixture.h" +#include "mongo/logv2/log.h" +#include "mongo/unittest/integration_test.h" +#include "mongo/unittest/unittest.h" +#include "mongo/util/assert_util.h" + +namespace mongo { +namespace executor { +namespace { + +std::string LoadFile(const std::string& name) { + std::ifstream input(name); + std::string str((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>()); + return str; +} + +class NetworkInterfaceSSLFixture : public NetworkInterfaceIntegrationFixture { +public: + void setUp() final { + ConnectionPool::Options options; + options.transientSSLParams.emplace([] { + TransientSSLParams params; + params.sslClusterPEMPayload = LoadFile("jstests/libs/client.pem"); + params.targetedClusterConnectionString = ConnectionString::forLocal(); + return params; + }()); + LOGV2(5181101, "Initializing the test connection with transient SSL params"); + createNet(nullptr, std::move(options)); + net().startup(); + } +}; + +TEST_F(NetworkInterfaceSSLFixture, Ping) { + assertCommandOK("admin", BSON("ping" << 1)); +} + + +} // namespace +} // namespace executor +} // namespace mongo diff --git a/src/mongo/util/net/ssl_manager_openssl.cpp b/src/mongo/util/net/ssl_manager_openssl.cpp index d42474657a3..cbd75b964f2 100644 --- a/src/mongo/util/net/ssl_manager_openssl.cpp +++ b/src/mongo/util/net/ssl_manager_openssl.cpp @@ -1331,7 +1331,7 @@ private: StatusWith<boost::optional<std::vector<DERInteger>>> _parseTLSFeature(X509* peerCert) const; /** @return true if was successful, otherwise false */ - bool _setupPEM(SSL_CTX* context, const std::string& keyFile, PasswordFetcher* password); + bool _setupPEM(SSL_CTX* context, const std::string& keyFile, PasswordFetcher* password) const; /** * @param payload in-memory payload of a PEM file @@ -1340,7 +1340,7 @@ private: bool _setupPEMFromMemoryPayload(SSL_CTX* context, const std::string& payload, PasswordFetcher* password, - StringData targetClusterURI); + StringData targetClusterURI) const; /** * Setup PEM from BIO, which could be file or memory input abstraction. @@ -1356,7 +1356,7 @@ private: UniqueBIO inBio, PasswordFetcher* password, std::optional<StringData> keyFile, - std::optional<StringData> targetClusterURI); + std::optional<StringData> targetClusterURI) const; /** * Loads a certificate chain from memory into context. @@ -2437,7 +2437,7 @@ bool SSLManagerOpenSSL::_readCertificateChainFromMemory( bool SSLManagerOpenSSL::_setupPEM(SSL_CTX* context, const std::string& keyFile, - PasswordFetcher* password) { + PasswordFetcher* password) const { logv2::DynamicAttributes errorAttrs; errorAttrs.add("keyFile", keyFile); @@ -2466,7 +2466,7 @@ bool SSLManagerOpenSSL::_setupPEM(SSL_CTX* context, bool SSLManagerOpenSSL::_setupPEMFromMemoryPayload(SSL_CTX* context, const std::string& payload, PasswordFetcher* password, - StringData targetClusterURI) { + StringData targetClusterURI) const { logv2::DynamicAttributes errorAttrs; errorAttrs.add("targetClusterURI", targetClusterURI); @@ -2492,7 +2492,7 @@ bool SSLManagerOpenSSL::_setupPEMFromBIO(SSL_CTX* context, UniqueBIO inBio, PasswordFetcher* password, std::optional<StringData> keyFile, - std::optional<StringData> targetClusterURI) { + std::optional<StringData> targetClusterURI) const { logv2::DynamicAttributes errorAttrs; if (keyFile) { errorAttrs.add("keyFile", *keyFile); diff --git a/src/mongo/util/net/ssl_manager_test.cpp b/src/mongo/util/net/ssl_manager_test.cpp index af325854a87..1fbd42bde40 100644 --- a/src/mongo/util/net/ssl_manager_test.cpp +++ b/src/mongo/util/net/ssl_manager_test.cpp @@ -36,6 +36,7 @@ #include "mongo/transport/service_entry_point.h" #include "mongo/transport/transport_layer_asio.h" +#include "mongo/transport/transport_layer_manager.h" #include "mongo/util/net/ssl/context_base.hpp" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/net/ssl_options.h" @@ -52,7 +53,6 @@ namespace mongo { namespace { - // Test implementation needed by ASIO transport. class ServiceEntryPointUtil : public ServiceEntryPoint { public: @@ -602,6 +602,42 @@ TEST(SSLManager, InitServerSideContextFromMemory) { SSLManagerInterface::ConnectionDirection::kOutgoing)); } +TEST(SSLManager, TransientSSLParams) { + SSLParams params; + params.sslMode.store(::mongo::sslGlobalParams.SSLMode_requireSSL); + params.sslCAFile = "jstests/libs/ca.pem"; + params.sslClusterFile = "jstests/libs/client.pem"; + + std::shared_ptr<SSLManagerInterface> manager = + SSLManagerInterface::create(params, false /* isSSLServer */); + + ServiceEntryPointUtil sepu; + + auto options = [] { + ServerGlobalParams params; + params.noUnixSocket = true; + transport::TransportLayerASIO::Options opts(¶ms); + return opts; + }(); + transport::TransportLayerASIO tla(options, &sepu); + + TransientSSLParams transientSSLParams; + transientSSLParams.sslClusterPEMPayload = LoadFile("jstests/libs/client.pem"); + transientSSLParams.targetedClusterConnectionString = ConnectionString::forLocal(); + + auto result = tla.createTransientSSLContext(transientSSLParams, manager.get()); + + // This will fail because we need to rotate certificates first to + // initialize the default SSL context inside TransportLayerASIO. + ASSERT_NOT_OK(result.getStatus()); + + // Init the transport properly. + uassertStatusOK(tla.rotateCertificates(manager, false /* asyncOCSPStaple */)); + + result = tla.createTransientSSLContext(transientSSLParams, manager.get()); + uassertStatusOK(result.getStatus()); +} + #endif } // namespace |