Skip to content

Commit a580ad7

Browse files
committed
WL#15524 Patch #12 MGM TLS in API Nodes, mysqld, and Cluster/J
For the Ndb_cluster_connection::configure_tls() method added in wl#15135, this patch adds the MGM TLS level as a second argument. When some data node requires TLS, but an API node does not have a certificate, the API node will fail quickly. In mysqld, this adds the --ndb-mgm-tls option. In Cluster/J, a new property com.mysql.clusterj.tls.strict that takes numeric values 0 or 1 and defaults to 0. Add an NDBAPI test, testMgmd -n ApiWithoutCertificate Change-Id: If62349c288b0bef2b4594662ade3befa4dc5ed8a
1 parent 9b06a30 commit a580ad7

File tree

14 files changed

+120
-19
lines changed

14 files changed

+120
-19
lines changed

mysql-test/suite/ndb/r/ndb_basic.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ ndb_log_updated_only #
184184
ndb_metadata_check #
185185
ndb_metadata_check_interval #
186186
ndb_metadata_sync #
187+
ndb_mgm_tls #
187188
ndb_mgmd_host #
188189
ndb_nodeid #
189190
ndb_optimization_delay #

mysql-test/suite/ndb/r/ndb_basic_3rpl.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ ndb_log_updated_only #
184184
ndb_metadata_check #
185185
ndb_metadata_check_interval #
186186
ndb_metadata_sync #
187+
ndb_mgm_tls #
187188
ndb_mgmd_host #
188189
ndb_nodeid #
189190
ndb_optimization_delay #

mysql-test/suite/ndb/r/ndb_basic_4rpl.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ ndb_log_updated_only #
184184
ndb_metadata_check #
185185
ndb_metadata_check_interval #
186186
ndb_metadata_sync #
187+
ndb_mgm_tls #
187188
ndb_mgmd_host #
188189
ndb_nodeid #
189190
ndb_optimization_delay #

mysql-test/suite/ndb/r/ndb_basic_ndbd.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ ndb_log_updated_only #
184184
ndb_metadata_check #
185185
ndb_metadata_check_interval #
186186
ndb_metadata_sync #
187+
ndb_mgm_tls #
187188
ndb_mgmd_host #
188189
ndb_nodeid #
189190
ndb_optimization_delay #

storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/Constants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ public interface Constants {
4646
/** The default value of the TLS Search Path property. */
4747
static final String DEFAULT_PROPERTY_TLS_SEARCH_PATH = "$HOME/ndb-tls";
4848

49+
/*** The name of the boolean strict MGM TLS property. */
50+
static final String PROPERTY_MGM_STRICT_TLS = "com.mysql.clusterj.tls.strict";
51+
52+
/*** The default value of the MGM TLS level property */
53+
static final int DEFAULT_PROPERTY_MGM_STRICT_TLS = 0;
54+
4955
/** The name of the initial timeout for cluster connection to connect to MGM before connecting to data nodes
5056
* <a href="http://dev.mysql.com/doc/ndbapi/en/ndb-ndb-cluster-connection.html#ndb-ndb-cluster-connection-set-timeout">Ndb_cluster_connection::set_timeout()</a>
5157
*/

storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionFactoryImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public class SessionFactoryImpl implements SessionFactory, Constants {
7676
String CLUSTER_CONNECTION_SERVICE;
7777
String CLUSTER_CONNECT_STRING;
7878
String CLUSTER_TLS_SEARCH_PATH;
79+
int CLUSTER_STRICT_TLS;
7980
int CLUSTER_CONNECT_TIMEOUT_MGM;
8081
int CLUSTER_CONNECT_RETRIES;
8182
int CLUSTER_CONNECT_DELAY;
@@ -192,6 +193,8 @@ protected SessionFactoryImpl(Map<?, ?> props) {
192193
CLUSTER_CONNECT_STRING = getRequiredStringProperty(props, PROPERTY_CLUSTER_CONNECTSTRING);
193194
CLUSTER_TLS_SEARCH_PATH = getStringProperty(props, PROPERTY_TLS_SEARCH_PATH,
194195
Constants.DEFAULT_PROPERTY_TLS_SEARCH_PATH);
196+
CLUSTER_STRICT_TLS = getIntProperty(props, PROPERTY_MGM_STRICT_TLS,
197+
Constants.DEFAULT_PROPERTY_MGM_STRICT_TLS);
195198
CLUSTER_CONNECT_RETRIES = getIntProperty(props, PROPERTY_CLUSTER_CONNECT_RETRIES,
196199
Constants.DEFAULT_PROPERTY_CLUSTER_CONNECT_RETRIES);
197200
CLUSTER_CONNECT_TIMEOUT_MGM = getIntProperty(props, PROPERTY_CLUSTER_CONNECT_TIMEOUT_MGM,
@@ -364,7 +367,7 @@ protected ClusterConnection createClusterConnection(
364367
try {
365368
result = service.create(CLUSTER_CONNECT_STRING, nodeId, CLUSTER_CONNECT_TIMEOUT_MGM);
366369
result.setByteBufferPoolSizes(CLUSTER_BYTE_BUFFER_POOL_SIZES);
367-
result.configureTls(CLUSTER_TLS_SEARCH_PATH, 0);
370+
result.configureTls(CLUSTER_TLS_SEARCH_PATH, CLUSTER_STRICT_TLS);
368371
result.connect(CLUSTER_CONNECT_RETRIES, CLUSTER_CONNECT_DELAY,true);
369372
result.waitUntilReady(CLUSTER_CONNECT_TIMEOUT_BEFORE,CLUSTER_CONNECT_TIMEOUT_AFTER);
370373
// Cluster connection successful.

storage/ndb/include/ndbapi/ndb_cluster_connection.hpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,21 @@ class Ndb_cluster_connection {
116116
* may contain absolute directories, relative directories, and environment
117117
* variables which will be expanded.
118118
*
119-
* The second (int) parameter will be introduced in WL#15524.
119+
* mgm_tls_level is a value 0 or 1 specifying the requirement for TLS
120+
* to secure the MGM protocol connection between this node and the NDB
121+
* Management server.
122+
* 0 = Relaxed TLS (attempt to use TLS, but failure is OK)
123+
* 1 = Strict TLS (failure to establish TLS is treated as an error)
120124
*
121125
* If the node finds active NDB TLS node keys and certificates in the seach
122126
* path, it will be able to connect securely to other nodes. These keys and
123127
* certificates can be created using the ndb_sign_keys tool.
124128
*
125-
* If configure_tls() is not called for a connection, the search path used
126-
* will be the compile-time default NDB_TLS_SEARCH_PATH.
127-
129+
* If configure_tls() is not called for a connection, the search path
130+
* used will be the compile-time default NDB_TLS_SEARCH_PATH, and the
131+
* mgm_tls_level will be 0 (relaxed).
128132
*/
129-
void configure_tls(const char * tls_search_path, int);
133+
void configure_tls(const char * tls_search_path, int mgm_tls_level);
130134

131135
/**
132136
* For each Ndb_cluster_connection, NDB publishes a URI in the ndbinfo

storage/ndb/plugin/ha_ndbcluster.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ static bool opt_ndb_fully_replicated;
146146
static ulong opt_ndb_row_checksum;
147147

148148
char *opt_ndb_tls_search_path;
149+
ulong opt_ndb_mgm_tls_level;
149150

150151
// The version where ndbcluster uses DYNAMIC by default when creating columns
151152
static const ulong NDB_VERSION_DYNAMIC_IS_DEFAULT = 50711;
@@ -17614,6 +17615,16 @@ static MYSQL_SYSVAR_STR(tls_search_path, /* name */
1761417615
"Directory containing NDB Cluster TLS Private Keys",
1761517616
NULL, NULL, NDB_TLS_SEARCH_PATH);
1761617617

17618+
static const char *tls_req_levels[] = {"relaxed", "strict", NullS};
17619+
17620+
static TYPELIB mgm_tls_typelib = {array_elements(tls_req_levels) - 1, "",
17621+
tls_req_levels, nullptr};
17622+
17623+
static MYSQL_SYSVAR_ENUM(mgm_tls, opt_ndb_mgm_tls_level,
17624+
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
17625+
"MGM TLS Requirement level", nullptr, nullptr, 0,
17626+
&mgm_tls_typelib);
17627+
1761717628
static const int MIN_ACTIVATION_THRESHOLD = 0;
1761817629
static const int MAX_ACTIVATION_THRESHOLD = 16;
1761917630

@@ -18451,6 +18462,7 @@ static SYS_VAR *system_variables[] = {
1845118462
MYSQL_SYSVAR(index_stat_enable),
1845218463
MYSQL_SYSVAR(index_stat_option),
1845318464
MYSQL_SYSVAR(tls_search_path),
18465+
MYSQL_SYSVAR(mgm_tls),
1845418466
MYSQL_SYSVAR(table_no_logging),
1845518467
MYSQL_SYSVAR(table_temporary),
1845618468
MYSQL_SYSVAR(log_bin),

storage/ndb/plugin/ha_ndbcluster_connection.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ static uint g_pool_pos = 0;
6060
static mysql_mutex_t g_pool_mutex;
6161

6262
extern char *opt_ndb_tls_search_path;
63+
extern ulong opt_ndb_mgm_tls_level;
6364

6465
/**
6566
@brief Parse the --ndb-cluster-connection-pool-nodeids=nodeid[,nodeidN]
@@ -247,7 +248,8 @@ int ndbcluster_connect(ulong wait_connected, // Timeout in seconds
247248
char buf[128];
248249
snprintf(buf, sizeof(buf), "mysqld --server-id=%lu", server_id);
249250
g_ndb_cluster_connection->set_name(buf);
250-
g_ndb_cluster_connection->configure_tls(opt_ndb_tls_search_path, 0);
251+
g_ndb_cluster_connection->configure_tls(opt_ndb_tls_search_path,
252+
opt_ndb_mgm_tls_level);
251253
snprintf(buf, sizeof(buf), "%s%s", processinfo_path, server_id_string);
252254
g_ndb_cluster_connection->set_service_uri("mysql", processinfo_host,
253255
processinfo_port, buf);
@@ -309,7 +311,8 @@ int ndbcluster_connect(ulong wait_connected, // Timeout in seconds
309311
snprintf(buf, sizeof(buf), "mysqld --server-id=%lu (connection %u)",
310312
server_id, i + 1);
311313
g_pool[i]->set_name(buf);
312-
g_pool[i]->configure_tls(opt_ndb_tls_search_path, 0);
314+
g_pool[i]->configure_tls(opt_ndb_tls_search_path,
315+
opt_ndb_mgm_tls_level);
313316
const char *uri_sep = server_id ? ";" : "?";
314317
snprintf(buf, sizeof(buf), "%s%s%sconnection=%u", processinfo_path,
315318
server_id_string, uri_sep, i + 1);

storage/ndb/src/ndbapi/TransporterFacade.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,8 @@ void copy(Uint32*& /*insertPtr*/, class SectionSegmentPool& /*thePool*/,
499499

500500
int
501501
TransporterFacade::start_instance(NodeId nodeId,
502-
const ndb_mgm_configuration* conf)
502+
const ndb_mgm_configuration* conf,
503+
bool tls_required)
503504
{
504505
DBUG_ENTER("TransporterFacade::start_instance");
505506

@@ -527,6 +528,13 @@ TransporterFacade::start_instance(NodeId nodeId,
527528
m_tls_primary_api,
528529
m_mgm_tls_level);
529530

531+
if(tls_required && ! theTransporterRegistry->getTlsKeyManager()->ctx())
532+
{
533+
delete theTransporterRegistry;
534+
theTransporterRegistry = nullptr;
535+
DBUG_RETURN(-2);
536+
}
537+
530538
if (theClusterMgr == nullptr)
531539
{
532540
theClusterMgr = new ClusterMgr(*this);

storage/ndb/src/ndbapi/TransporterFacade.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class TransporterFacade :
7070
TransporterFacade(GlobalDictCache *cache);
7171
~TransporterFacade() override;
7272

73-
int start_instance(NodeId, const ndb_mgm_configuration*);
73+
int start_instance(NodeId, const ndb_mgm_configuration*, bool tls_req=false);
7474
void stop_instance();
7575

7676
void configure_tls(const char *, int type, bool primary, int mgmLevel);

storage/ndb/src/ndbapi/ndb_cluster_connection.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -942,14 +942,12 @@ Ndb_cluster_connection_impl::set_data_node_neighbour(Uint32 node)
942942
}
943943

944944
void
945-
Ndb_cluster_connection_impl::configure_tls(const char * searchPath)
945+
Ndb_cluster_connection_impl::configure_tls(const char * searchPath,
946+
int mgm_level)
946947
{
947948
bool isPrimary = ! (bool) m_main_connection;
948949
m_tls_search_path = strdup(searchPath);
949950

950-
/* A later patch will make mgm_level configurable */
951-
static constexpr int mgm_level = CLIENT_TLS_RELAXED;
952-
953951
m_config_retriever->init_mgm_tls(m_tls_search_path, ::Node::Type::Client,
954952
mgm_level);
955953
m_transporter_facade->api_configure_tls(m_tls_search_path, isPrimary,
@@ -1008,7 +1006,7 @@ Ndb_cluster_connection_impl::init_nodes_vector(Uint32 nodeid,
10081006

10091007
for(iter.first(); iter.valid(); iter.next())
10101008
{
1011-
Uint32 nodeid1, nodeid2, remoteNodeId, group= 5;
1009+
Uint32 nodeid1, nodeid2, tlsReq, remoteNodeId, group= 5;
10121010
const char *remoteHostName = nullptr;
10131011
if(iter.get(CFG_CONNECTION_NODE_1, &nodeid1)) continue;
10141012
if(iter.get(CFG_CONNECTION_NODE_2, &nodeid2)) continue;
@@ -1042,6 +1040,10 @@ Ndb_cluster_connection_impl::init_nodes_vector(Uint32 nodeid,
10421040
* decrease it by 1.
10431041
*/
10441042
case CONNECTION_TYPE_TCP:{
1043+
// check for TLS requirement
1044+
iter.get(CFG_TCP_REQUIRE_TLS, &tlsReq);
1045+
if(tlsReq) m_tls_requirement = true;
1046+
10451047
// connecting through localhost
10461048
// check if config_hostname is local
10471049
// check if in same location domain
@@ -1408,9 +1410,10 @@ Ndb_cluster_connection_impl::do_test()
14081410
delete[] nodes;
14091411
}
14101412

1411-
void Ndb_cluster_connection::configure_tls(const char * searchPath, int)
1413+
void Ndb_cluster_connection::configure_tls(const char * searchPath,
1414+
int mgmTlsLevel)
14121415
{
1413-
m_impl.configure_tls(searchPath);
1416+
m_impl.configure_tls(searchPath, mgmTlsLevel);
14141417
}
14151418

14161419
void Ndb_cluster_connection::set_data_node_neighbour(Uint32 node)
@@ -1494,10 +1497,21 @@ int Ndb_cluster_connection_impl::connect(int no_retries,
14941497
DBUG_RETURN(-1);
14951498
}
14961499

1497-
if (m_transporter_facade->start_instance(nodeId, config.get()) < 0)
1500+
int r_start = m_transporter_facade->start_instance(nodeId,
1501+
config.get(),
1502+
m_tls_requirement);
1503+
if (r_start == -2)
1504+
{
1505+
m_latest_error = 2;
1506+
m_latest_error_msg.assign(
1507+
"TLS is required but this node does not have a valid certificate");
1508+
}
1509+
1510+
if (r_start < 0)
14981511
{
14991512
DBUG_RETURN(-1);
15001513
}
1514+
15011515
// NOTE! The config generation used by this API node could also be sent to
15021516
// the cluster in same way as other properties with setProcessInfoUri()
15031517
m_transporter_facade->theClusterMgr->setProcessInfoUri(m_uri_scheme.c_str(),

storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class Ndb_cluster_connection_impl : public Ndb_cluster_connection
134134
int configure(Uint32 nodeid, const ndb_mgm_configuration *config);
135135
void connect_thread();
136136
void set_name(const char *name);
137-
void configure_tls(const char * search_path);
137+
void configure_tls(const char * search_path, int mgm_tls_level);
138138
int set_service_uri(const char *, const char *, int, const char *);
139139
void set_data_node_neighbour(Uint32 neighbour_node);
140140
void adjust_node_proximity(Uint32 node_id, Int32 adjustment);
@@ -212,6 +212,9 @@ class Ndb_cluster_connection_impl : public Ndb_cluster_connection
212212

213213
// TLS Certificate Search Path
214214
const char * m_tls_search_path {nullptr};
215+
216+
// Some connection requires TLS
217+
bool m_tls_requirement{false};
215218
};
216219

217220
#endif

storage/ndb/test/ndbapi/testMgmd.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,44 @@ runTestMgmdWithoutCert(NDBT_Context* ctx, NDBT_Step* step)
19641964
return NDBT_OK;
19651965
}
19661966

1967+
int runTestApiWithoutCert(NDBT_Context* ctx, NDBT_Step* step)
1968+
{
1969+
NDBT_Workingdir wd("test_tls"); // temporary working directory
1970+
1971+
BaseString cfg_path = path(wd.path(), "config.ini", nullptr);
1972+
Properties config = ConfigFactory::create();
1973+
CHECK(ConfigFactory::put(config, "ndbd", 2, "RequireTls", "true"));
1974+
CHECK(ConfigFactory::write_config_ini(config, cfg_path.c_str()));
1975+
1976+
CHECK(sign_tls_keys(wd));
1977+
1978+
Mgmd mgmd(1);
1979+
Ndbd ndbd(2);
1980+
1981+
NdbProcess::Args mgmdArgs;
1982+
mgmd.common_args(mgmdArgs, wd.path());
1983+
1984+
CHECK(mgmd.start(wd.path(), mgmdArgs)); // Start management node
1985+
CHECK(mgmd.connect(config)); // Connect to management node
1986+
CHECK(mgmd.wait_confirmed_config()); // Wait for configuration
1987+
1988+
ndbd.args().add("--ndb-tls-search-path=", wd.path());
1989+
ndbd.start(wd.path(), mgmd.connectstring(config)); // Start data node
1990+
NdbMgmHandle handle = mgmd.handle() ;
1991+
CHECK(ndbd.wait_started(handle));
1992+
1993+
/* API has no TLS context and should fail to connect */
1994+
Ndb_cluster_connection con(mgmd.connectstring(config).c_str());
1995+
con.set_name("api_without_cert");
1996+
int r = con.connect(0,0,1);
1997+
CHECK(r == -1);
1998+
printf("ERROR %d: %s\n", con.get_latest_error(), con.get_latest_error_msg());
1999+
2000+
ndbd.stop();
2001+
mgmd.stop();
2002+
return NDBT_OK;
2003+
}
2004+
19672005
int
19682006
runTestNdbdWithoutCert(NDBT_Context* ctx, NDBT_Step* step)
19692007
{
@@ -2292,6 +2330,12 @@ TESTCASE("NdbdWithoutCertificate",
22922330
INITIALIZER(runTestNdbdWithoutCert)
22932331
}
22942332

2333+
TESTCASE("ApiWithoutCertificate",
2334+
"Test API node without certificate where TRP TLS is required")
2335+
{
2336+
INITIALIZER(runTestApiWithoutCert)
2337+
}
2338+
22952339
TESTCASE("NdbdWithExpiredCertificate",
22962340
"Test data node startup with expired certificate")
22972341
{

0 commit comments

Comments
 (0)