1

I am using the Spring Data Cassandra project v1.3.0 am unable to configure SSL for my Cassandra cluster (v2.0.17). The Sprint Data Cassandra documentation says it supports Cassandra 2.X using the DataStax Java Driver (2.0.X) so there shouldn't be an issue there. Here is my Java cassandra configuration that initializes the cassandra cluster bean:

@Autowired
private Environment env;

@Bean
public CassandraClusterFactoryBean cluster() {
    SSLContext context = null;

    try {
        context = getSSLContext(
                env.getProperty("cassandra.connection.ssl.trustStorePath"),
                env.getProperty("cassandra.connection.ssl.trustStorePassword"),
                env.getProperty("cassandra.connection.ssl.keyStorePath"),
                env.getProperty("cassandra.connection.ssl.keyStorePassword"));
    } catch (Exception ex) {
        log.warn("Error setting SSL context for Cassandra.");
    }

    // Default cipher suites supported by C*
    String[] cipherSuites = { "TLS_RSA_WITH_AES_128_CBC_SHA",
            "TLS_RSA_WITH_AES_256_CBC_SHA" };

    CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
    cluster.setContactPoints(env.getProperty("cassandra.contactpoints"));
    cluster.setPort(Integer.parseInt(env.getProperty("cassandra.port")));
    cluster.setSslOptions(new SSLOptions(context, cipherSuites));
    cluster.setSslEnabled(true);
    return cluster;
}

@Bean
public CassandraMappingContext mappingContext() {
    return new BasicCassandraMappingContext();
}

@Bean
public CassandraConverter converter() {
    return new MappingCassandraConverter(mappingContext());
}

@Bean
public CassandraSessionFactoryBean session() throws Exception {

    CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
    session.setCluster(cluster().getObject());
    session.setKeyspaceName(env.getProperty("cassandra.keyspace"));
    session.setConverter(converter());
    session.setSchemaAction(SchemaAction.NONE);

    return session;
}

@Bean
public CassandraOperations cassandraTemplate() throws Exception {
    return new CassandraTemplate(session().getObject());
}

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;
}

I have verified the environment properties to set the SSL context are being populated properly and are the same keystore and truststore being used in the cassandra configuration file. Below is my cassandra configuration regarding enabling client to node encryption:

server_encryption_options:
    internode_encryption: all
    keystore: /usr/share/ssl/cassandra_client.jks
    keystore_password: cassandra
    truststore: /usr/share/ssl/cassandra_client_trust.jks
    truststore_password: cassandra
    # 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]
    # require_client_auth: true

# enable or disable client/server encryption.
client_encryption_options:
    enabled: true
    keystore: /usr/share/ssl/cassandra_client.jks
    keystore_password: cassandra
    require_client_auth: true
    # Set trustore and truststore_password if require_client_auth is true
    truststore: /usr/share/ssl/cassandra_client_trust.jks
    truststore_password: cassandra
    # 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]

When launching my client application I get the following error when cassandra cluster is being initialized:

17:02:39,330 WARN  [org.springframework.web.context.support.XmlWebApplicationContext] (ServerService Thread Pool -- 58) Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cassandraServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.data.cassandra.core.CassandraOperations com.cloudistics.cldtx.mwc.service.CassandraServiceImpl.cassandraOperations; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cassandraTemplate' defined in com.cloudistics.cldtx.mwc.conn.CassandraConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.cassandra.core.CassandraOperations]: Factory method 'cassandraTemplate' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'session' defined in com.cloudistics.cldtx.mwc.conn.CassandraConfig: Invocation of init method failed; nested exception is com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: /127.0.0.1:9042 (com.datastax.driver.core.ConnectionException: [/127.0.0.1:9042] Unexpected error during transport initialization (com.datastax.driver.core.OperationTimedOutException: [/127.0.0.1:9042] Operation timed out)))17:02:39,330 WARN  [org.springframework.web.context.support.XmlWebApplicationContext] (ServerService Thread Pool -- 58) Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cassandraServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.data.cassandra.core.CassandraOperations com.cloudistics.cldtx.mwc.service.CassandraServiceImpl.cassandraOperations; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cassandraTemplate' defined in com.cloudistics.cldtx.mwc.conn.CassandraConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.cassandra.core.CassandraOperations]: Factory method 'cassandraTemplate' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'session' defined in com.cloudistics.cldtx.mwc.conn.CassandraConfig: Invocation of init method failed; nested exception is com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: /127.0.0.1:9042 (com.datastax.driver.core.ConnectionException: [/127.0.0.1:9042] Unexpected error during transport initialization (com.datastax.driver.core.OperationTimedOutException: [/127.0.0.1:9042] Operation timed out)))

If anybody has any insight into this it would be greatly appreciated. I followed these instructions on Datastax to prepare the server certificates and enable client-to-node encryption.

1
  • was there any solution to this problem ? Commented Nov 22, 2018 at 12:41

1 Answer 1

0

I could able to do this with following code. Hope this helps.

cassandra.properties

# KeyStore Path
cassandra.cassks=classpath:cass.keystore.p12
# KeyStore Password
cassandra.casskspass=defkeypass
# KeyStore Type
cassandra.casskstype=pkcs12

# TrustStore Path
cassandra.cassts=classpath:cass.truststore.p12
# TrustStore Password
cassandra.casstspass=deftrustpass
# TrustStore Type
cassandra.casststype=pkcs12

CassandraProperties.java

@Configuration
@ConfigurationProperties("cassandra")
@PropertySource(value = "${classpath:conf/cassandra.properties}")
@Validated
@Data
public class CassandraProperties {

    @NotNull
    private Boolean ssl;

    @NotNull
    private String sslver;

    private Resource cassks;
    private String casskspass;
    private String casskstype;

    private Resource cassts;
    private String casstspass;
    private String casststype;
}

CassandraConfig.java

public class CassandraConfig extends AbstractCassandraConfiguration {
    @Autowired
    private CassandraProperties cassandraProp;

    @Bean
    public CassandraClusterFactoryBean cluster() {
        CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
        cluster.setContactPoints(cassandraProp.getContactpoints());
        cluster.setPort(cassandraProp.getPort());

        if (true == cassandraProp.isSSEnabled()) {

            File KeyStoreFile = null;
            File TrustStoreFile = null;
            InputStream keyStoreIS = null;
            InputStream tustStoreIS = null;
            KeyStore keyStore = null;
            KeyStore trustStore = null;
            TrustManagerFactory tmf = null;
            KeyManagerFactory kmf = null;
            SSLContext sslContext = null;
            RemoteEndpointAwareJdkSSLOptions sslOptions = null;

            try {
                KeyStoreFile = cassandraProp.getCassks().getFile();

                keyStoreIS = new FileInputStream(KeyStoreFile);
                keyStore = KeyStore.getInstance(cassandraProp.getCasskstype());
                keyStore.load(keyStoreIS, cassandraProp.getCasskspass().toCharArray());

                TrustStoreFile = cassandraProp.getCassts().getFile();
                tustStoreIS = new FileInputStream(TrustStoreFile);
                trustStore = KeyStore.getInstance(cassandraProp.getCasststype());
                trustStore.load(tustStoreIS, cassandraProp.getCasstspass().toCharArray());

                tmf = TrustManagerFactory.getInstance("SunX509");
                tmf.init(trustStore);

                kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(keyStore, cassandraProp.getCasskspass().toCharArray());

                sslContext = SSLContext.getInstance(cassandraProp.getSslver());
                sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

                sslOptions = new RemoteEndpointAwareJdkSSLOptions.Builder().withSSLContext(sslContext).build();

            } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException
                    | KeyManagementException | UnrecoverableKeyException e) {
                e.printStackTrace();
            }

            cluster.setSslEnabled(true);
            cluster.setSslOptions(sslOptions);
        }
        return cluster;
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.