Accessing secure DSE clusters with CQL native protocol
Apache Cassandra provides a number of features designed to help you secure your data. For deployments where Cassandra's internal authentication mechanism is not sufficient, DataStax Enterprise adds support for enterprise-grade authentication using Kerberos.
The DataStax Java driver for the CQL native protocol can be used with both DSE and Apache C* to access your data in a secure manner. If you're running a secure DSE cluster using Kerberos authentication and/or SSL for client to node encryption, you might find these examples useful.
DataStax Enterprise with Kerberos Authentication
In order to support Kerberos authentication, it was necessary to backport the authentication mechanism from version 2 of the CQL native protocol (CASSANDRA-5545) into the C* 1.2 which ships with DSE. For this reason, we also publish a DSE-specific version of the DataStax java driver for use with secure DSE clusters. This DSE extension to the driver is open source and available from the same Github repository as the mainstream version, where you can find it in the dse_3.1
branch. It's a drop in replacement for the mainstream driver, so to include it in your maven project just use these maven coordinates:
<dependency> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-driver-core</artifactId> <version>1.0.4-dse</version> </dependency>
(Incidentally, we employ a similar approach when it comes to the C# driver. I won't cover the details here, but to use the C# driver with Kerberos and DSE, check out this branch).
This DSE version of the java driver includes some additional authentication classes, amongst which is com.datastax.driver.core.sasl.DseAuthProvider
that handles the negotiation of secure connections with DSE using GSSAPI & SASL.
When using DseAuthProvider
, Kerberos options are set using a standard JAAS Login configuration file. The location of the file can be set using the standard Java mechanisms; by setting the java.security.auth.login.config
system property or by adding a login.config.url.n
entry in the java.security
properties file.
Below are a couple of examples of JAAS config files which demonstrate the most commonly used means of providing Kerberos credentials. Both contain an entry named DseClient
, which is the reference that DseAuthProvider
uses to retrieve the login configuration (and so this shouldn't be changed). Both examples also specify the JVM standard Krb5LoginModule
be used, for obvious reasons.
Obtaining User Credentials From a Keytab
To authenticate using a credentials from a keytab file, specify its location on disk. If your keytab contains more than one principal key, you should also specify which one to select.
DseClient { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true keyTab="/path/to/file.keytab" principal="user@MYDOMAIN.COM"; };
Obtaining Credentials From a Local Ticket Cache
To authenticate using credentials obtained from the local per-user Kerberos ticket cache, you just need a few changes to the config. You must run kinit
to obtain a ticket and populate the cache before connecting.
DseClient { com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true renewTGT=true; };
A full list of the options supported by Krb5LoginModule
can be found in its javadoc. You can read more about the details of what may be specified by the login file here and more on JAAS in general here.
Having provided a JAAS configuration, connecting to a secure DSE cluster is as simple as creating a DseAuthProvider
instance.
Cluster cluster = Cluster.builder() .addContactPoints("192.168.10.10", "192.168.10.11") .withAuthProvider(new DseAuthProvider()) .build(); Session session = cluster.connect();
Client to Node Encryption with SSL
As well as the option to encrypt all internode communication, Apache Cassandra also supports client to server encryption using SSL. To open an encrypted connection with the java-driver, whether using Apache Cassandra or DSE, simply use the withSSL()
method when constructing your Cluster instance
Cluster cluster = Cluster.builder() .addContactPoints("192.168.10.10", "192.168.10.11") .withSSL() .build();
By default this will instantiate connections using the system's default SSL context, which can be configured using system properties as documented here. The same end can also be achieved programatically, by constructing an SSLContext
and handing that to the Cluster builder
public static void main(String[] args) { . . . SSLContext context = getSSLContext(truststorePath, truststorePassword, keystorePath, keystorePassword); // Default cipher suites supported by C* String[] cipherSuites = { "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA" }; Cluster cluster = Cluster.builder() .addContactPoints("192.168.10.10", "192.168.10.11") .withSSL(new SSLOptions(context, cipherSuites)) .build(); Session session = cluster.connect(); } private static SSLContext getSSLContext(String truststorePath, String truststorePassword, String keystorePath, String keystorePassword) throws Exception { FileInputStream tsf = new FileInputStream(truststorePath); FileInputStream ksf = new FileInputStream(keystorePath); SSLContext ctx = SSLContext.getInstance("SSL"); KeyStore ts = KeyStore.getInstance("JKS"); ts.load(tsf, truststorePassword.toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ts); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(ksf, keystorePassword.toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, keystorePassword.toCharArray()); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); return ctx; }
That just about covers using the DataStax CQL driver for accessing secured clusters in Java. DSE also supports Kerberos authentication in its Solr HTTP API, using SPNEGO. Next time, I'll cover some examples using those APIs from the command line with cURL and from Java with SolrJ.