Conversation
Checklist before you submit for review
|
This ticket ports DSP-24965 adding cluster membership checks for nodes in some extra code paths to prevent foreing nodes from joining.
|
❌ Build ds-cassandra-pr-gate/PR-2289 rejected by Butler3 regressions found Found 3 new test failures
Found 8 known test failures |
|
CI failures lgtm:
|
djatnieks
left a comment
There was a problem hiding this comment.
Suggest maybe to also have the DSP ticket reviewer also review this
JeremiahDJordan
left a comment
There was a problem hiding this comment.
This patch was rejected from Apache Cassandra. Do we really want to add new gossip states that are not going to end up in the upstream? @driftx thoughts? ideas for how we can protect against this without adding new gossip states?
|
I believe the community rejected this approach not because of adding new states, but because of sticking them in a new json field and adding json processing to gossip. I think it would be better received if we were just adding CLUSTER_NAME and PARTITIONER_NAME as new states in the existing framework. |
|
Thx for the comments. As for the DSP ticket reviewer he is on parental leave atm. On the JSON state this mirrors what we've had in DSE for years. We also preferred not burning 2 states. On top of that adding states messes up ApplicationStates alignment during upgrade tests needing careful attention. You don't want to be having these problems again in the CC world so the DSE solution seems the best future proof approach imho. On OSS it was rejected, iiuc, as it was seen as a non problem and node to node auth should be used instead. Yes we would like to add this to CC as this is a DSE fix requested by Apple now being ported to HCD (CC). I'm happy to go either way: JSON or 2 extra states. I just need a decision to what the preferred solution is. |
|
@bereng I do not think we should add new JSON stuff to CC. You mention the DSE JSON payload. I would be less against adding the same state that DSE has. That would just be giving us DSE compatibility, and OSS already marked that DSE one as a "dead" state. So it won't cause compatibility issues. |
|
Oh that is an excellent idea tbh. I like it a lot. It is ordinal 10 so would now match |
| { | ||
| InetAddressAndPort from = message.from(); | ||
| logger.trace("Received a GossipDigestAck2Message from {}", from); | ||
| } |
There was a problem hiding this comment.
nit: this change can be avoided. it's better to call message.from() again on line 49, then touch more lines of code. this is for the sake of rebases. new lines are easy, changes lines like this^ quickly are painful.
|
|
||
| InetAddressAndPort nodeAddress = FBUtilities.getBroadcastAddressAndPort(); | ||
| // Send cluster and partitioner names for cluster foreign node checks | ||
| if (deltaEpStateMap.get(nodeAddress) != null && | ||
| !deltaEpStateMap.get(nodeAddress).containsApplicationState(ApplicationState.JSON_PAYLOAD)) | ||
| { | ||
| deltaEpStateMap.get(nodeAddress).addApplicationState(ApplicationState.JSON_PAYLOAD, | ||
| ApplicationState.serializeJsonPayload(ApplicationState.initialJsonPayload)); | ||
|
|
||
| } | ||
| deltaEpStateMap = removeForeignClusterNodes(deltaEpStateMap); | ||
|
|
There was a problem hiding this comment.
nit: can we make this a method ? removing the duplicated code in createShadowReply(), and making rebases that little bit easier.
| return endpointStateMap.size(); | ||
| } | ||
|
|
||
| public Map<InetAddressAndPort, EndpointState> getEndpointStateMapUnsafeForTest() |
There was a problem hiding this comment.
| public Map<InetAddressAndPort, EndpointState> getEndpointStateMapUnsafeForTest() | |
| @VisibleForTesting | |
| public Map<InetAddressAndPort, EndpointState> getEndpointStateMapUnsafeForTest() |
?
| public static <T> Message<T> synthetic(InetAddressAndPort from, Verb verb, T payload) | ||
| { | ||
| return new Message<>(new Header(-1, verb, from, -1, -1, 0, NO_PARAMS), payload); | ||
| } |
| if (jsonMap != null) | ||
| { | ||
| String auxValue = (String) jsonMap.get(ApplicationState.JsonPayload.CLUSTER_NAME.name()); | ||
| if (auxValue != null && !auxValue.equals(DatabaseDescriptor.getClusterName())) |
There was a problem hiding this comment.
nit: can be simplified
| if (auxValue != null && !auxValue.equals(DatabaseDescriptor.getClusterName())) | |
| if (DatabaseDescriptor.getClusterName().equals(auxValue))) |
can be applied to line 2644 too
| private void markAlive(final InetAddressAndPort addr, final EndpointState localState) | ||
| { | ||
| if (!maybeBelongsInCluster(addr, localState)) | ||
| logger.error("Not sending ECHO to {} which doesn't belong in this cluster", addr); |
There was a problem hiding this comment.
(question)
i see that the gossiper just ignores an unknown node (over different verbs). how does the unknown node itself respond and behave to this ? if the operator is primarily observing that node will they see enough to know what is now happening here ?
| if (!maybeBelongsInCluster(entry.getKey(), entry.getValue())) | ||
| { | ||
| logger.error("Ignoring Gossip from node {} because its state has info from other clusters {}", entry.getKey(), entry.getValue()); | ||
| it.remove(); |
There was a problem hiding this comment.
is this (thread) safe ?
| // for each test case, the MIGRATION_DELAY time is adjusted accordingly | ||
| savedMigrationDelay = CassandraRelevantProperties.MIGRATION_DELAY.getLong(); | ||
| CassandraRelevantProperties.MIGRATION_DELAY.setLong(ManagementFactory.getRuntimeMXBean().getUptime() + savedMigrationDelay); | ||
| DatabaseDescriptor.clientInitialization(); |
There was a problem hiding this comment.
heh ? what's with all the tests getting this added (but otherwise not changing in any way) ?
I share this question, without really having a solid opinion. I'm uneasy about all gossip/verb changes that makes CC communicate differently to C*, and there's a more solid proper solution to this: implementing internode encryption using per-node certs+ and host verification. I don't know if that's appropriate for the customer, or if this is a guardrail that adds enough value to overcome the concerns… What's our future compatibility plan on this ? Are we expecting CC5 to also provide it ? Are we expecting mix-version clusters to provide it ? What happens if such a strange node is added to a cluster in the middle of a C* to CC upgrade ? This might seem esoteric, but nice to have brief thoughts/answers written down to it… |



This ticket ports DSP-24965 adding cluster membership checks for nodes in some extra code paths to prevent foreign nodes from joining.
What is the issue
In some rare scenarios, some with bad config, some with the wrong data folders plugged into the wrong node, operator mistake, etc nodes from cluster A can join nodes from cluster B. That breaks topology badly both for A and B.
What does this PR fix and why was it fixed
This PR extends the original cluster membership check to all other susceptible code paths to prevent these.