Add test for fdbcli's coordinator TLS suffix check
This commit is contained in:
parent
bcf0861a0a
commit
738a101a58
|
@ -7,6 +7,7 @@ import subprocess
|
||||||
import logging
|
import logging
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
||||||
|
@ -770,6 +771,68 @@ def integer_options():
|
||||||
assert lines[1].startswith('Committed')
|
assert lines[1].startswith('Committed')
|
||||||
assert error_output == b''
|
assert error_output == b''
|
||||||
|
|
||||||
|
def tls_address_suffix():
|
||||||
|
# fdbcli shall prevent a non-TLS fdbcli run from connecting to an all-TLS cluster, and vice versa
|
||||||
|
preamble = 'eNW1yf1M:eNW1yf1M@'
|
||||||
|
def make_addr(port: int, tls: bool = False):
|
||||||
|
return "127.0.0.1:{}{}".format(port, ":tls" if tls else "")
|
||||||
|
testcases = [
|
||||||
|
# IsServerTLS, NumServerAddrs
|
||||||
|
(True, 1),
|
||||||
|
(False, 1),
|
||||||
|
(True, 3),
|
||||||
|
(False, 3),
|
||||||
|
]
|
||||||
|
err_output_server_no_tls = "ERROR: fdbcli is configured with TLS, but none of the coordinators have TLS addresses."
|
||||||
|
err_output_server_tls = "ERROR: fdbcli is not configured with TLS, but all of the coordinators have TLS addresses."
|
||||||
|
|
||||||
|
# technically the contents of the certs and key files are not evaluated
|
||||||
|
# before tls-suffix check against tls configuration takes place,
|
||||||
|
# but we generate the certs and keys anyway to avoid
|
||||||
|
# imposing nuanced TLSConfig evaluation ordering requirement on the testcase
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
cert_file = tmpdir + "/client-cert.pem"
|
||||||
|
key_file = tmpdir + "/client-key.pem"
|
||||||
|
ca_file = tmpdir + "/server-ca.pem"
|
||||||
|
mkcert_process = subprocess.run([
|
||||||
|
args.build_dir + "/bin/mkcert",
|
||||||
|
"--server-chain-length", "1",
|
||||||
|
"--client-chain-length", "1",
|
||||||
|
"--server-cert-file", tmpdir + "/server-cert.pem",
|
||||||
|
"--client-cert-file", tmpdir + "/client-cert.pem",
|
||||||
|
"--server-key-file", tmpdir + "/server-key.pem",
|
||||||
|
"--client-key-file", tmpdir + "/client-key.pem",
|
||||||
|
"--server-ca-file", tmpdir + "/server-ca.pem",
|
||||||
|
"--client-ca-file", tmpdir + "/client-ca.pem",
|
||||||
|
],
|
||||||
|
capture_output=True)
|
||||||
|
if mkcert_process.returncode != 0:
|
||||||
|
print("mkcert returned with code {}".format(mkcert_process.returncode))
|
||||||
|
print("Output:\n{}{}\n".format(
|
||||||
|
mkcert_process.stdout.decode("utf8").strip(),
|
||||||
|
mkcert_process.stderr.decode("utf8").strip()))
|
||||||
|
assert False
|
||||||
|
cluster_fn = tmpdir + "/fdb.cluster"
|
||||||
|
for testcase in testcases:
|
||||||
|
is_server_tls, num_server_addrs = testcase
|
||||||
|
with open(cluster_fn, "w") as fp:
|
||||||
|
fp.write(preamble + ",".join(
|
||||||
|
[make_addr(port=4000 + addr_idx, tls=is_server_tls) for addr_idx in range(num_server_addrs)]))
|
||||||
|
fp.close()
|
||||||
|
tls_args = ["--tls-certificate-file",
|
||||||
|
cert_file,
|
||||||
|
"--tls-key-file",
|
||||||
|
key_file,
|
||||||
|
"--tls-ca-file",
|
||||||
|
ca_file] if not is_server_tls else []
|
||||||
|
fdbcli_process = subprocess.run(command_template[:2] + [cluster_fn] + tls_args, capture_output=True)
|
||||||
|
assert fdbcli_process.returncode != 0
|
||||||
|
err_out = fdbcli_process.stderr.decode("utf8").strip()
|
||||||
|
if is_server_tls:
|
||||||
|
assert err_out == err_output_server_tls, f"unexpected output: {err_out}"
|
||||||
|
else:
|
||||||
|
assert err_out == err_output_server_no_tls, f"unexpected output: {err_out}"
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
|
parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
|
||||||
description="""
|
description="""
|
||||||
|
@ -816,6 +879,7 @@ if __name__ == '__main__':
|
||||||
tenants()
|
tenants()
|
||||||
versionepoch()
|
versionepoch()
|
||||||
integer_options()
|
integer_options()
|
||||||
|
tls_address_suffix()
|
||||||
else:
|
else:
|
||||||
assert args.process_number > 1, "Process number should be positive"
|
assert args.process_number > 1, "Process number should be positive"
|
||||||
coordinators()
|
coordinators()
|
||||||
|
|
|
@ -49,6 +49,7 @@ enum EMkCertOpt : int {
|
||||||
OPT_PRINT_SERVER_CERT,
|
OPT_PRINT_SERVER_CERT,
|
||||||
OPT_PRINT_CLIENT_CERT,
|
OPT_PRINT_CLIENT_CERT,
|
||||||
OPT_PRINT_ARGUMENTS,
|
OPT_PRINT_ARGUMENTS,
|
||||||
|
OPT_ENABLE_TRACE,
|
||||||
};
|
};
|
||||||
|
|
||||||
CSimpleOpt::SOption gOptions[] = { { OPT_HELP, "--help", SO_NONE },
|
CSimpleOpt::SOption gOptions[] = { { OPT_HELP, "--help", SO_NONE },
|
||||||
|
@ -68,6 +69,7 @@ CSimpleOpt::SOption gOptions[] = { { OPT_HELP, "--help", SO_NONE },
|
||||||
{ OPT_PRINT_SERVER_CERT, "--print-server-cert", SO_NONE },
|
{ OPT_PRINT_SERVER_CERT, "--print-server-cert", SO_NONE },
|
||||||
{ OPT_PRINT_CLIENT_CERT, "--print-client-cert", SO_NONE },
|
{ OPT_PRINT_CLIENT_CERT, "--print-client-cert", SO_NONE },
|
||||||
{ OPT_PRINT_ARGUMENTS, "--print-args", SO_NONE },
|
{ OPT_PRINT_ARGUMENTS, "--print-args", SO_NONE },
|
||||||
|
{ OPT_ENABLE_TRACE, "--trace", SO_NONE },
|
||||||
SO_END_OF_OPTIONS };
|
SO_END_OF_OPTIONS };
|
||||||
|
|
||||||
template <size_t Len>
|
template <size_t Len>
|
||||||
|
@ -191,6 +193,7 @@ int main(int argc, char** argv) {
|
||||||
auto printServerCert = false;
|
auto printServerCert = false;
|
||||||
auto printClientCert = false;
|
auto printClientCert = false;
|
||||||
auto printArguments = false;
|
auto printArguments = false;
|
||||||
|
auto enableTrace = false;
|
||||||
auto args = CSimpleOpt(argc, argv, gOptions, SO_O_EXACT | SO_O_HYPHEN_TO_UNDERSCORE);
|
auto args = CSimpleOpt(argc, argv, gOptions, SO_O_EXACT | SO_O_HYPHEN_TO_UNDERSCORE);
|
||||||
while (args.Next()) {
|
while (args.Next()) {
|
||||||
if (auto err = args.LastError()) {
|
if (auto err = args.LastError()) {
|
||||||
|
@ -266,6 +269,8 @@ int main(int argc, char** argv) {
|
||||||
case OPT_PRINT_ARGUMENTS:
|
case OPT_PRINT_ARGUMENTS:
|
||||||
printArguments = true;
|
printArguments = true;
|
||||||
break;
|
break;
|
||||||
|
case OPT_ENABLE_TRACE:
|
||||||
|
enableTrace = true;
|
||||||
default:
|
default:
|
||||||
fmt::print(stderr, "ERROR: Unknown option {}\n", args.OptionText());
|
fmt::print(stderr, "ERROR: Unknown option {}\n", args.OptionText());
|
||||||
return FDB_EXIT_ERROR;
|
return FDB_EXIT_ERROR;
|
||||||
|
@ -277,11 +282,13 @@ int main(int argc, char** argv) {
|
||||||
platformInit();
|
platformInit();
|
||||||
Error::init();
|
Error::init();
|
||||||
g_network = newNet2(TLSConfig());
|
g_network = newNet2(TLSConfig());
|
||||||
|
if (enableTrace)
|
||||||
openTraceFile(NetworkAddress(), 10 << 20, 10 << 20, ".", "mkcert");
|
openTraceFile(NetworkAddress(), 10 << 20, 10 << 20, ".", "mkcert");
|
||||||
auto thread = std::thread([]() { g_network->run(); });
|
auto thread = std::thread([]() { g_network->run(); });
|
||||||
auto cleanUpGuard = ScopeExit([&thread]() {
|
auto cleanUpGuard = ScopeExit([&thread, enableTrace]() {
|
||||||
g_network->stop();
|
g_network->stop();
|
||||||
thread.join();
|
thread.join();
|
||||||
|
if (enableTrace)
|
||||||
closeTraceFile();
|
closeTraceFile();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue