Skip to content

CASSANDRA-21146 Guardrail for client driver versions#4699

Closed
smiklosovic wants to merge 2 commits intoapache:trunkfrom
smiklosovic:CASSANDRA-21146
Closed

CASSANDRA-21146 Guardrail for client driver versions#4699
smiklosovic wants to merge 2 commits intoapache:trunkfrom
smiklosovic:CASSANDRA-21146

Conversation

@smiklosovic
Copy link
Copy Markdown
Contributor

Thanks for sending a pull request! Here are some tips if you're new here:

  • Ensure you have added or run the appropriate tests for your PR.
  • Be sure to keep the PR description updated to reflect all changes.
  • Write your PR title to summarize what this PR proposes.
  • If possible, provide a concise example to reproduce the issue for a faster review.
  • Read our contributor guidelines
  • If you're making a documentation change, see our guide to documentation contribution

Commit messages should follow the following format:

<One sentence description, usually Jira title or CHANGES.txt summary>

<Optional lengthier description (context on patch)>

patch by <Authors>; reviewed by <Reviewers> for CASSANDRA-#####

Co-authored-by: Name1 <email1>
Co-authored-by: Name2 <email2>

The Cassandra Jira

@smiklosovic smiklosovic force-pushed the CASSANDRA-21146 branch 9 times, most recently from 717609b to 4e3a9d4 Compare March 31, 2026 12:20
@bschoening bschoening requested a review from Copilot April 1, 2026 20:13
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a new guardrail to warn or reject native protocol connections based on configured minimum client driver versions.

Changes:

  • Adds ClientDriverVersionGuardrail and wires it into STARTUP processing to enforce driver version constraints.
  • Exposes warned/disallowed driver-version maps via Guardrails MBean + configuration plumbing.
  • Adds unit and integration tests for version parsing/comparison and guardrail behavior.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/java/org/apache/cassandra/db/guardrails/ClientDriverVersionGuardrail.java Implements the guardrail logic for comparing driver versions against configured minimums.
src/java/org/apache/cassandra/db/guardrails/Guardrails.java Registers the new guardrail and adds MBean getter/setter JSON serialization for the new config.
src/java/org/apache/cassandra/transport/messages/StartupMessage.java Invokes the guardrail during client STARTUP when driver name/version are provided.
src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java Adds MBean methods for getting/setting minimum client driver versions (warn/fail).
src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java Extends guardrails config interface with minimum driver version maps.
src/java/org/apache/cassandra/config/GuardrailsOptions.java Implements the new config getters and adds setters with logging for runtime updates.
src/java/org/apache/cassandra/config/Config.java Adds YAML-backed config fields for warned/disallowed minimum driver versions.
src/java/org/apache/cassandra/tools/nodetool/GuardrailsConfigCommand.java Excludes the new map-based configs from nodetool guardrails config handling.
conf/cassandra.yaml Documents new YAML options for minimum client driver versions (warn/disallow).
conf/cassandra_latest.yaml Mirrors the new YAML documentation in the “latest” config template.
test/unit/org/apache/cassandra/db/guardrails/GuardrailClientDriverVersionTest.java Adds unit/integration tests for version comparisons and guardrail outcomes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@smiklosovic smiklosovic force-pushed the CASSANDRA-21146 branch 2 times, most recently from eb26940 to 59d739e Compare April 2, 2026 12:59
@tolbertam tolbertam self-requested a review April 9, 2026 15:02

# Minimum client driver versions. Connections from drivers whose version is below
# the configured minimum will be warned or rejected. Connections that do not report
# a driver name or version are considered valid. The map key is the driver name
Copy link
Copy Markdown
Contributor

@tolbertam tolbertam Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be really useful to have a way to warn or disallow on unknown Driver implementations, or ones that don't have anything set. Could we consider adding options for that (maybe using special keys like 'unknown' and 'unset'.
This doesn't necessarily need to be done in this change as could be done additively but would be nice if an operator wants to enforce specific driver implementations

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just thinking where this is going to be actually exercised? It is not like you are running drivers without any driver id every other day that this would be so common it would need to have a lot of attention. For 99.9% of cases your connections will always have identifiers in some fashion. At least everything under Apache Cassandra umbrella should have (not sure what the situation is with c++ or nodejs drivers etc but they should have the very same concept of driver ids).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not like you are running drivers without any driver id every other day that this would be so common it would need to have a lot of attention

This does happen occasionally for us, we help partner teams by supporting specific drivers, but we don't currently mandate what gets used.

  • Clients not sending driver versions: We've had some occasions where a team is using a very old driver that doesn't send driver name/version and it would be nice to have some enforcement/visibility around that.

  • Clients using client libraries we don't know about: Using a language like rust that has a community maintained driver that does send this information (https://github.com/scylladb/scylla-rust-driver).

In either case having some visibility via the warning guardrail could be useful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"unknown"/"unset" implementation looks great to me, thank you!

2026/04/12 15:21:31 Host: 127.0.0.1
2026/04/12 15:21:31 Username: cassandra
2026/04/12 15:21:31 Driver name: Andys Custom Driver
2026/04/12 15:21:31 Driver version: 3.6.0
2026/04/12 15:21:31 gocql: received 1 warning(s) from server for frame op=ERROR stream=64
2026/04/12 15:21:31 gocql: warning - Guardrail minimum_client_driver_versions violated: Detected unknown driver id: Andys Custom Driver.
2026/04/12 15:21:31 Failed to connect to Cassandra: gocql: unable to create session: unable to discover protocol version: Guardrail minimum_client_driver_versions violated: Detected unknown driver id: Andys Custom Driver.
2026/04/12 15:59:04 Host: 127.0.0.1
2026/04/12 15:59:04 Username: cassandra
2026/04/12 15:59:04 gocql: received 1 warning(s) from server for frame op=ERROR stream=64
2026/04/12 15:59:04 gocql: warning - Guardrail minimum_client_driver_versions violated: Connections with unset driver id's are forbidden.
2026/04/12 15:59:04 Failed to connect to Cassandra: gocql: unable to create session: unable to discover protocol version: Guardrail minimum_client_driver_versions violated: Connections with unset driver id's are forbidden.
exit status 1

Comment on lines +61 to +85
String sanitizedDriverId = driverName == null ? null : driverName.trim();
if (sanitizedDriverId == null || sanitizedDriverId.isBlank())
{
logger.debug("minimum_client_driver_versions guardrail identified empty driver " +
"id to check the minimum version of, such connections will be allowed but " +
"an operator should check what kind of clients are connecting to the cluster.");
return;
}

String sanitizedDriverVersion = GuardrailsOptions.sanitizeVersion(driverVersion);
if (sanitizedDriverVersion == null)
{
logger.debug("minimum_client_driver_versions guardrail identified empty driver " +
"version to check the minimum version of, such connections will be allowed but " +
"an operator should check what kind of clients are connecting to the cluster.");
return;
}

if (!GuardrailsOptions.isValidVersion(sanitizedDriverVersion))
{
logger.debug("minimum_client_driver_versions guardrail identified driver " +
"version which is not compliant semver version, such connections will be allowed but " +
"an operator should check what kind of clients are connecting to the cluster.");
return;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as alluded here i think it would be nice to guard on these scenarios too, but i don't think it needs to necessarily be handled in this PR

if (minimumVersionWarn != null && isBelowMinimum(sanitizedDriverVersion, minimumVersionWarn))
{
warn(String.format("Client driver %s is below recommended minimum version %s",
sanitizedDriverId, minimumVersionWarn));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another thing is that I suspect most drivers won't support logging warnings for something like a READY response, but this does work. I added it for gocql and I see the warnings being emitted for each connection:

2026/04/11 15:56:34 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 15:56:34 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver github.com/apache/cassandra-gocql-driver is below recommended minimum version 2.0.0
2026/04/11 15:56:34 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 15:56:34 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver github.com/apache/cassandra-gocql-driver is below recommended minimum version 2.0.0
2026/04/11 15:56:34 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 15:56:34 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver github.com/apache/cassandra-gocql-driver is below recommended minimum version 2.0.0
2026/04/11 15:56:34 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 15:56:34 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver github.com/apache/cassandra-gocql-driver is below recommended minimum version 2.0.0

Copy link
Copy Markdown
Contributor

@tolbertam tolbertam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works great, thank you @smiklosovic ! I had a couple suggestions (e.g. including the client version in the messages), but I am +1 on the changes overall.

I tested this by updating gocql to log all warnings received on frames, and also to allow passing in arbitrary driver name and versions. Tried several permutations with multiple driver names/version combinations and everything works as expected:

 go run main.go -n "DataStax Java Driver" -v 3.11.0
2026/04/11 16:46:16 Host: 127.0.0.1
2026/04/11 16:46:16 Username: cassandra
2026/04/11 16:46:16 Driver name: DataStax Java Driver
2026/04/11 16:46:16 Driver version: 3.11.0
2026/04/11 16:46:16 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 16:46:16 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver DataStax Java Driver is below recommended minimum version 4.0.0
2026/04/11 16:46:16 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 16:46:16 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver DataStax Java Driver is below recommended minimum version 4.0.0
2026/04/11 16:46:16 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 16:46:16 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver DataStax Java Driver is below recommended minimum version 4.0.0
2026/04/11 16:46:16 gocql: received 1 warning(s) from server for frame op=AUTHENTICATE stream=64
2026/04/11 16:46:16 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver DataStax Java Driver is below recommended minimum version 4.0.0
Connection successful!
Cluster Name: Test Cluster
Data Center: datacenter1
Rack: rack1
Host ID: 6d194555-f6eb-41d0-c000-000000000001

Peers in the cluster:

Active client connections:
  Client: 127.0.0.1:51374
    Driver: DataStax Java Driver/3.11.0
    Protocol Version: 4
    Username: cassandra
  Client: 127.0.0.1:51375
    Driver: DataStax Java Driver/3.11.0
    Protocol Version: 4
    Username: cassandra
  Client: 127.0.0.1:51376
    Driver: DataStax Java Driver/3.11.0
    Protocol Version: 4
    Username: cassandra

go run main.go -n "DataStax Java Driver" -v 3.6.0
2026/04/11 16:46:21 Host: 127.0.0.1
2026/04/11 16:46:21 Username: cassandra
2026/04/11 16:46:21 Driver name: DataStax Java Driver
2026/04/11 16:46:21 Driver version: 3.6.0
2026/04/11 16:46:21 gocql: received 1 warning(s) from server for frame op=ERROR stream=64
2026/04/11 16:46:21 gocql: warning - Guardrail minimum_client_driver_versions violated: Client driver DataStax Java Driver is below required minimum version 3.11.0, connection rejected
2026/04/11 16:46:21 Failed to connect to Cassandra: gocql: unable to create session: unable to discover protocol version: Guardrail minimum_client_driver_versions violated: Client driver DataStax Java Driver is below required minimum version 3.11.0, connection rejected

Copy link
Copy Markdown
Contributor

@tolbertam tolbertam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thank you! 🚀

@pmcfadin pmcfadin added the needs-committer Patch ready, waiting for a committer to review and merge label Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-committer Patch ready, waiting for a committer to review and merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants