Add networkoption to disable non-TLS connections (#9984)
* Add networkoption to disable non-TLS connections * add disable plaintext connection to fdbserver * python doc * Formatting * Add tls disable plaintext connection to client api test * review * fix negative test * formatting * add TLS support to c client config tests Adds support for TLS in the client and server separately * add tests for disable_plaintext_connections Test TLS and Plaintext Clusters and Clients * Fix documentation * Rename option to indicate it is client-only * clearer formatting * default to allowing plaintext connections * add SetTLSDisablePlaintextConnection to go bindings
This commit is contained in:
parent
9c081f8a08
commit
6c16875c34
|
@ -14,7 +14,7 @@ from threading import Thread
|
||||||
import time
|
import time
|
||||||
from fdb_version import CURRENT_VERSION, PREV_RELEASE_VERSION, PREV2_RELEASE_VERSION
|
from fdb_version import CURRENT_VERSION, PREV_RELEASE_VERSION, PREV2_RELEASE_VERSION
|
||||||
from binary_download import FdbBinaryDownloader
|
from binary_download import FdbBinaryDownloader
|
||||||
from local_cluster import LocalCluster, PortProvider
|
from local_cluster import LocalCluster, PortProvider, TLSConfig
|
||||||
from test_util import random_alphanum_string
|
from test_util import random_alphanum_string
|
||||||
|
|
||||||
args = None
|
args = None
|
||||||
|
@ -36,6 +36,9 @@ class TestCluster(LocalCluster):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
version: str,
|
version: str,
|
||||||
|
tls_config: TLSConfig = None,
|
||||||
|
mkcert_binary: str = None,
|
||||||
|
disable_server_side_tls: bool = False,
|
||||||
):
|
):
|
||||||
self.client_config_tester_bin = Path(args.client_config_tester_bin).resolve()
|
self.client_config_tester_bin = Path(args.client_config_tester_bin).resolve()
|
||||||
assert self.client_config_tester_bin.exists(), "{} does not exist".format(
|
assert self.client_config_tester_bin.exists(), "{} does not exist".format(
|
||||||
|
@ -46,7 +49,16 @@ class TestCluster(LocalCluster):
|
||||||
assert self.build_dir.is_dir(), "{} is not a directory".format(args.build_dir)
|
assert self.build_dir.is_dir(), "{} is not a directory".format(args.build_dir)
|
||||||
self.tmp_dir = self.build_dir.joinpath("tmp", random_alphanum_string(16))
|
self.tmp_dir = self.build_dir.joinpath("tmp", random_alphanum_string(16))
|
||||||
print("Creating temp dir {}".format(self.tmp_dir), file=sys.stderr)
|
print("Creating temp dir {}".format(self.tmp_dir), file=sys.stderr)
|
||||||
|
|
||||||
self.tmp_dir.mkdir(parents=True)
|
self.tmp_dir.mkdir(parents=True)
|
||||||
|
if mkcert_binary:
|
||||||
|
self.mkcert_binary = Path(mkcert_binary).resolve()
|
||||||
|
else:
|
||||||
|
self.mkcert_binary = os.path.join(self.build_dir, "bin", "mkcert")
|
||||||
|
assert Path(self.mkcert_binary).exists(), "{} does not exist".format(
|
||||||
|
self.mkcert_binary
|
||||||
|
)
|
||||||
|
|
||||||
self.version = version
|
self.version = version
|
||||||
super().__init__(
|
super().__init__(
|
||||||
self.tmp_dir,
|
self.tmp_dir,
|
||||||
|
@ -54,6 +66,9 @@ class TestCluster(LocalCluster):
|
||||||
downloader.binary_path(version, "fdbmonitor"),
|
downloader.binary_path(version, "fdbmonitor"),
|
||||||
downloader.binary_path(version, "fdbcli"),
|
downloader.binary_path(version, "fdbcli"),
|
||||||
1,
|
1,
|
||||||
|
tls_config=tls_config,
|
||||||
|
mkcert_binary=self.mkcert_binary,
|
||||||
|
disable_server_side_tls=disable_server_side_tls,
|
||||||
)
|
)
|
||||||
self.set_env_var("LD_LIBRARY_PATH", downloader.lib_dir(version))
|
self.set_env_var("LD_LIBRARY_PATH", downloader.lib_dir(version))
|
||||||
|
|
||||||
|
@ -97,6 +112,10 @@ class ClientConfigTest:
|
||||||
self.status_json = None
|
self.status_json = None
|
||||||
|
|
||||||
# Configuration parameters to be set directly as needed
|
# Configuration parameters to be set directly as needed
|
||||||
|
self.tls_client_cert_file = None
|
||||||
|
self.tls_client_key_file = None
|
||||||
|
self.tls_client_ca_file = None
|
||||||
|
self.tls_client_disable_plaintext_connection = None
|
||||||
self.disable_local_client = False
|
self.disable_local_client = False
|
||||||
self.disable_client_bypass = False
|
self.disable_client_bypass = False
|
||||||
self.ignore_external_client_failures = False
|
self.ignore_external_client_failures = False
|
||||||
|
@ -266,6 +285,18 @@ class ClientConfigTest:
|
||||||
if self.disable_client_bypass:
|
if self.disable_client_bypass:
|
||||||
cmd_args += ["--network-option-disable_client_bypass", ""]
|
cmd_args += ["--network-option-disable_client_bypass", ""]
|
||||||
|
|
||||||
|
if self.tls_client_cert_file:
|
||||||
|
cmd_args += ["--network-option-tls_cert_path", self.tls_client_cert_file]
|
||||||
|
|
||||||
|
if self.tls_client_key_file:
|
||||||
|
cmd_args += ["--network-option-tls_key_path", self.tls_client_key_file]
|
||||||
|
|
||||||
|
if self.tls_client_ca_file:
|
||||||
|
cmd_args += ["--network-option-tls_ca_path", self.tls_client_ca_file]
|
||||||
|
|
||||||
|
if self.tls_client_disable_plaintext_connection:
|
||||||
|
cmd_args += ["--network-option-tls_disable_plaintext_connection", ""]
|
||||||
|
|
||||||
if self.external_lib_path is not None:
|
if self.external_lib_path is not None:
|
||||||
cmd_args += ["--external-client-library", self.external_lib_path]
|
cmd_args += ["--external-client-library", self.external_lib_path]
|
||||||
|
|
||||||
|
@ -337,6 +368,16 @@ class ClientConfigTests(unittest.TestCase):
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
cls.cluster.tear_down()
|
cls.cluster.tear_down()
|
||||||
|
|
||||||
|
def test_disable_plaintext_connection(self):
|
||||||
|
# Local client only; Plaintext connections are disabled in a plaintext cluster; Timeout Expected
|
||||||
|
test = ClientConfigTest(self)
|
||||||
|
test.print_status = True
|
||||||
|
test.tls_client_disable_plaintext_connection = True
|
||||||
|
test.transaction_timeout = 100
|
||||||
|
test.expected_error = 1031 # Timeout
|
||||||
|
test.exec()
|
||||||
|
test.check_healthy_status(False)
|
||||||
|
|
||||||
def test_local_client_only(self):
|
def test_local_client_only(self):
|
||||||
# Local client only
|
# Local client only
|
||||||
test = ClientConfigTest(self)
|
test = ClientConfigTest(self)
|
||||||
|
@ -581,6 +622,78 @@ class ClientConfigSeparateCluster(unittest.TestCase):
|
||||||
finally:
|
finally:
|
||||||
self.cluster.tear_down()
|
self.cluster.tear_down()
|
||||||
|
|
||||||
|
def test_tls_cluster_tls_client(self):
|
||||||
|
# Test connecting successfully to a TLS-enabled cluster
|
||||||
|
self.cluster = TestCluster(CURRENT_VERSION, tls_config=TLSConfig())
|
||||||
|
self.cluster.setup()
|
||||||
|
try:
|
||||||
|
test = ClientConfigTest(self)
|
||||||
|
test.print_status = True
|
||||||
|
test.tls_client_cert_file = self.cluster.client_cert_file
|
||||||
|
test.tls_client_key_file = self.cluster.client_key_file
|
||||||
|
test.tls_client_ca_file = self.cluster.client_ca_file
|
||||||
|
test.tls_client_disable_plaintext_connection = True
|
||||||
|
test.exec()
|
||||||
|
test.check_healthy_status(True)
|
||||||
|
finally:
|
||||||
|
self.cluster.tear_down()
|
||||||
|
|
||||||
|
def test_plaintext_cluster_tls_client(self):
|
||||||
|
# Test connecting succesfully to a plaintext cluster with a TLS client
|
||||||
|
self.cluster = TestCluster(
|
||||||
|
CURRENT_VERSION, tls_config=TLSConfig(), disable_server_side_tls=True
|
||||||
|
)
|
||||||
|
self.cluster.setup()
|
||||||
|
try:
|
||||||
|
test = ClientConfigTest(self)
|
||||||
|
test.print_status = True
|
||||||
|
test.tls_client_cert_file = self.cluster.client_cert_file
|
||||||
|
test.tls_client_key_file = self.cluster.client_key_file
|
||||||
|
test.tls_client_ca_file = self.cluster.client_ca_file
|
||||||
|
test.exec()
|
||||||
|
test.check_healthy_status(True)
|
||||||
|
finally:
|
||||||
|
self.cluster.tear_down()
|
||||||
|
|
||||||
|
def test_tls_cluster_tls_client_plaintext_disabled(self):
|
||||||
|
# Test connecting successfully to a TLS-enabled cluster with plain-text connections
|
||||||
|
# disabled in a TLS-configured client
|
||||||
|
disable_plaintext_connection = True
|
||||||
|
tls_config = TLSConfig(
|
||||||
|
client_disable_plaintext_connection=disable_plaintext_connection
|
||||||
|
)
|
||||||
|
self.cluster = TestCluster(CURRENT_VERSION, tls_config=tls_config)
|
||||||
|
self.cluster.setup()
|
||||||
|
try:
|
||||||
|
test = ClientConfigTest(self)
|
||||||
|
test.print_status = True
|
||||||
|
test.tls_client_cert_file = self.cluster.client_cert_file
|
||||||
|
test.tls_client_key_file = self.cluster.client_key_file
|
||||||
|
test.tls_client_ca_file = self.cluster.client_ca_file
|
||||||
|
test.tls_client_disable_plaintext_connection = disable_plaintext_connection
|
||||||
|
test.exec()
|
||||||
|
test.check_healthy_status(True)
|
||||||
|
finally:
|
||||||
|
self.cluster.tear_down()
|
||||||
|
|
||||||
|
def test_plaintext_cluster_tls_client_plaintext_connection_disabled(self):
|
||||||
|
# Test connecting succesfully to a plaintext cluster with a TLS-configured client with plaintext connections disabled
|
||||||
|
self.cluster = TestCluster(
|
||||||
|
CURRENT_VERSION, tls_config=TLSConfig(), disable_server_side_tls=True
|
||||||
|
)
|
||||||
|
self.cluster.setup()
|
||||||
|
try:
|
||||||
|
test = ClientConfigTest(self)
|
||||||
|
test.tls_client_cert_file = self.cluster.client_cert_file
|
||||||
|
test.tls_client_key_file = self.cluster.client_key_file
|
||||||
|
test.tls_client_ca_file = self.cluster.client_ca_file
|
||||||
|
test.tls_client_disable_plaintext_connection = True
|
||||||
|
test.transaction_timeout = 100
|
||||||
|
test.expected_error = 1031 # Timeout
|
||||||
|
test.exec()
|
||||||
|
finally:
|
||||||
|
self.cluster.tear_down()
|
||||||
|
|
||||||
|
|
||||||
# Test client-side tracing
|
# Test client-side tracing
|
||||||
class ClientTracingTests(unittest.TestCase):
|
class ClientTracingTests(unittest.TestCase):
|
||||||
|
|
|
@ -213,6 +213,11 @@ func (o NetworkOptions) SetTLSPassword(param string) error {
|
||||||
return o.setOpt(54, []byte(param))
|
return o.setOpt(54, []byte(param))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent client from connecting to a non-TLS endpoint by throwing network connection failed error.
|
||||||
|
func (o NetworkOptions) SetTLSDisablePlaintextConnection() error {
|
||||||
|
return o.setOpt(55, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// Disables the multi-version client API and instead uses the local client directly. Must be set before setting up the network.
|
// Disables the multi-version client API and instead uses the local client directly. Must be set before setting up the network.
|
||||||
func (o NetworkOptions) SetDisableMultiVersionClientApi() error {
|
func (o NetworkOptions) SetDisableMultiVersionClientApi() error {
|
||||||
return o.setOpt(60, nil)
|
return o.setOpt(60, nil)
|
||||||
|
|
|
@ -612,6 +612,10 @@
|
||||||
|
|
||||||
Sets the passphrase for encrypted private key. Password should be set before setting the key for the password to be used.
|
Sets the passphrase for encrypted private key. Password should be set before setting the key for the password to be used.
|
||||||
|
|
||||||
|
.. |option-tls-disable-plaintext-connection| replace::
|
||||||
|
|
||||||
|
Disable non-TLS connections from the client, allowing only TLS connections. Plaintext connections will timeout.
|
||||||
|
|
||||||
.. |option-set-disable-local-client| replace::
|
.. |option-set-disable-local-client| replace::
|
||||||
|
|
||||||
Prevents connections through the local client, allowing only connections through externally loaded client libraries.
|
Prevents connections through the local client, allowing only connections through externally loaded client libraries.
|
||||||
|
|
|
@ -206,6 +206,10 @@ After importing the ``fdb`` module and selecting an API version, you probably wa
|
||||||
|
|
||||||
|option-tls-password|
|
|option-tls-password|
|
||||||
|
|
||||||
|
.. method :: fdb.options.set_tls_disable_plaintext_connection()
|
||||||
|
|
||||||
|
|option-tls-disable-plaintext-connection|
|
||||||
|
|
||||||
.. method :: fdb.options.set_disable_local_client()
|
.. method :: fdb.options.set_disable_local_client()
|
||||||
|
|
||||||
|option-set-disable-local-client|
|
|option-set-disable-local-client|
|
||||||
|
|
|
@ -116,6 +116,8 @@ The value for each setting can be specified in more than one way. The actual va
|
||||||
|
|
||||||
For the password, rather than using the command-line option, it is recommended to use the environment variable ``FDB_TLS_PASSWORD``, as command-line options are more visible to other processes running on the same host.
|
For the password, rather than using the command-line option, it is recommended to use the environment variable ``FDB_TLS_PASSWORD``, as command-line options are more visible to other processes running on the same host.
|
||||||
|
|
||||||
|
Clients can disable non-TLS or plaintext connections by setting ``--tls-disable-plaintext-connection``.
|
||||||
|
|
||||||
As with all other command-line options to ``fdbserver``, the TLS settings can be specified in the :ref:`[fdbserver] section of the configuration file <foundationdb-conf-fdbserver>`.
|
As with all other command-line options to ``fdbserver``, the TLS settings can be specified in the :ref:`[fdbserver] section of the configuration file <foundationdb-conf-fdbserver>`.
|
||||||
|
|
||||||
The settings for certificate file, key file, peer verification, password and CA file are interpreted by the software.
|
The settings for certificate file, key file, peer verification, password and CA file are interpreted by the software.
|
||||||
|
|
|
@ -922,6 +922,7 @@ struct CLIOptions {
|
||||||
std::string tlsVerifyPeers;
|
std::string tlsVerifyPeers;
|
||||||
std::string tlsCAPath;
|
std::string tlsCAPath;
|
||||||
std::string tlsPassword;
|
std::string tlsPassword;
|
||||||
|
bool tlsDisablePlainTextConnection = false;
|
||||||
uint64_t memLimit = 8uLL << 30;
|
uint64_t memLimit = 8uLL << 30;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> knobs;
|
std::vector<std::pair<std::string, std::string>> knobs;
|
||||||
|
@ -1041,6 +1042,9 @@ struct CLIOptions {
|
||||||
case TLSConfig::OPT_TLS_VERIFY_PEERS:
|
case TLSConfig::OPT_TLS_VERIFY_PEERS:
|
||||||
tlsVerifyPeers = args.OptionArg();
|
tlsVerifyPeers = args.OptionArg();
|
||||||
break;
|
break;
|
||||||
|
case TLSConfig::OPT_TLS_DISABLE_PLAINTEXT_CONNECTION:
|
||||||
|
tlsDisablePlainTextConnection = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_HELP:
|
case OPT_HELP:
|
||||||
printProgramUsage(program_name.c_str());
|
printProgramUsage(program_name.c_str());
|
||||||
|
@ -2409,6 +2413,15 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt.tlsDisablePlainTextConnection) {
|
||||||
|
try {
|
||||||
|
setNetworkOption(FDBNetworkOptions::TLS_DISABLE_PLAINTEXT_CONNECTION);
|
||||||
|
} catch (Error& e) {
|
||||||
|
fprintf(stderr, "ERROR: cannot disable non-TLS connections (%s)\n", e.what());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setNetworkOption(FDBNetworkOptions::DISABLE_CLIENT_STATISTICS_LOGGING);
|
setNetworkOption(FDBNetworkOptions::DISABLE_CLIENT_STATISTICS_LOGGING);
|
||||||
} catch (Error& e) {
|
} catch (Error& e) {
|
||||||
|
@ -2423,6 +2436,7 @@ int main(int argc, char** argv) {
|
||||||
printf("\tCertificate Path: %s\n", tlsConfig.getCertificatePathSync().c_str());
|
printf("\tCertificate Path: %s\n", tlsConfig.getCertificatePathSync().c_str());
|
||||||
printf("\tKey Path: %s\n", tlsConfig.getKeyPathSync().c_str());
|
printf("\tKey Path: %s\n", tlsConfig.getKeyPathSync().c_str());
|
||||||
printf("\tCA Path: %s\n", tlsConfig.getCAPathSync().c_str());
|
printf("\tCA Path: %s\n", tlsConfig.getCAPathSync().c_str());
|
||||||
|
printf("\tPlaintext Connection Disable: %s\n", tlsConfig.getDisablePlainTextConnection() ? "true" : "false");
|
||||||
try {
|
try {
|
||||||
LoadedTLSConfig loaded = tlsConfig.loadSync();
|
LoadedTLSConfig loaded = tlsConfig.loadSync();
|
||||||
printf("\tPassword: %s\n", loaded.getPassword().empty() ? "Not configured" : "Exists, but redacted");
|
printf("\tPassword: %s\n", loaded.getPassword().empty() ? "Not configured" : "Exists, but redacted");
|
||||||
|
|
|
@ -2543,6 +2543,9 @@ void setNetworkOption(FDBNetworkOptions::Option option, Optional<StringRef> valu
|
||||||
tlsConfig.clearVerifyPeers();
|
tlsConfig.clearVerifyPeers();
|
||||||
tlsConfig.addVerifyPeers(value.get().toString());
|
tlsConfig.addVerifyPeers(value.get().toString());
|
||||||
break;
|
break;
|
||||||
|
case FDBNetworkOptions::TLS_DISABLE_PLAINTEXT_CONNECTION:
|
||||||
|
tlsConfig.setDisablePlainTextConnection(true);
|
||||||
|
break;
|
||||||
case FDBNetworkOptions::CLIENT_BUGGIFY_ENABLE:
|
case FDBNetworkOptions::CLIENT_BUGGIFY_ENABLE:
|
||||||
enableBuggify(true, BuggifyType::Client);
|
enableBuggify(true, BuggifyType::Client);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -104,6 +104,8 @@ description is not currently required but encouraged.
|
||||||
<Option name="TLS_password" code="54"
|
<Option name="TLS_password" code="54"
|
||||||
paramType="String" paramDescription="key passphrase"
|
paramType="String" paramDescription="key passphrase"
|
||||||
description="Set the passphrase for encrypted private key. Password should be set before setting the key for the password to be used." />
|
description="Set the passphrase for encrypted private key. Password should be set before setting the key for the password to be used." />
|
||||||
|
<Option name="TLS_disable_plaintext_connection" code="55"
|
||||||
|
description="Prevent client from connecting to a non-TLS endpoint by throwing network connection failed error." />
|
||||||
<Option name="disable_multi_version_client_api" code="60"
|
<Option name="disable_multi_version_client_api" code="60"
|
||||||
description="Disables the multi-version client API and instead uses the local client directly. Must be set before setting up the network." />
|
description="Disables the multi-version client API and instead uses the local client directly. Must be set before setting up the network." />
|
||||||
<Option name="callbacks_on_external_threads" code="61"
|
<Option name="callbacks_on_external_threads" code="61"
|
||||||
|
|
|
@ -1694,6 +1694,9 @@ private:
|
||||||
case TLSConfig::OPT_TLS_VERIFY_PEERS:
|
case TLSConfig::OPT_TLS_VERIFY_PEERS:
|
||||||
tlsConfig.addVerifyPeers(args.OptionArg());
|
tlsConfig.addVerifyPeers(args.OptionArg());
|
||||||
break;
|
break;
|
||||||
|
case TLSConfig::OPT_TLS_DISABLE_PLAINTEXT_CONNECTION:
|
||||||
|
tlsConfig.setDisablePlainTextConnection(true);
|
||||||
|
break;
|
||||||
case OPT_KMS_CONN_DISCOVERY_URL_FILE: {
|
case OPT_KMS_CONN_DISCOVERY_URL_FILE: {
|
||||||
knobs.emplace_back("rest_kms_connector_discover_kms_url_file", args.OptionArg());
|
knobs.emplace_back("rest_kms_connector_discover_kms_url_file", args.OptionArg());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1321,7 +1321,8 @@ void Net2::initTLS(ETLSInitState targetState) {
|
||||||
.detail("CertificatePath", tlsConfig.getCertificatePathSync())
|
.detail("CertificatePath", tlsConfig.getCertificatePathSync())
|
||||||
.detail("KeyPath", tlsConfig.getKeyPathSync())
|
.detail("KeyPath", tlsConfig.getKeyPathSync())
|
||||||
.detail("HasPassword", !loaded.getPassword().empty())
|
.detail("HasPassword", !loaded.getPassword().empty())
|
||||||
.detail("VerifyPeers", boost::algorithm::join(loaded.getVerifyPeers(), "|"));
|
.detail("VerifyPeers", boost::algorithm::join(loaded.getVerifyPeers(), "|"))
|
||||||
|
.detail("DisablePlainTextConnection", tlsConfig.getDisablePlainTextConnection());
|
||||||
auto loadedTlsConfig = tlsConfig.loadSync();
|
auto loadedTlsConfig = tlsConfig.loadSync();
|
||||||
ConfigureSSLContext(loadedTlsConfig, newContext);
|
ConfigureSSLContext(loadedTlsConfig, newContext);
|
||||||
activeTlsPolicy = makeReference<TLSPolicy>(loadedTlsConfig, onPolicyFailure);
|
activeTlsPolicy = makeReference<TLSPolicy>(loadedTlsConfig, onPolicyFailure);
|
||||||
|
@ -1787,6 +1788,11 @@ Future<Reference<IConnection>> Net2::connect(NetworkAddress toAddr, tcp::socket*
|
||||||
return SSLConnection::connect(&this->reactor.ios, this->sslContextVar.get(), toAddr, existingSocket);
|
return SSLConnection::connect(&this->reactor.ios, this->sslContextVar.get(), toAddr, existingSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tlsConfig.getDisablePlainTextConnection()) {
|
||||||
|
TraceEvent(SevError, "PlainTextConnectionDisabled").detail("toAddr", toAddr);
|
||||||
|
throw connection_failed();
|
||||||
|
}
|
||||||
|
|
||||||
return Connection::connect(&this->reactor.ios, toAddr);
|
return Connection::connect(&this->reactor.ios, toAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ TLSPolicy::~TLSPolicy() {}
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <boost/asio/ssl/context.hpp>
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include "flow/Platform.h"
|
#include "flow/Platform.h"
|
||||||
#include "flow/IAsyncFile.h"
|
#include "flow/IAsyncFile.h"
|
||||||
|
@ -64,6 +65,10 @@ std::vector<std::string> LoadedTLSConfig::getVerifyPeers() const {
|
||||||
return { "Check.Valid=1" };
|
return { "Check.Valid=1" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LoadedTLSConfig::getDisablePlainTextConnection() const {
|
||||||
|
return tlsDisablePlainTextConnection;
|
||||||
|
}
|
||||||
|
|
||||||
std::string LoadedTLSConfig::getPassword() const {
|
std::string LoadedTLSConfig::getPassword() const {
|
||||||
if (tlsPassword.size()) {
|
if (tlsPassword.size()) {
|
||||||
return tlsPassword;
|
return tlsPassword;
|
||||||
|
@ -211,6 +216,22 @@ std::string TLSConfig::getCAPathSync() const {
|
||||||
return envCAPath;
|
return envCAPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TLSConfig::getDisablePlainTextConnection() const {
|
||||||
|
std::string envDisablePlainTextConnection;
|
||||||
|
if (platform::getEnvironmentVar("FDB_TLS_DISABLE_PLAINTEXT_CONNECTION", envDisablePlainTextConnection)) {
|
||||||
|
try {
|
||||||
|
return boost::lexical_cast<bool>(envDisablePlainTextConnection);
|
||||||
|
} catch (boost::bad_lexical_cast& e) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: Ignoring invalid FDB_TLS_DISABLE_PLAINTEXT_CONNECTION [%s]: %s\n",
|
||||||
|
envDisablePlainTextConnection.c_str(),
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlsDisablePlainTextConnection;
|
||||||
|
}
|
||||||
|
|
||||||
LoadedTLSConfig TLSConfig::loadSync() const {
|
LoadedTLSConfig TLSConfig::loadSync() const {
|
||||||
LoadedTLSConfig loaded;
|
LoadedTLSConfig loaded;
|
||||||
|
|
||||||
|
@ -253,6 +274,7 @@ LoadedTLSConfig TLSConfig::loadSync() const {
|
||||||
loaded.tlsPassword = tlsPassword;
|
loaded.tlsPassword = tlsPassword;
|
||||||
loaded.tlsVerifyPeers = tlsVerifyPeers;
|
loaded.tlsVerifyPeers = tlsVerifyPeers;
|
||||||
loaded.endpointType = endpointType;
|
loaded.endpointType = endpointType;
|
||||||
|
loaded.tlsDisablePlainTextConnection = tlsDisablePlainTextConnection;
|
||||||
|
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
@ -327,6 +349,7 @@ ACTOR Future<LoadedTLSConfig> TLSConfig::loadAsync(const TLSConfig* self) {
|
||||||
loaded.tlsPassword = self->tlsPassword;
|
loaded.tlsPassword = self->tlsPassword;
|
||||||
loaded.tlsVerifyPeers = self->tlsVerifyPeers;
|
loaded.tlsVerifyPeers = self->tlsVerifyPeers;
|
||||||
loaded.endpointType = self->endpointType;
|
loaded.endpointType = self->endpointType;
|
||||||
|
loaded.tlsDisablePlainTextConnection = self->tlsDisablePlainTextConnection;
|
||||||
|
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,8 @@ public:
|
||||||
// If no environment setting exists, return an empty string
|
// If no environment setting exists, return an empty string
|
||||||
std::string getPassword() const;
|
std::string getPassword() const;
|
||||||
|
|
||||||
|
bool getDisablePlainTextConnection() const;
|
||||||
|
|
||||||
TLSEndpointType getEndpointType() const { return endpointType; }
|
TLSEndpointType getEndpointType() const { return endpointType; }
|
||||||
|
|
||||||
bool isTLSEnabled() const { return endpointType != TLSEndpointType::UNSET; }
|
bool isTLSEnabled() const { return endpointType != TLSEndpointType::UNSET; }
|
||||||
|
@ -109,6 +111,7 @@ private:
|
||||||
std::string tlsCertBytes, tlsKeyBytes, tlsCABytes;
|
std::string tlsCertBytes, tlsKeyBytes, tlsCABytes;
|
||||||
std::string tlsPassword;
|
std::string tlsPassword;
|
||||||
std::vector<std::string> tlsVerifyPeers;
|
std::vector<std::string> tlsVerifyPeers;
|
||||||
|
bool tlsDisablePlainTextConnection;
|
||||||
TLSEndpointType endpointType = TLSEndpointType::UNSET;
|
TLSEndpointType endpointType = TLSEndpointType::UNSET;
|
||||||
|
|
||||||
friend class TLSConfig;
|
friend class TLSConfig;
|
||||||
|
@ -125,7 +128,8 @@ public:
|
||||||
OPT_TLS_KEY,
|
OPT_TLS_KEY,
|
||||||
OPT_TLS_VERIFY_PEERS,
|
OPT_TLS_VERIFY_PEERS,
|
||||||
OPT_TLS_CA_FILE,
|
OPT_TLS_CA_FILE,
|
||||||
OPT_TLS_PASSWORD
|
OPT_TLS_PASSWORD,
|
||||||
|
OPT_TLS_DISABLE_PLAINTEXT_CONNECTION
|
||||||
};
|
};
|
||||||
|
|
||||||
TLSConfig() = default;
|
TLSConfig() = default;
|
||||||
|
@ -161,6 +165,8 @@ public:
|
||||||
tlsCAPath = "";
|
tlsCAPath = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDisablePlainTextConnection(const bool val) { tlsDisablePlainTextConnection = val; }
|
||||||
|
|
||||||
void setPassword(const std::string& password) { tlsPassword = password; }
|
void setPassword(const std::string& password) { tlsPassword = password; }
|
||||||
|
|
||||||
void clearVerifyPeers() { tlsVerifyPeers.clear(); }
|
void clearVerifyPeers() { tlsVerifyPeers.clear(); }
|
||||||
|
@ -187,6 +193,8 @@ public:
|
||||||
std::string getKeyPathSync() const;
|
std::string getKeyPathSync() const;
|
||||||
std::string getCAPathSync() const;
|
std::string getCAPathSync() const;
|
||||||
|
|
||||||
|
bool getDisablePlainTextConnection() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ACTOR static Future<LoadedTLSConfig> loadAsync(const TLSConfig* self);
|
ACTOR static Future<LoadedTLSConfig> loadAsync(const TLSConfig* self);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -195,6 +203,7 @@ private:
|
||||||
std::string tlsCertPath, tlsKeyPath, tlsCAPath;
|
std::string tlsCertPath, tlsKeyPath, tlsCAPath;
|
||||||
std::string tlsCertBytes, tlsKeyBytes, tlsCABytes;
|
std::string tlsCertBytes, tlsKeyBytes, tlsCABytes;
|
||||||
std::string tlsPassword;
|
std::string tlsPassword;
|
||||||
|
bool tlsDisablePlainTextConnection = false;
|
||||||
std::vector<std::string> tlsVerifyPeers;
|
std::vector<std::string> tlsVerifyPeers;
|
||||||
TLSEndpointType endpointType = TLSEndpointType::UNSET;
|
TLSEndpointType endpointType = TLSEndpointType::UNSET;
|
||||||
};
|
};
|
||||||
|
@ -251,14 +260,16 @@ public:
|
||||||
#define TLS_VERIFY_PEERS_FLAG "--tls-verify-peers"
|
#define TLS_VERIFY_PEERS_FLAG "--tls-verify-peers"
|
||||||
#define TLS_CA_FILE_FLAG "--tls-ca-file"
|
#define TLS_CA_FILE_FLAG "--tls-ca-file"
|
||||||
#define TLS_PASSWORD_FLAG "--tls-password"
|
#define TLS_PASSWORD_FLAG "--tls-password"
|
||||||
|
#define TLS_DISABLE_PLAINTEXT_CONNECTION_FLAG "--tls-disable-plaintext-connection"
|
||||||
|
|
||||||
#define TLS_OPTION_FLAGS \
|
#define TLS_OPTION_FLAGS \
|
||||||
{ TLSConfig::OPT_TLS_PLUGIN, TLS_PLUGIN_FLAG, SO_REQ_SEP }, \
|
{ TLSConfig::OPT_TLS_PLUGIN, TLS_PLUGIN_FLAG, SO_REQ_SEP }, \
|
||||||
{ TLSConfig::OPT_TLS_CERTIFICATES, TLS_CERTIFICATE_FILE_FLAG, SO_REQ_SEP }, \
|
{ TLSConfig::OPT_TLS_CERTIFICATES, TLS_CERTIFICATE_FILE_FLAG, SO_REQ_SEP }, \
|
||||||
{ TLSConfig::OPT_TLS_KEY, TLS_KEY_FILE_FLAG, SO_REQ_SEP }, \
|
{ TLSConfig::OPT_TLS_KEY, TLS_KEY_FILE_FLAG, SO_REQ_SEP }, \
|
||||||
{ TLSConfig::OPT_TLS_VERIFY_PEERS, TLS_VERIFY_PEERS_FLAG, SO_REQ_SEP }, \
|
{ TLSConfig::OPT_TLS_VERIFY_PEERS, TLS_VERIFY_PEERS_FLAG, SO_REQ_SEP }, \
|
||||||
{ TLSConfig::OPT_TLS_PASSWORD, TLS_PASSWORD_FLAG, SO_REQ_SEP }, { \
|
{ TLSConfig::OPT_TLS_PASSWORD, TLS_PASSWORD_FLAG, SO_REQ_SEP }, \
|
||||||
TLSConfig::OPT_TLS_CA_FILE, TLS_CA_FILE_FLAG, SO_REQ_SEP \
|
{ TLSConfig::OPT_TLS_CA_FILE, TLS_CA_FILE_FLAG, SO_REQ_SEP }, { \
|
||||||
|
TLSConfig::OPT_TLS_DISABLE_PLAINTEXT_CONNECTION, TLS_DISABLE_PLAINTEXT_CONNECTION_FLAG, SO_NONE \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TLS_HELP \
|
#define TLS_HELP \
|
||||||
|
@ -274,7 +285,9 @@ public:
|
||||||
" The passphrase of encrypted private key\n" \
|
" The passphrase of encrypted private key\n" \
|
||||||
" " TLS_VERIFY_PEERS_FLAG " CONSTRAINTS\n" \
|
" " TLS_VERIFY_PEERS_FLAG " CONSTRAINTS\n" \
|
||||||
" The constraints by which to validate TLS peers. The contents\n" \
|
" The constraints by which to validate TLS peers. The contents\n" \
|
||||||
" and format of CONSTRAINTS are plugin-specific.\n"
|
" and format of CONSTRAINTS are plugin-specific.\n" \
|
||||||
|
" " TLS_DISABLE_PLAINTEXT_CONNECTION_FLAG "\n" \
|
||||||
|
" Disable non-TLS connections. All plaintext connection attempts will timeout.\n"
|
||||||
|
|
||||||
#include "flow/unactorcompiler.h"
|
#include "flow/unactorcompiler.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -79,11 +79,13 @@ class TLSConfig:
|
||||||
self,
|
self,
|
||||||
server_chain_len: int = 3,
|
server_chain_len: int = 3,
|
||||||
client_chain_len: int = 2,
|
client_chain_len: int = 2,
|
||||||
verify_peers="Check.Valid=1",
|
verify_peers: str = "Check.Valid=1",
|
||||||
|
client_disable_plaintext_connection: bool = False,
|
||||||
):
|
):
|
||||||
self.server_chain_len = server_chain_len
|
self.server_chain_len = server_chain_len
|
||||||
self.client_chain_len = client_chain_len
|
self.client_chain_len = client_chain_len
|
||||||
self.verify_peers = verify_peers
|
self.verify_peers = verify_peers
|
||||||
|
self.client_disable_plaintext_connection = client_disable_plaintext_connection
|
||||||
|
|
||||||
|
|
||||||
class LocalCluster:
|
class LocalCluster:
|
||||||
|
@ -154,6 +156,7 @@ knob_min_trace_severity=5
|
||||||
custom_config: dict = {},
|
custom_config: dict = {},
|
||||||
authorization_kty: str = "",
|
authorization_kty: str = "",
|
||||||
authorization_keypair_id: str = "",
|
authorization_keypair_id: str = "",
|
||||||
|
disable_server_side_tls: bool = False,
|
||||||
):
|
):
|
||||||
self.port_provider = PortProvider()
|
self.port_provider = PortProvider()
|
||||||
self.basedir = Path(basedir)
|
self.basedir = Path(basedir)
|
||||||
|
@ -202,6 +205,7 @@ knob_min_trace_severity=5
|
||||||
self.use_legacy_conf_syntax = False
|
self.use_legacy_conf_syntax = False
|
||||||
self.coordinators = set()
|
self.coordinators = set()
|
||||||
self.active_servers = set(self.server_ports.keys())
|
self.active_servers = set(self.server_ports.keys())
|
||||||
|
self.disable_server_side_tls = disable_server_side_tls
|
||||||
self.tls_config = tls_config
|
self.tls_config = tls_config
|
||||||
self.public_key_jwks_str = None
|
self.public_key_jwks_str = None
|
||||||
self.public_key_json_file = None
|
self.public_key_json_file = None
|
||||||
|
@ -287,7 +291,7 @@ knob_min_trace_severity=5
|
||||||
encrypt_config=encrypt_config,
|
encrypt_config=encrypt_config,
|
||||||
tls_config=self.tls_conf_string(),
|
tls_config=self.tls_conf_string(),
|
||||||
authz_public_key_config=self.authz_public_key_conf_string(),
|
authz_public_key_config=self.authz_public_key_conf_string(),
|
||||||
optional_tls=":tls" if self.tls_config is not None else "",
|
optional_tls=self.tls_optional_string(),
|
||||||
custom_config="\n".join(
|
custom_config="\n".join(
|
||||||
[
|
[
|
||||||
"{} = {}".format(key, value)
|
"{} = {}".format(key, value)
|
||||||
|
@ -333,7 +337,7 @@ knob_min_trace_severity=5
|
||||||
secret=self.cluster_secret,
|
secret=self.cluster_secret,
|
||||||
ip_addr=self.ip_address,
|
ip_addr=self.ip_address,
|
||||||
server_port=self.server_ports[0],
|
server_port=self.server_ports[0],
|
||||||
optional_tls=":tls" if self.tls_config else "",
|
optional_tls=self.tls_optional_string(),
|
||||||
)
|
)
|
||||||
return conn_str
|
return conn_str
|
||||||
|
|
||||||
|
@ -405,6 +409,8 @@ knob_min_trace_severity=5
|
||||||
"--tls-ca-file",
|
"--tls-ca-file",
|
||||||
self.server_ca_file,
|
self.server_ca_file,
|
||||||
]
|
]
|
||||||
|
if self.tls_config.client_disable_plaintext_connection:
|
||||||
|
args += ["--tls-disable-plaintext-connection"]
|
||||||
if self.use_future_protocol_version:
|
if self.use_future_protocol_version:
|
||||||
args += ["--use-future-protocol-version"]
|
args += ["--use-future-protocol-version"]
|
||||||
res = subprocess.run(
|
res = subprocess.run(
|
||||||
|
@ -476,7 +482,7 @@ knob_min_trace_severity=5
|
||||||
|
|
||||||
# Materialize server's TLS configuration section
|
# Materialize server's TLS configuration section
|
||||||
def tls_conf_string(self):
|
def tls_conf_string(self):
|
||||||
if self.tls_config is None:
|
if self.tls_config is None or self.disable_server_side_tls:
|
||||||
return ""
|
return ""
|
||||||
else:
|
else:
|
||||||
conf_map = {
|
conf_map = {
|
||||||
|
@ -487,6 +493,12 @@ knob_min_trace_severity=5
|
||||||
}
|
}
|
||||||
return "\n".join("{} = {}".format(k, v) for k, v in conf_map.items())
|
return "\n".join("{} = {}".format(k, v) for k, v in conf_map.items())
|
||||||
|
|
||||||
|
def tls_optional_string(self):
|
||||||
|
if self.tls_config is None or self.disable_server_side_tls:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return ":tls"
|
||||||
|
|
||||||
def authz_public_key_conf_string(self):
|
def authz_public_key_conf_string(self):
|
||||||
if self.public_key_json_file is not None:
|
if self.public_key_json_file is not None:
|
||||||
return "authorization-public-key-file = {}".format(
|
return "authorization-public-key-file = {}".format(
|
||||||
|
|
Loading…
Reference in New Issue