NoHostAvailableException :: Ошибка подключения Java к SSL-кластеру Cassandra

Я пытаюсь подключиться к трехузловому кластеру Cassandra из клиентской программы Java с кластером Cassandra, настроенным с включенным шифрованием от клиента к узлу. Я развернул три самоподписанных сертификата на всех трех узлах и импортировал общедоступные сертификаты на каждый из других узлов в соответствии с документом Шифрование между клиентом и узлом. Когда я запускаю клиентскую программу, я получаю следующее исключение.

 Exception in thread "main" com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: clm-pun-swpry4/10.133.181.157:9042 (com.datastax.driver.core.exceptions.TransportException: [clm-pun-swpry4/10.133.181.157:9042] Channel has been closed), clm-pun-swpryf/10.133.181.156:9042 (com.datastax.driver.core.exceptions.TransportException: [clm-pun-swpryf/10.133.181.156:9042] Channel has been closed), clm-pun-sqbgda/10.133.172.70:9042 (com.datastax.driver.core.exceptions.TransportException: [clm-pun-sqbgda/10.133.172.70:9042] Channel has been closed))
    at com.datastax.driver.core.ControlConnection.reconnectInternal(ControlConnection.java:233)
    at com.datastax.driver.core.ControlConnection.connect(ControlConnection.java:79)
    at com.datastax.driver.core.Cluster$Manager.init(Cluster.java:1483)
    at com.datastax.driver.core.Cluster.init(Cluster.java:159)
    at com.datastax.driver.core.SessionManager.initAsync(SessionManager.java:78)
    at com.datastax.driver.core.SessionManager.executeAsync(SessionManager.java:139)
    at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:68)
    at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:43)
    at clm.bmc.saas.incubator.ClientToNodeExample.main(ClientToNodeExample.java:28)

Моя конфигурация Cassandra в cassandra.yaml (индивидуальный самоподписанный сертификат для каждого из 3 узлов):

client_encryption_options:
    enabled: true
    # If enabled and optional is set to true encrypted and unencrypted connections are handled.
    optional: false
    keystore: /opt/secure/keystore.clm-pun-swpry4
    keystore_password: changeit
    # require_client_auth: false
    # Set trustore and truststore_password if require_client_auth is true
    # truststore: conf/.truststore
    # truststore_password: cassandra
    # More advanced defaults below:
    protocol: TLSv1.2
    algorithm: SunX509
    store_type: JKS
    cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA]

Моя программа на Java:


public class ClientToNodeExample {
    private static final Logger LOGGER = LoggerFactory.getLogger(ClientToNodeExample.class);

    public static void main(String[] args) {
        ClientToNodeExample example = new ClientToNodeExample();
        Session session = example.getCluster("C:\\install\\ssl\\cassandraCluster.ks", "changeit",
                new String[]{"clm-pun-sqbgda", "clm-pun-swpryf", "clm-pun-swpry4"}, 9042).newSession();
        ResultSet results = session.execute("SELECT * FROM entity_space.mo;");
        LOGGER.info("NumberOfRows:" + results.all().size());
        session.close();
    }

    private Cluster getCluster(String trustStoreLocation, String trustStorePassword, String[] host, int port) {
        Cluster cluster;
        SSLContext sslcontext = null;
        try {
            InputStream is = ClientToNodeExample.class.getResourceAsStream(trustStoreLocation);
            KeyStore keystore = KeyStore.getInstance("jks");
            char[] pwd = trustStorePassword.toCharArray();
            keystore.load(is, pwd);
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(keystore);
            TrustManager[] tm = tmf.getTrustManagers();
            sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init(null, tm, null);
        } catch (Exception e) {
            LOGGER.error("ERROR", e);
        }
        JdkSSLOptions sslOptions = JdkSSLOptions.builder().withSSLContext(sslcontext).build();
        cluster = Cluster.builder().addContactPoints(host).withPort(port).withSSL(sslOptions).build();
        return cluster;
    }
}

Однако, если я попытаюсь проверить сертификат от каждого узла с помощью следующей команды keytool, я получу сертификат:

keytool -printcert -sslserver clm-pun-sqbgda:9042 -rfc

Может ли кто-нибудь помочь, где я ошибаюсь?

Cassandra version:3.11.0
cassandra-driver-core : 3.1.4

Какие ошибки есть в вашем файле system.log?

Horia 23.07.2018 11:42

Сначала я бы попытался подключиться через cqlsh --ssl (вам нужно сделать несколько дополнительных шагов). Если это нормально, значит, настройка верна, и я бы удалил sslOptions и предоставил -Djavax.net.ssl.trustStore, -Djavax.net.ssl.trustStorePassword и -Djavax.net.debug = ssl. Если это тоже работает, значит проблема в вашем методе getCluster. Я предполагаю, что ваше хранилище ключей (cassandraCluster.ks) загружено неправильно. Я успешно запустил код как проект maven с хранилищем ключей в папке ресурсов и загруженным с помощью cluster = getCluster ("/ client-truststore.jks", "changeit", new String [] {"127.0.0.1"}, 9042) ;

Horia 23.07.2018 13:56

@Horia, спасибо, что указали. это был неверный путь к доверенному магазину. После исправления работает нормально. Я настроил все предложенные способы, cqlsh, truststore с системными переменными и, наконец, с загруженным sslcontext: все работает хорошо. Спасибо!

gbhadhar 24.07.2018 07:50

Хорошо, рад, что смог помочь. В качестве ответа поставлю свой комментарий.

Horia 24.07.2018 08:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
1 395
1

Ответы 1

Сначала я бы попытался подключиться через cqlsh --ssl (вам нужно сделать несколько дополнительных шагов):

  • конвертировать сертификат сервера в формат PKCS12
  • конвертировать PKCS12 в PEM
  • измените файл cqlshrc, чтобы использовать сертификат PEM.

Если это нормально, значит, настройка верна, и я бы удалил sslOptions и предоставил

-Djavax.net.ssl.trustStore
-Djavax.net.ssl.trustStorePassword 
-Djavax.net.debug=ssl.

Если это тоже работает, значит проблема в вашем методе getCluster.

Я предполагаю, что ваше хранилище ключей (cassandraCluster.ks) загружено неправильно.

Я успешно выполнил ваш код как проект maven с хранилищем ключей в папке ресурсов и загрузил его с помощью

cluster = getCluster("/client-truststore.jks", "changeit", new String[]{"127.0.0.1"}, 9042);

Другие вопросы по теме