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.


No comments :

Post a Comment