3. Enable encryption¶
This is a part of the Charmed Apache Cassandra Tutorial.
TLS encrypts data exchanged between applications, securing it as it travels over the network. Typically, enabling TLS within a highly available database, and between the database and its clients, requires domain-specific knowledge and a high level of expertise. Fortunately, that knowledge has been encoded into Charmed Apache Cassandra, so configuring TLS requires minimal effort on your end.
Juju relations are particularly useful for enabling TLS. Charmed Apache Cassandra implements the Requirer side of the tls-certificates relation, so any charm implementing the Provider side can supply certificates. The relation centralises certificate management, handling provisioning, requests, and renewal, and lets you use different providers such as self-signed certificates or external services like Let’s Encrypt.
Charmed Apache Cassandra supports two separate TLS channels, each exposed as its own relation endpoint:
peer-certificates- encrypts peer-to-peer traffic between the nodes in the clusterclient-certificates- encrypts client-to-node traffic, for example connections fromcqlsh
Note
In this tutorial we distribute self-signed certificates signed by a single root CA. This is for testing and demonstration only. Self-signed certificates are not recommended for a production cluster. For guidance on choosing a provider, see the Security with X.509 certificates page.
Deploy a certificate provider¶
Before enabling TLS on Charmed Apache Cassandra, deploy the self-signed-certificates charm:
juju deploy self-signed-certificates --channel 1/stable --config ca-common-name="Tutorial CA"
Wait for the charm to settle into an active/idle state, as shown by juju status.
Enable peer-to-peer encryption¶
To encrypt traffic between the cluster nodes, integrate Charmed Apache Cassandra with the certificate
provider over the peer-certificates endpoint:
juju integrate cassandra:peer-certificates self-signed-certificates
While certificates are being issued and distributed, units show waiting and maintenance statuses such
as waiting for internal TLS setup and waiting for peer tls rotation to complete. Once the process
completes, the units return to active/idle.
Enable client-to-node encryption¶
To encrypt traffic between clients and the cluster, integrate over the client-certificates
endpoint:
juju integrate cassandra:client-certificates self-signed-certificates
Again the units briefly show statuses such as waiting for TLS setup and waiting for client tls rotation to complete before returning to active/idle.
Reconnect with cqlsh over SSL¶
Now that client-to-node encryption is enabled, the cluster rejects plaintext connections. If you try to connect the way we did in the previous chapter, it fails:
charmed-cassandra.cqlsh "$CASSANDRA_IP" -u operator -p "<operator-password>"
Connection error: ('Unable to connect to any servers',
{'10.166.144.10:9042': ConnectionResetError(104, 'Connection reset by peer')})
This confirms that Apache Cassandra now requires a secure TLS connection.
Retrieve the root CA¶
cqlsh needs the root CA to verify the certificate the Cassandra nodes present during the TLS
handshake. Fetch it from the self-signed-certificates charm.
Since the charmed-cassandra snap is strictly confined, the CA must live in a location the snap can
read. Write it directly into the snap’s configuration directory:
juju run self-signed-certificates/0 get-ca-certificate --format json \
| jq -r '."self-signed-certificates/0".results."ca-certificate"' \
| sudo tee /var/snap/charmed-cassandra/current/etc/cassandra/ca.cert
Create a cqlshrc file¶
In the same directory, create a cqlshrc configuration file that tells cqlsh which credentials to
use and where to find the CA. Retrieve the operator password again if you need it:
juju show-secret --reveal cassandra-peers.cassandra.app --format json \
| jq -r '.[].content.Data."operator-password"'
Then create /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc with the following content,
substituting the password and the <CASSANDRA-IP> address captured earlier:
[authentication]
username = operator
password = <operator-password>
[connection]
hostname = <CASSANDRA-IP>
port = 9042
[ssl]
certfile = /var/snap/charmed-cassandra/current/etc/cassandra/ca.cert
validate = true
cqlsh refuses to use a cqlshrc that other users can read, so restrict its permissions to your
user only:
sudo chown $USER /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
sudo chmod 600 /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
Connect¶
Connect to the cluster over TLS by pointing cqlsh at the cqlshrc file and passing the --ssl
flag:
charmed-cassandra.cqlsh --ssl \
--cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
Output example
[cqlsh 6.1.0 | Cassandra 5.0.5 | CQL spec 3.4.7 | Native protocol v5]
Use HELP for help.
operator@cqlsh>
The connection now succeeds over an encrypted channel. The hostname set in cqlshrc is the default
target, but you can always connect to a specific node by passing its address as a positional
argument, which is handy once the cluster has more nodes:
charmed-cassandra.cqlsh --ssl "$CASSANDRA_IP" \
--cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
Leave the shell with exit. We will reuse this cqlshrc file for every cqlsh command in the rest
of the tutorial.
Note
If you ever want to go back to unencrypted connections, remove the relations with
juju remove-relation cassandra:client-certificates self-signed-certificates and
juju remove-relation cassandra:peer-certificates self-signed-certificates. This triggers a rolling
restart as the units switch back to plaintext communication.
What’s next?¶
The cluster is now secured. In the next section we will integrate a client application to generate a scoped user and a dedicated keyspace automatically through a relation.