Search code examples
dockerssldocker-composecassandradatastax-csharp-driver

Cannot connect to Cassandra in Docker with SSL enabled, getting "Database handshake error: RemoteCertificateNameMismatch"


Help! I am Running Cassandra in Docker.

I have the hostname set up as "mycassandra".

I have issued a certificate to CN="mycassandra", added a SAN DNS="mycassandra" and even added SAN IP "172.19.0.7" as precautionary measure then created the keystore.

I have set the cluster name to "mycassandra" in cassandra config.

The C# code looks like this (simplified):

await Cluster.Builder()
.AddContactPoints("mycassandra")
.WithSSL(new SSLOptions().SetRemoteCertValidationCallback(
                    (sender, certificate, chain, errors) =>
                    {
                        var hostEntry = Dns.GetHostEntry(_serviceConfig.DatabaseHostname);
                        log.LogDebug("Dns.GetHostEntry: " + hostEntry.HostName + " (Cert Subject:" + certificate.Subject + ")");

                        if (errors == SslPolicyErrors.None)
                            return true;

                        throw new Exception($"Hand no shakey error: {errors}");
                    }

                ))
.Build().ConnectAsync("mykeyspace");

The one error that appears is :

Dns.GetHostEntry: mycassandra (Cert Subject:CN=mycassandra)

Could not establish connection with cassandra. Message: All hosts tried for query failed (tried 172.19.0.7:9042: Exception 'Database handshake error: RemoteCertificateNameMismatch')
---> Cassandra.NoHostAvailableException: All hosts tried for query failed (tried 172.19.0.7:9042: Exception 'Database handshake error: RemoteCertificateNameMismatch')
at Cassandra.Connections.Control.ControlConnection.Connect(Boolean isInitializing)
at Cassandra.Connections.Control.ControlConnection.InitAsync()
at Cassandra.Tasks.TaskHelper.WaitToCompleteAsync(Task task, Int32 timeout)
at Cassandra.Cluster.Init()
at Cassandra.Cluster.ConnectAsync(String keyspace)

If I skip on RemoteCertificateNameMismatch, everything works fine.

Update:

I inspected the "sender" object param for SetRemoteCertValidationCallback(). It is of SSLStream type, the sender.targethostname shows "mycassandra.mydockernetwork" as the value hence not being able to validate against the cert issue.

My docker-compose yaml file:

version: '3.5'
services:
  mycassandra:
    container_name: mycassandra
    image: cassandra:4.0
    networks:
        mydockernetwork:

networks:
    mydockernetwork:
        name: my_docker_network
        driver: bridge

Solution

  • The Cassandra C# driver (which I'll refer to as "the driver") uses .Net's SSL API to connect to encrypted Cassandra nodes. The driver performs a reverse DNS lookup on the IP address to get the node's hostname. This is problematic for Cassandra running in Docker because of its internal networking.

    The .Net SSL API returned RemoteCertificateNameMismatch because the the HostName in the certificate did not match the container's hostname returned by the reverse DNS lookup.

    Assuming this is for a development environment, you can either (a) temporarily disable encryption on the Cassandra node, or (b) implement a custom certificate validation in your code (c) using SSLOptions.SetHostNameResolver() or (d) your own RemoteCertificateValidationCallback.

    For details, see the C# driver TLS/SSL page. Cheers!