ansible-collections / community.cassandra

Cassandra Ansible Collection
http://galaxy.ansible.com/community/cassandra
GNU General Public License v3.0
25 stars 17 forks source link

SSL - Server verifies client and client verifies server #280

Open jamesdehart opened 1 month ago

jamesdehart commented 1 month ago
SUMMARY

Currently the SSL mode only supports Client verifies server and I would love to add Server verifies client and client verifies server and these updates would also support Server verifies client as well.

ISSUE TYPE
COMPONENT NAME
ADDITIONAL INFORMATION

By adding support for SSLContext.load_cert_chain this would allow for Server verifies client and client verifies server connections to Cassandra. I have a requirement for two way auth when connecting to Cassandra.

When using the below code (With the values for my setup) I get

from cassandra.auth import PlainTextAuthProvider
from cassandra.cluster import Cluster, Session
from ssl import SSLContext, PROTOCOL_TLS, CERT_REQUIRED

ssl_context = SSLContext(PROTOCOL_TLS)
ssl_context.load_verify_locations('/path/to/rootca.crt')
ssl_context.verify_mode = CERT_REQUIRED
cluster = Cluster(['127.0.0.1'], 
                  ssl_context=ssl_context, 
                  auth_provider=PlainTextAuthProvider( username='cassandra',
                                                                                   password='cassandra'))
session = cluster.connect()

Output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib64/python3.7/site-packages/cassandra/cluster.py", line 1740, in connect
    self.control_connection.connect()
  File "/usr/local/lib64/python3.7/site-packages/cassandra/cluster.py", line 3543, in connect
    self._set_new_connection(self._reconnect_internal())
  File "/usr/local/lib64/python3.7/site-packages/cassandra/cluster.py", line 3588, in _reconnect_internal
    raise NoHostAvailable("Unable to connect to any servers", errors)
cassandra.cluster.NoHostAvailable: ('Unable to connect to any servers', {'127.0.0.1:9042': PermissionError(1, "Tried connecting to [('127.0.0.1', 9042)]. Last error: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1091)")})

from cassandra's system.log file

WARN  [epollEventLoopGroup-5-5] 2024-05-14 20:24:47,628 PreV5Handlers.java:261 
 - Unknown exception in client networking io.netty.handler.codec.DecoderException: 
 javax.net.ssl.SSLHandshakeException: error:100000c0:SSL 
 routines:OPENSSL_internal:PEER_DID_NOT_RETURN_A_CERTIFICATE

Once I add in the ssl_context.load_cert_chain

from cassandra.auth import PlainTextAuthProvider
from cassandra.cluster import Cluster, Session
from ssl import SSLContext, PROTOCOL_TLS, CERT_REQUIRED

ssl_context = SSLContext(PROTOCOL_TLS)
ssl_context.load_verify_locations('/path/to/rootca.crt')
ssl_context.load_cert_chain(
    certfile='/path/to/client.crt_signed',
    keyfile='/path/to/client.key')
ssl_context.verify_mode = CERT_REQUIRED
cluster = Cluster(['127.0.0.1'], 
                  ssl_context=ssl_context, 
                  auth_provider=PlainTextAuthProvider( username='cassandra', password='cassandra'))
session = cluster.connect()

Everything works. If there is anything missing please let me know. I don't mind adding an MR to add the above.

rhysmeister commented 1 month ago

Hello @jamesdehart,

Feel free to add this. The SSL stuff here was done in conjuction with a user's specific use-case and holes in the implementation are to be expected. Bonus points if you can add tests for this case.

Cheers,

Rhys

jamesdehart commented 1 month ago

I was able to copy and run the module locally and things worked well. I came across a bug that I'm going to post shortly about.

Thanks so much!