Monday, June 27, 2016

Securing client-node communication in Cassandra Part3


This is the last post about securing client-node communication in Cassandra and it will show how to force Cassandra to ask the client for a certificate signed by a trusted CA.
So not only Cassandra nodes must have the right credentials as I showed in the last post but also the client must be trusted.

Let's start creating the certificate and key pairs for the client:

We can now embody Cassandra administrator and we can use Openssl to generate the keys and the request:

#openssl req -newkey rsa:1024 -keyout clientkey.pem -keyform PEM -out clientreq.pem

This will ask a password (I answered “mysupersecretpassword”, change it accordingly in the C code below if you change it), and CN, OU, O, L,C, essentially the same stuff we passed in the command line to keytool when we generated the keys, see the previous posts.

The ouput of the commands will be two files, clientkey.pem which contains the keys and clientreq.pem which will contain the request to be sent to the CA.
Of course instead of clientkey.pem and clientreq.pem you can use names you like.

Now let's act the role of CA:
#openssl ca -config gen_ca_cert.conf -in clientreq.pem

The CA has to use  his password in order to use his private key to sign the certificate, so type the CA password when prompted. At the end of command the certificate is ready and stored in the certs directory, the location of the certs directory is specified in the gen_ca_cert.conf under the section [ {CAname} ], and specifically in $dir/certs where $dir=./ (see my previous posts Securing client-node communication in Cassandra Part1); now we can give the certificate to Cassandra administrator as client_cert.pem, of course you can use another name, but in the following I will use that one.

Now as Cassandra administrator we must create a truststore for the node:

#keytool -keystore {TRUSTSTORE}.jks -alias CARoot -importcert -file ~/cacert.pem -keypass {TRUSTSTOREPASSORD} -storepass {TRUSTSTOREPASSORD} -noprompt

Basically we are storing the CA certificate which will grant for the client certificate, so that that node could trust the client.
Copy the {TRUSTSTORE}.jks in a directory accessible from Cassandra, e.g. I copy it in the configuration directory of Cassandra that in my system is in /etc/cassandra/conf/
As I installed Cassandra as a service I give the ownership of the file to the service/user.

# chown cassandra /etc/cassandra/conf/{TRUSTSTORE}.jks


In order to use the keystore generated let's modify cassandra.yaml, always as Cassandra administrator, as the following:

client_encryption_options:
enabled: true
# If enabled and optional is set to true encrypted and unencrypted connections are handled.
optional: false
keystore: /etc/cassandra/conf/{KEYSTORENAME}.jks
keystore_password: {KEYSTOREPASSWORD}
truststore:{TRUSTSTORE}.jks
truststore_password: {TRUSTSTOREPASSORD}
require_client_auth: true
# Set trustore and truststore_password if require_client_auth is true
# More advanced defaults below:
protocol: TLS
algorithm: SunX509
store_type: JKS
cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]

As before instead of the words between brackets and brackets themselves you put the stuff that make sense for you.

Reboot Cassandra, on my system:

#service cassandra restart

If we try now to connect to Cassandra we are not trusted anymore:

# cqlsh --ssl
Connection error: ('Unable to connect to any servers', {'127.0.0.1': error(8, "Tried connecting to [('127.0.0.1', 9042)]. Last error: _ssl.c:492: EOF occurred in violation of protocol")})

We must therefore modify .~/.cassandra/cqlshrc as the following:

[connection]
hostname = 127.0.0.1
port = 9042
factory = cqlshlib.ssl.ssl_transport_factory

[ssl]
certfile = ~/.cassandra/cacert.pem
# Optional, true by default
validate = true
userkey = ~/ssl-cassandra/clientkey.pem
usercert = ~/ssl-cassandra/client_cert.pem

where clientkey.pem and client_cert.pem are respectively the client private key and the certificate signed by the CA.
Now set everything to be trusted by the node, we are using a certificate signed by a CA that is in its trusted list, in its truststore.
We can now try to connect to Cassandra node using cqlsh, of course we must give the correct password to ensure that the keys are ours, the password we gave when we generated the keys and the request at the beginning (in my case “mysupersecretpassword”).

#cqlsh --ssl
Enter PEM pass phrase:
Enter PEM pass phrase:
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.1.14 | CQL spec 3.2.1 | Native protocol v3]
Use HELP for help.
dle_relay@cqlsh>

we could remove the password from the file that stores the keys:

#openssl rsa -in clientkey.pem -out clientkey1.pem

and modify .~/.cassandra/cqlshrc to use the key without password:

[connection]
hostname = 127.0.0.1
port = 9042
factory = cqlshlib.ssl.ssl_transport_factory

[ssl]
certfile = ~/.cassandra/cacert.pem
# Optional, true by default
validate = true
userkey = ~/ssl-cassandra/clientkey1.pem
usercert = ~/ssl-cassandra/client_cert.pem


Now cqlsh will not prompt for password, but of course we don't like it and will immediately delete  clientkey1.pem and will revert .~/.cassandra/cqlshrc.


We played the Cassandra administrator and the CA role, now it is the time to play the programmer role.
In my previous post I showed how to use DataStax C/C++ driver to connect to a Cassandra DB where the node authenticate itself, now we have also the client that authenticate itself, so we need to modify the code in order to load the client certificate and client private.

We need, first of all, to add the function that loads the client certificate calling the cass_ssl_set_cert_n API:


int  
 load_clientCert_file (const char *file, CassSsl * ssl)  
 {  
  CassError rc;  
  char *cert;  
  long cert_size;  
  size_t bytes_read;  
  FILE *in = fopen (file, "rb");  
  if (in == NULL)  
   {  
    fprintf (stderr, "Error loading certificate file '%s'\n", file);  
    return 0;  
   }  
  fseek (in, 0, SEEK_END);  
  cert_size = ftell (in);  
  rewind (in);  
  cert = (char *) malloc (cert_size);  
  bytes_read = fread (cert, 1, cert_size, in);  
  fclose (in);  
  if (bytes_read == (size_t) cert_size)  
   {  
    rc = cass_ssl_set_cert_n (ssl, cert, cert_size);  
    if (rc != CASS_OK)  
      {  
       fprintf (stderr, "Error loading SSL certificate: %s\n",  
             cass_error_desc (rc));  
       free (cert);  
       return 0;  
      }  
   }  
  free (cert);  
  return 1;  
 }  


and a function that loads the client private key calling cass_ssl_set_private_key_n:


 int  
 load_privateKey_file (const char *file, CassSsl * ssl, const char *password)  
 {  
  CassError rc;  
  char *cert;  
  long cert_size;  
  size_t bytes_read;  
  FILE *in = fopen (file, "rb");  
  if (in == NULL)  
   {  
    fprintf (stderr, "Error loading certificate file '%s'\n", file);  
    return 0;  
   }  
  fseek (in, 0, SEEK_END);  
  cert_size = ftell (in);  
  rewind (in);  
  cert = (char *) malloc (cert_size);  
  bytes_read = fread (cert, 1, cert_size, in);  
  fclose (in);  
  int len = 0;  
  if (bytes_read == (size_t) cert_size)  
   {  
    rc = cass_ssl_set_private_key_n (ssl, cert, cert_size, password, len);  
    if (rc != CASS_OK)  
      {  
       fprintf (stderr, "Error loading SSL certificate: %s\n",  
             cass_error_desc (rc));  
       free (cert);  
       return 0;  
      }  
   }  
  free (cert);  
  return 1;  
 }  


we then eventually modify the main function:


 main ()  
 {  
  CassError rc = CASS_OK;  
  CassCluster *cluster = NULL;  
  CassSession *session = NULL;  
  CassSsl *ssl = NULL;  
  CassFuture *connect_future = NULL;  
  const char *username = "Cassandra";  
  const char *password = "Cassandra";  
  cluster = cass_cluster_new ();  
  cass_cluster_set_credentials (cluster, username, password);  
  session = cass_session_new ();  
  ssl = cass_ssl_new ();  
  cass_cluster_set_contact_points (cluster, "127.0.0.1");  
  cass_ssl_set_verify_flags (ssl,  
                   CASS_SSL_VERIFY_PEER_CERT |  
                   CASS_SSL_VERIFY_PEER_IDENTITY);  
  if (!add_ca_cert_file ("/home/ieio/.cassandra/cacert.pem", ssl))  
   {  
    fprintf (stderr, "Failed to load certificate\n");  
    cass_ssl_free (ssl);  
    cass_session_free (session);  
    cass_cluster_free (cluster);  
    return -1;;  
   }  
  if (!load_clientCert_file ("/home/ieo/.cassandra/client_cert.pem", ssl))  
   {  
    fprintf (stderr, "Failed to load client certificate\n");  
    cass_ssl_free (ssl);  
    cass_session_free (session);  
    cass_cluster_free (cluster);  
    return -1;  
   }  
  if (!load_privateKey_file  
    ("/home/ieio/.cassandra/clientkey.pem", ssl, "mysupersecretpassword"))  
   {  
    fprintf (stderr, "Failed to private key certificate\n");  
    cass_ssl_free (ssl);  
    cass_session_free (session);  
    cass_cluster_free (cluster);  
    return -1;  
   }  
  cass_cluster_set_ssl (cluster, ssl);  
  connect_future = cass_session_connect (session, cluster);  
  cass_future_wait (connect_future);  
  rc = cass_future_error_code (connect_future);  
  if (rc == CASS_OK)  
   {  
    printf ("Cassandra Connected\n");  
   }  
  else  
   {  
    printf ("Cassandra NOT Connected: %s\n", cass_error_desc (rc));  
    if (connect_future != NULL)  
      cass_future_free (connect_future);  
    return rc;  
   }  
  cass_ssl_free (ssl);  
  cass_session_free (session);  
  cass_future_free (connect_future);  
  cass_cluster_free (cluster);  
  return rc;  
 }  



To compile cut and paste the code in a file named Cassandra.c and if you use Linux give the following command:

#gcc Cassandra.c -l cassandra

the output is a.out and you can execute with typing:

#./a.out
and if everything is correct the result will be:

1465723034.040 [WARN] (src/connection.cpp:795:void cass::Connection::notify_error(const string&, cass::Connection::ConnectionError)): Host 127.0.0.1 received invalid protocol response Invalid or unsupported protocol version: 4
1465723034.041 [WARN] (src/control_connection.cpp:213:virtual void cass::ControlConnection::on_close(cass::Connection*)): Lost control connection on host 127.0.0.1
1465723034.041 [WARN] (src/control_connection.cpp:232:virtual void cass::ControlConnection::on_close(cass::Connection*)): Host 127.0.0.1 does not support protocol version 4. Trying protocol version 3...
Cassandra Connected

This concludes my series of posts on Securing client-node communication in Cassandra.

Sunday, June 12, 2016

Securing client-node communication in Cassandra Part2

In the previous post I showed how to create a CA, how to use the CA to sign certificate generated by keytool and how to use these certificates in Cassandra to protect node to client communication where the client was CQLSH.

In this new post I show how to use DataStax C/C++ driver instead of CQLSH.
DataStax C/C++ driver is a set of APIs in C/C++ to interface an application to Cassanda, it is available at https://github.com/datastax/cpp-driver and pretty well documented here http://docs.datastax.com/en/latest-cpp-driver/cpp-driver/whatsNew.html.
DataStax C/C++ driver is available also in binary format (http://downloads.datastax.com/cpp-driver/), depends on libuv, which is also available at the same place.

I based this post on the instructions I found here: https://docs.datastax.com/en/developer/cpp-driver/1.0/cpp-driver/reference/ssl.html but instead of using self signed certificates I used CA signed certificates.

So we need first of all a function to load the certificate of the CA using the cass_ssl_add_trusted_cert_n API:

 #include <cassandra.h>  
 #include <stdio.h>   
 #include <stdlib.h>  
 int add_ca_cert_file(const char* file, CassSsl* ssl) {  
  CassError rc;  
  char* cert;  
  long cert_size;  
  size_t bytes_read;  
  FILE *in = fopen(file, "rb");  
  if (in == NULL) {  
   fprintf(stderr, "Error loading certificate file '%s'\n", file);  
   return 0;  
  }  
  fseek(in, 0, SEEK_END);  
  cert_size = ftell(in);  
  rewind(in);  
  cert = (char*)malloc(cert_size);  
  bytes_read = fread(cert, 1, cert_size, in);  
  fclose(in);  
  if (bytes_read == (size_t) cert_size) {  
   rc = cass_ssl_add_trusted_cert_n(ssl, cert, cert_size);  
   if (rc != CASS_OK) {  
    fprintf(stderr, "Error loading SSL certificate: %s\n", cass_error_desc(rc));  
    free(cert);  
    return 0;  
   }  
  }  
  free(cert);  
  return 1;  
 }  

and then we can use it in our main function:


 main ()  
 {  
  CassError rc = CASS_OK;  
  CassCluster *cluster=NULL;  
  CassSession *session =NULL;  
  CassSsl *ssl=NULL;  
  CassFuture *connect_future = NULL;  
  const char *username = "Cassandra";  
  const char *password = "Cassandra";  
  cluster = cass_cluster_new ();  
  cass_cluster_set_credentials (cluster, username, password);  
  session = cass_session_new ();  
  ssl = cass_ssl_new ();  
  cass_cluster_set_contact_points (cluster, "127.0.0.1");  
  cass_ssl_set_verify_flags (ssl,  
                   CASS_SSL_VERIFY_PEER_CERT |  
                   CASS_SSL_VERIFY_PEER_IDENTITY);  
  if (!add_ca_cert_file ("/home/ieio/.cassandra/cacert.pem", ssl))  
   {  
    fprintf (stderr,  
          "Failed to load certificate\n");  
      cass_ssl_free (ssl);  
      cass_session_free(session);  
      cass_cluster_free(cluster);  
      return -1;  
   }  
  cass_cluster_set_ssl (cluster, ssl);  
  connect_future = cass_session_connect (session, cluster);  
  cass_future_wait (connect_future);  
  rc = cass_future_error_code (connect_future);  
  if (rc == CASS_OK)  
   {  
    printf ("Cassandra Connected\n");  
   }  
  else  
   {  
    printf ("Cassandra NOT Connected: %s\n", cass_error_desc (rc));  
    if (connect_future != NULL)  
      cass_future_free (connect_future);  
    return rc;  
   }  
  cass_ssl_free (ssl);  
  cass_session_free(session);  
  cass_future_free (connect_future);  
  cass_cluster_free(cluster);  
  return 0;  
 }   

as you can see add_ca_cert_file is loading the same certificate we user to make CQLSH works, do u remember? ~/.cassandra/cacert.pem
To compile cut and paste the code in a file named Cassandra.c and if you use Linux give the following command:

#gcc Cassandra.c -l cassandra

the output is a.out and you can execute with typing:

#./a.out
and if everything is correct the result will be:

1465492279.189 [WARN] (src/connection.cpp:795:void cass::Connection::notify_error(const string&, cass::Connection::ConnectionError)): Host 127.0.0.1 received invalid protocol response Invalid or unsupported protocol version: 4
1465492279.189 [WARN] (src/control_connection.cpp:213:virtual void cass::ControlConnection::on_close(cass::Connection*)): Lost control connection on host 127.0.0.1
1465492279.189 [WARN] (src/control_connection.cpp:232:virtual void cass::ControlConnection::on_close(cass::Connection*)): Host 127.0.0.1 does not support protocol version 4. Trying protocol version 3...
Cassandra Connected

Warnings are due to the fact I am still using Cassandra 2.1 which does not support protocol 4.
In the next post as promised in the previous one I will show how to force Cassandra to ask us for a signed certificate in order to establish the secure (TLS) communication and how to use CQLSH and DataStax C/C++ driver in this case.


Sunday, May 29, 2016

Securing client-node communication in Cassandra Part1


Recently I came across this nosql database stuff, I did some researches and I landed in Cassandra world.
You can find information about Cassandra here: http://cassandra.apache.org/.
One of the issues I encountered working with Cassandra was securing the database, there is an excellent post (http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html) about  how to set up node to node encryption using Certificates and CA, but I didn't find a good tutorial for client to node encryption.
In this post I will do my best to show how to setup a secure communication in Cassandra between a client and a node, but first of all let's see how easy it is to sniff a client to node communication.
In the following pictures I sniffed with wireshark cqlsh asking Cassandra cql version (SELECT cql_version FROM system.local;)


and Cassandra answering (3.2.1)




I am too much paranoiac to let it be, I want an encrypted version, otherwise I won't have good dreams.

So first first of all let's create a CA that will sign SSL certificates, then we will make ourselves  sure that Cassandra is using a certificate signed by our "trusted" CA in order to set up a secure (encrypted) connection.

I use Linux so all the commands I will show in the following will work on a Linux system.
For the sake of my mind I prefer to keep separate the user that will act as CA from the user that will manage Cassandra, even if those users are always me.
Create the user that will act as a CA, he will generate the pair of keys, he will publish his public certificate and he will sign the request from the other user:

# useradd user-ca
# passwd user-ca

Create two directory, one to store the private key and one for the certificates:

#mkdir certs private

Protect the private directory so that only the CA user can read, write and enter in it:

#chmod 700 private

Create the serial file that will track the serial number of the certificates and the index.txt file that act as a database of signed certificates

#echo '01' > serial
#touch index.txt

Create a gen_ca_cert.conf like this:

[ ca ]
default_ca ={CAname}

[ {CAname} ]
dir =./
certificate = $dir/cacert.pem
database = $dir/index.txt
serial = $dir/serial
new_certs_dir = $dir/certs
private_key = $dir/private/privkey.pem

default_days = 365
default_md = md5
policy = CAuser_policy

[ CAuser_policy ]
stateOrProvinceName = optional
countryName = supplied
organizationName = supplied
organizationalUnitName =optional


commonName = supplied

[ req ]
distinguished_name = req_distinguished_name
prompt = no
default_bits = 2048
default_keyfile =./private/privkey.pem

[ req_distinguished_name ]
C = {COUNTRY}
ST = {PROVINCE}
L = {CITY}
O = {ORGANITATION}
OU = {ORGANITATION UNIT}
CN = {COMMON NAME}
emailAddress = {EMAIL ADDRESS}

where instead of the words between brackets and brackets themselves put the stuff that make sense for you.
Now it is possible to generate the CA private key and CA certificate:

#openssl req -config gen_ca_cert.conf -new -x509 -out cacert.pem

where
  • req: it is used to emit the root self signed certificate
  • -config specifies to user the conf file created before
  • -new specifies to generate a new certificate request
  • -x509 specifies the certificate format
  • -out specifies the name of the file that will be generated
A password will be required to protect the private key and it will be prompted to be inserted.

Now private key and certificate are generated, the key is stored in directory named private and the certificate in userCA home:

#ls -l
total 20
-rw-rw-r--. 1 CAuser CAuser 1314 May 25 14:24 cacert.pem
drwxrwxr-x. 2 CAuser CAuser 4096 May 25 11:52 certs
-rw-rw-r--. 1 CAuser CAuser 656 May 25 14:39 gen_ca_cert.conf
-rw-rw-r--. 1 CAuser CAuser 0 May 25 11:58 index.txt
drwx------. 2 CAuser CAuser 4096 May 25 14:23 private
-rw-rw-r--. 1 CAuser CAuser 3 May 25 11:58 serial
#ls -l private/
total 4
-rw-rw-r--. 1 CAuser CAuser 1834 May 25 14:24 privkey.pem

Now we can create the certificate and private key for each node, login as Cassandra administrator and issue the following command:

#keytool -genkeypair -keyalg RSA -alias client -keystore {KEYSTORENAME}.jks -storepass {PASSWORD} -keypass {PASSWORD} -validity 365 -keysize 2048 -dname "CN={IPADDRESS}, OU={ORGANIZATION UNIT}, O={ORGANIZATION}, L={LOCATION}, S={STATE},C={COUNTRY}"

where instead of the words between brackets and brackets themselves you put the stuff that make sense for you.
I use keytool instead of openssl for two reasons, first I found tutorials using it, and I copy from them, second it already generates the keystore in the format  Cassandra uses.

Keytool can be found in the bin directory of JDK distribution, I use jdk1.8.0_77
Now that {KEYSTORENAME}.jks is generated the certificate request can be generated:

#keytool -keystore {KEYSTORENAME}.jks -alias client -certreq -file {CERT-REQ} -keypass {KEYSTOREPASSWORD} -storepass {KEYSTOREPASSWORD}

this will create {CERT-REQ} that can be passed to the CA so that it can sign it.

We are now CAuser:

#openssl ca -config gen_ca_cert.conf -in {CERT-REQ}

Now the signed certificate is ready and stored in the certs directory:

#ls -la certs/
drwxrwxr-x. 2 CAuser CAuser 4096 May 25 17:59 .
drwx------. 13 CAuser CAuser 4096 May 26 09:33 ..
-rw-rw-r--. 1 CAuser CAuser 3963 May 25 17:59 01.pem

Give 01.pem back to Cassandra admin.

Let's change hat again, we are Cassandra admin.
The CA certificate and the signed certificate of the node should now be stored in the {KEYSTORENAME}.jks

#keytool -keystore {KEYSTORENAME}.jks -alias CARoot -import -file cacert.pem -noprompt -keypass {PASSWORD} -storepass {PASSWORD}

for the CA certificate

#keytool -keystore {KEYSTORENAME}.jks -alias client -import -file 01.pem -keypass {KEYSTOREPASSWORD} -storepass {KEYSTOREPASSWORD}

and for the signed certficate.

Copy the {KEYSTORENAME}.jks in a directory accessible from Cassandra, e.g. I copy it in the configuration directory of Cassandra that in my system is in /etc/cassandra/conf/ and as I installed Cassandra as a service I give the ownership of the file to the service/user

Login as root, or use sudo and type:

#cp {KEYSTORENAME}.jks /etc/cassandra/conf/{KEYSTORENAME}.jks
#chown cassandra:cassandra
#exit

Now cassandra.yaml has to be modified as following go to the  client_encryption_options section and change it as in the following:

client_encryption_options:
enabled: true
# If enabled and optional is set to true encrypted and unencrypted connections are handled.
optional: false
keystore: /etc/cassandra/conf/{KEYSTORENAME}.jks
keystore_password: {KEYSTOREPASSWORD}
#truststore:truststore.jks
#truststore_password: cassandra
require_client_auth: false
# Set trustore and truststore_password if require_client_auth is true
# More advanced defaults below:
protocol: TLS
algorithm: SunX509
store_type: JKS
cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]

Restart Cassandra.

Now you can try to connect to Cassandra:

#cqlsh –ssl
Validation is enabled; SSL transport factory requires a valid certfile to be specified. Please provide path to the certfile in [ssl] section as 'certfile' option in /home/ieio/.cassandra/cqlshrc (or use [certfiles] section) or set SSL_CERTFILE environment variable.

Now cqlsh  (the client) doesn't trust Cassandra node anymore, it needs the CA certificate in order to be sure that Cassandra is using a certificate signed by the CA.
Modify or create ~/.cassandra/cqlshrc as in the following:

[connection]
hostname = 127.0.0.1
port = 9042
factory = cqlshlib.ssl.ssl_transport_factory

[ssl]
certfile = ~/.cassandra/cacert.pem
# Optional, true by default
validate = true

and of course, copy the CA certificate in the directory you specify in the certfile and give right permission; as root if needed.
Now cqlsh can trust Cassandra and connect to it:

#cqlsh --ssl
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.1.14 | CQL spec 3.2.1 | Native protocol v3]
Use HELP for help.
>

If you trying to sniff the traffic with wireshark you cannot easily understand what is going on... phew now I can sleep.
But we want to always to  move further with security so let's force Cassandra to ask for a username and password each time we want to connect to it, in order to do that we just have to modify cassandra.yaml as in the following:

authenticator: PasswordAuthenticator

Restart Cassandra. If we now try to connect to it we will receive an error:

#cqlsh --ssl
Connection error: ('Unable to connect to any servers', {'127.0.0.1': AuthenticationFailed('Remote end requires authentication.',)})

So we must now add a username to the cqlsh command and a promt asking for a password will appear (default password is cassandra):

#cqlsh --ssl -u cassandra
Password:
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.1.14 | CQL spec 3.2.1 | Native protocol v3]
Use HELP for help.
>


Now we have a secure connection and the client can trust the node if we want to move even further we can force Cassandra to ask us for a signed certificate so that Cassandra can trust the client, but this will be the subject of one of the next posts.