Client TLS protects CQL sessions between application clients and Apache Cassandra nodes from plaintext exposure on the native transport port. Without it, credentials, schema queries, and row data can cross a reachable network segment without encryption even when database authentication is enabled.
Cassandra manages client-to-node encryption under client_encryption_options in /etc/cassandra/cassandra.yaml for package installs. With enabled set to true and optional set to true, encrypted and unencrypted clients can share native_transport_port during a rollout. With optional set to false, clients must negotiate TLS before CQL can proceed.
Use a rolling change and prepare trusted CA material for every client before making TLS mandatory. Examples use package paths, a PKCS12 server keystore, and a cqlsh TLS profile; tarball installs use conf/cassandra.yaml under the Cassandra home, and mutual client certificate authentication also needs a Cassandra truststore plus userkey and usercert entries in the client profile.
$ cqlsh 10.0.0.10 9042 -e "SHOW HOST" Connected to SG Cluster at 10.0.0.10:9042
Replace 10.0.0.10 with the Cassandra node address that clients use for native transport.
$ sudo install -o cassandra -g cassandra -m 0750 -d /etc/cassandra/tls
$ sudo install -o cassandra -g cassandra -m 0600 server-keystore.p12 /etc/cassandra/tls/server-keystore.p12
Use a certificate whose names match the addresses or hostnames used by clients. Keep the private key and keystore password out of shared transcripts and shell history.
$ sudo cp /etc/cassandra/cassandra.yaml /etc/cassandra/cassandra.yaml.pre-client-tls
$ sudoedit /etc/cassandra/cassandra.yaml
client_encryption_options: enabled: true optional: true keystore: /etc/cassandra/tls/server-keystore.p12 keystore_password: REPLACE_WITH_KEYSTORE_PASSWORD store_type: PKCS12 require_client_auth: false
optional: true lets encrypted and unencrypted clients connect on the same native transport port while client profiles and application drivers are updated.
Set require_client_auth to true only when Cassandra has a truststore for client certificate issuers and each client presents a matching certificate.
$ sudo systemctl restart cassandra
Cassandra validates this configuration during startup. If the service fails to start, restore the backup file or fix the keystore path, password, store type, or certificate before moving to another node.
$ nodetool status Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 10.0.0.10 144.32 KiB 16 100.0% d0b8b726-c680-4b42-bb57-3fa50db70e6a rack1
UN means the node is up and normal from this node's ring view.
Related: How to check Apache Cassandra cluster status with nodetool
Related: How to check Apache Cassandra service status
$ mkdir -p ~/.cassandra
$ install -m 0644 cluster-ca.pem ~/.cassandra/cassandra-ca.pem
Use the CA certificate or certificate bundle that signs the Cassandra server certificate. Do not copy the server private key to client hosts.
[connection] hostname = 10.0.0.10 port = 9042 ssl = true [ssl] certfile = ~/.cassandra/cassandra-ca.pem validate = true
When require_client_auth is true, add userkey and usercert under [ssl] and point them at the client's PEM key and certificate.
$ cqlsh --cqlshrc ~/.cassandra/cqlshrc -e "SHOW HOST" Connected to SG Cluster at 10.0.0.10:9042
Restart one node at a time, wait for UN in nodetool status, and confirm encrypted cqlsh access before changing the next node.
Driver option names differ, but the client must trust the server certificate chain and connect to the same native transport host and port used in the server certificate names.
client_encryption_options: enabled: true optional: false keystore: /etc/cassandra/tls/server-keystore.p12 keystore_password: REPLACE_WITH_KEYSTORE_PASSWORD store_type: PKCS12 require_client_auth: false
native_transport_port_ssl is deprecated in Cassandra 5.0, so prefer mandatory TLS on native_transport_port unless an existing compatibility plan requires a separate secure port.
$ sudo systemctl restart cassandra
Wait for each node to return to UN before restarting the next node.
Related: How to check Apache Cassandra service status
$ cqlsh --cqlshrc /dev/null 10.0.0.10 9042 -e "SHOW HOST"
Connection error: ('Unable to connect to any servers', {'10.0.0.10:9042': ConnectionShutdown('Connection to 10.0.0.10:9042 was closed')})
The rejection confirms the native transport listener no longer accepts plaintext CQL sessions.
$ cqlsh --cqlshrc ~/.cassandra/cqlshrc -e "SELECT cluster_name, native_protocol_version FROM system.local;" cluster_name | native_protocol_version --------------+------------------------- SG Cluster | 5 (1 rows)
A successful read from system.local proves the client can negotiate TLS and execute CQL through the secured native transport port.