Hello!
Thank you so much for taking time off for this comprehensive demonstration and detailed instruction. I am so amazed by how everything is well packaged. I really appreciate it!
I am sorry for the late reply. I took a while to study and understand the many advanced settings in this demonstration. Especially with the use of x509 certificate based authentication (EXTERNAL).
I have again performed extensive testing on different cases to explore the behavior of RabbitMQ Trust Store in this case. In my use case, using just CA to whitelist can be quite challenging and less robust as most likely, all the clients will be signed with the same CA.
Here are my assumption/conditions:
rmq-0 set of certificates are unrelated to rmq-1 set of certificates. ca_certs.pem in the certs directory is the combination of rmq-0 and rmq-1 CA certificates.
The rabbitmq server is using rmq-0 server certificate
In short, this is what I did:
Created a user with CN=rmq-0 so that I can test a client that is signed by rmq-0 CA. (I did not do that initially, so I was not able to connect with rmq-0 client, but this is not due to the TrustStore)
Place/remove rmq-0 and rmq-1 client certificates into the trust store directory
Using Pika client to connect to the rabbitMQ server with rmq-0 and rmq-1 client certificate respectively.
An interesting behavior I found is that, with just the client certificate, I am able to whitelist / block access to the client with rmq-1 certificate with just the client certificate inside/removed from the trust store directory, provided that the rabbitMQ server is using rmq-0 certificate (issued by different CA).
White Listing:
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:31.714458+00:00 [debug] <0.754.0> Trust store listed certificates: [{{"client_rmq-0_certificate.pem",1656051228,
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:31.714458+00:00 [debug] <0.754.0> 62543353},
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:31.714458+00:00 [debug] <0.754.0> [{name,"client_rmq-0_certificate.pem"}]},
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:31.714458+00:00 [debug] <0.754.0> {{"client_rmq-1_certificate.pem",1656051228,
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:31.714458+00:00 [debug] <0.754.0> 102077184},
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:31.714458+00:00 [debug] <0.754.0> [{name,"client_rmq-1_certificate.pem"}]}]
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:31.714788+00:00 [debug] <0.754.0> Updating 2 fetched trust store certificates
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:57.257337+00:00 [info] <0.1089.0> accepting AMQP connection <0.1089.0> (172.26.0.1:55042 -> 172.26.0.2:5671)
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:57.261471+00:00 [debug] <0.1089.0> auth mechanism TLS extracted username 'O=client,CN=rmq-1' from peer certificate
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:57.261613+00:00 [debug] <0.1089.0> Raw client connection hostname during authN phase: {0,0,0,0,0,65535,44058,2}
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:57.261738+00:00 [debug] <0.1089.0> Resolved client hostname during authN phase: ::ffff:172.26.0.2
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:57.261798+00:00 [debug] <0.1089.0> User 'O=client,CN=rmq-1' authenticated successfully by backend rabbit_auth_backend_internal
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:20:57.268351+00:00 [info] <0.1089.0> connection <0.1089.0> (172.26.0.1:55042 -> 172.26.0.2:5671): user 'O=client,CN=rmq-1' authenticated and granted access to vhost '/'
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:33:28.396335+00:00 [debug] <0.754.0> Trust store listed certificates: []
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:33:28.396507+00:00 [debug] <0.754.0> Updating 0 fetched trust store certificates
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:33:46.151157+00:00 [notice] <0.993.0> TLS server: In state wait_cert at ssl_handshake.erl:2084 generated SERVER ALERT: Fatal - Handshake Failure
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:33:46.151157+00:00 [notice] <0.993.0> - "CA not known AND certificate not whitelisted"
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:33:46.177202+00:00 [notice] <0.999.0> TLS server: In state wait_cert at ssl_handshake.erl:2084 generated SERVER ALERT: Fatal - Handshake Failure
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:33:46.177202+00:00 [notice] <0.999.0> - "CA not known AND certificate not whitelisted"However, if the client also uses rmq-0 client certificate, it will by-pass the the trust store and connect to the server, even with an empty trust store.
Bypassed:
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:28.363402+00:00 [debug] <0.754.0> Trust store listed certificates: []
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:28.363484+00:00 [debug] <0.754.0> Updating 0 fetched trust store certificates
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:50.216529+00:00 [info] <0.898.0> accepting AMQP connection <0.898.0> (172.27.0.1:55120 -> 172.27.0.2:5671)
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:50.221797+00:00 [debug] <0.898.0> auth mechanism TLS extracted username 'O=client,CN=rmq-0' from peer certificate
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:50.221896+00:00 [debug] <0.898.0> Raw client connection hostname during authN phase: {0,0,0,0,0,65535,44059,2}
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:50.222091+00:00 [debug] <0.898.0> Resolved client hostname during authN phase: ::ffff:172.27.0.2
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:50.222151+00:00 [debug] <0.898.0> User 'O=client,CN=rmq-0' authenticated successfully by backend rabbit_auth_backend_internal
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:50.229725+00:00 [info] <0.898.0> connection <0.898.0> (172.27.0.1:55120 -> 172.27.0.2:5671): user 'O=client,CN=rmq-0' authenticated and granted access to vhost '/'
rabbitmq-users-slxfibgakfq-tc3-rmq-0-1 | 2022-06-27 08:30:53.371718+00:00 [info] <0.898.0> closing AMQP connection <0.898.0> (172.27.0.1:55120 -> 172.27.0.2:5671, vhost: '/', user: 'O=client,CN=rmq-0')I wonder why I was experiencing such behavior in my first post is because my server cert and client cert are always signed with the same CA.
I would like to confirm:
This is the behavior of the Trust Store plugin, and the only way to block some certificates with the same CA is through CRL with erlang and Advanced Config.
Another wonder I have is if rmq-0 and rmq-1 are intermediate CAs signed by the same root CA, is this behavior still holds true.
I will make a pull request soon if you are interested in my code.
Once again, thank you for your kind guidance!
I am so amazed by how everything is well packaged. I really appreciate it!
I would like to confirm:
This is the behavior of the Trust Store plugin, and the only way to block some certificates with the same CA is through CRL with erlang and Advanced Config.
Another wonder I have is if rmq-0 and rmq-1 are intermediate CAs signed by the same root CA, is this behavior still holds true.
Hello again!
Thank you so much for your insight!
I conducted another round of tests to see if the Trust Store is able to block clients with certificates signed by an Intermediate CA that has the same root CA as the RabbitMQ server.
Certificate:
I generated Chained (With Separate Intermediates) Certificates with tls-gen repo, in the following hierarchy:
Chain 1: root CA => client intermediate => client certificate/key pair
Chain 2: root CA => server intermediate => server certificate/key pair
The CN were overwritten as rmq, with new user rmq created in the RabbitMQ.
Configuration:
RabbitMQ:
CA cert file: CA Chain (root CA cert + server intermediate CA cert)
Cert file & Key file: server certificate/key pair
Pika Client 1:
CA cert file: CA Chain (root CA cert + client intermediate CA cert)
Cert file & Key file: client certificate/key pair
Result:
Unfortunately, with an empty trust store directory, client 1 is still able to connect to the server.
RabbitMQ:
2022-06-28 06:10:37.506007+00:00 [debug] <0.754.0> Trust store listed certificates: []
2022-06-28 06:10:37.506329+00:00 [debug] <0.754.0> Updating 0 fetched trust store certificates
2022-06-28 06:10:51.092364+00:00 [info] <0.1156.0> accepting AMQP connection <0.1156.0> (172.29.0.1:56078 -> 172.29.0.2:5671)
2022-06-28 06:10:51.096298+00:00 [debug] <0.1156.0> auth mechanism TLS extracted username 'O=client,CN=rmq' from peer certificate
2022-06-28 06:10:51.096376+00:00 [debug] <0.1156.0> Raw client connection hostname during authN phase: {0,0,0,0,0,65535,44061,2}
2022-06-28 06:10:51.096467+00:00 [debug] <0.1156.0> Resolved client hostname during authN phase: ::ffff:172.29.0.2
2022-06-28 06:10:51.096520+00:00 [debug] <0.1156.0> User 'O=client,CN=rmq' authenticated successfully by backend rabbit_auth_backend_internal
2022-06-28 06:10:51.100525+00:00 [info] <0.1156.0> connection <0.1156.0> (172.29.0.1:56078 -> 172.29.0.2:5671): user 'O=client,CN=rmq' authenticated and granted access to vhost '/'
2022-06-28 06:10:51.119506+00:00 [info] <0.1156.0> closing AMQP connection <0.1156.0> (172.29.0.1:56078 -> 172.29.0.2:5671, vhost: '/', user: 'O=client,CN=rmq')
2022-06-28 06:10:51.122134+00:00 [debug] <0.1171.0> Closing all channels from connection '172.29.0.1:56078 -> 172.29.0.2:5671' because it has been closed
Pika Client 1:
INFO:__main__:ssl.HAS_SNI: True
INFO:pika.adapters.utils.connection_workflow:Pika version 1.2.0 connecting to ('::1', 5671, 0, 0)
INFO:pika.adapters.utils.io_services_utils:Socket connected: <socket.socket fd=8, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=6, laddr=('::1', 54602, 0, 0), raddr=('::1', 5671, 0, 0)>
INFO:pika.adapters.utils.io_services_utils:SSL handshake completed successfully: <ssl.SSLSocket fd=8, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=0, laddr=('::1', 54602, 0, 0), raddr=('::1', 5671, 0, 0)>
INFO:pika.adapters.utils.connection_workflow:Streaming transport linked up: (<pika.adapters.utils.io_services_utils._AsyncSSLTransport object at 0x7fe2b179b8b0>, _StreamingProtocolShim: <SelectConnection PROTOCOL transport=<pika.adapters.utils.io_services_utils._AsyncSSLTransport object at 0x7fe2b179b8b0> params=<ConnectionParameters host=localhost port=5671 virtual_host=/ ssl=True>>).
INFO:pika.adapters.utils.connection_workflow:AMQPConnector - reporting success: <SelectConnection OPEN transport=<pika.adapters.utils.io_services_utils._AsyncSSLTransport object at 0x7fe2b179b8b0> params=<ConnectionParameters host=localhost port=5671 virtual_host=/ ssl=True>>
INFO:pika.adapters.utils.connection_workflow:AMQPConnectionWorkflow - reporting success: <SelectConnection OPEN transport=<pika.adapters.utils.io_services_utils._AsyncSSLTransport object at 0x7fe2b179b8b0> params=<ConnectionParameters host=localhost port=5671 virtual_host=/ ssl=True>>
INFO:pika.adapters.blocking_connection:Connection workflow succeeded: <SelectConnection OPEN transport=<pika.adapters.utils.io_services_utils._AsyncSSLTransport object at 0x7fe2b179b8b0> params=<ConnectionParameters host=localhost port=5671 virtual_host=/ ssl=True>>
INFO:pika.adapters.blocking_connection:Created channel=1
INFO:__main__:(<Basic.GetOk(['delivery_tag=1', 'exchange=', 'message_count=2', 'redelivered=True', 'routing_key=foobar'])>, <BasicProperties>, b'Hello, world!')
Conclusion:
The client will still be able to pass through the trust store as ultimately, the root CA cert needs to be examined to verify the validity of the intermediate CAs to form a complete chain of trust.
(I also tried to use just intermediate CAs in the server and client respectively, but the connection could not be established. )
I was met with another interesting behavior when I tried to connect to RabbitMQ with the current CA Chain setup from clients using rmq-0 or rmq-1 client certificates.
RabbitMQ:
rabbitmq-users-slxfibgakfq-rmq-0-1 | 2022-06-28 07:43:08.497405+00:00 [debug] <0.754.0> Trust store listed certificates: []
rabbitmq-users-slxfibgakfq-rmq-0-1 | 2022-06-28 07:43:08.497513+00:00 [debug] <0.754.0> Updating 0 fetched trust store certificates
rabbitmq-users-slxfibgakfq-rmq-0-1 | 2022-06-28 07:43:25.168371+00:00 [notice] <0.4944.0> TLS server: In state wait_cert at tls_record_1_3.erl:204 generated SERVER ALERT: Fatal - Bad Record MAC
rabbitmq-users-slxfibgakfq-rmq-0-1 | 2022-06-28 07:43:25.168371+00:00 [notice] <0.4944.0> - {record_type_mismatch,21}
rabbitmq-users-slxfibgakfq-rmq-0-1 | 2022-06-28 07:43:25.183309+00:00 [notice] <0.4950.0> TLS server: In state wait_cert at tls_record_1_3.erl:204 generated SERVER ALERT: Fatal - Bad Record MAC
rabbitmq-users-slxfibgakfq-rmq-0-1 | 2022-06-28 07:43:25.183309+00:00 [notice] <0.4950.0> - {record_type_mismatch,21}
Pika Client 2 (with rmq-0 client certificate):
INFO:__main__:ssl.HAS_SNI: True
INFO:pika.adapters.utils.connection_workflow:Pika version 1.2.0 connecting to ('::1', 5671, 0, 0)
INFO:pika.adapters.utils.io_services_utils:Socket connected: <socket.socket fd=8, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=6, laddr=('::1', 55210, 0, 0), raddr=('::1', 5671, 0, 0)>
ERROR:pika.adapters.utils.io_services_utils:SSL do_handshake failed: error=SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1125)'); <ssl.SSLSocket fd=8, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=0, laddr=('::1', 55210, 0, 0), raddr=('::1', 5671, 0, 0)>
Traceback (most recent call last):
File "/Users/user/opt/anaconda3/lib/python3.8/site-packages/pika/adapters/utils/io_services_utils.py", line 636, in _do_ssl_handshake
self._sock.do_handshake()
File "/Users/user/opt/anaconda3/lib/python3.8/ssl.py", line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1125)
ERROR:pika.adapters.utils.connection_workflow:Attempt to create the streaming transport failed: SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1125)'); 'localhost'/(<AddressFamily.AF_INET6: 30>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('::1', 5671, 0, 0)); ssl=True
ERROR:pika.adapters.utils.connection_workflow:AMQPConnector - reporting failure: AMQPConnectorTransportSetupError: SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1125)')
INFO:pika.adapters.utils.connection_workflow:Pika version 1.2.0 connecting to ('127.0.0.1', 5671)
INFO:pika.adapters.utils.io_services_utils:Socket connected: <socket.socket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('127.0.0.1', 55211), raddr=('127.0.0.1', 5671)>
ERROR:pika.adapters.utils.io_services_utils:SSL do_handshake failed: error=SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1125)'); <ssl.SSLSocket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 55211), raddr=('127.0.0.1', 5671)>
Traceback (most recent call last):
File "/Users/user/opt/anaconda3/lib/python3.8/site-packages/pika/adapters/utils/io_services_utils.py", line 636, in _do_ssl_handshake
self._sock.do_handshake()
File "/Users/user/opt/anaconda3/lib/python3.8/ssl.py", line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1125)
I was surprised by this behavior such that last time, we could use rmq-0 and rmq-1’s certificates to connect, even as they are self-signed certificate, however, in this case, as soon as we introduce CA chain in the server side, and when we tried to connect with a client cert signed by a different CA, we get this error. I wonder if I made some mistakes in my configuration, and what is the implication here.
Thank you for your kind support!Hello!
I am sorry for this late reply.
I did a thorough investigation on both the Trust Store and Erlang CRL. I prepared 2 repositories for you.
1. White-listing through Trust Store
This repo is a branched out from your repo. I tried to deepen the chain of trust while limiting the Trust Store’s SSL Depth.
Unfortunately, this method does not seem to work in my use case. As long as the Root CA is the same for the broker and the clients, the client will always be able to connect to the broker, regardless of if the client’s certificate is inside the truststore or not.
2. Black-Listing through Erlang CRL (ssl_crl_has_dir) and advanced.config
While I am able to enable the CRL checking module, I do face issues in the hashing of the CRL files.
I tried to use the chained CRL file and rehash it with “openssl crl -hash” command, but this leads to {bad_crls,no_relevant_crls} errors.
I also tried to use individual CRL files generated at each CA level, rehash with “openssl rehash crl_dir” command, but this leads to {bad_crl,invalid_signature}
Please refer to the "Current Issue" Section in the readme file for more information.
I would appreciate it if you can give me some insights in resolving this issue. Which would be the correct CRL form, and how should I re-hash it.
Once we resolved the issue, I would like to make a pull request on rabbitmq-website to include the documentation on how to enable CRL check on RabbitMQ into the TLS Support Page for others to take reference as well.
Thank you!
1. White-listing through Trust Store
This repo is a branched out from your repo. I tried to deepen the chain of trust while limiting the Trust Store’s SSL Depth.
Unfortunately, this method does not seem to work in my use case. As long as the Root CA is the same for the broker and the clients, the client will always be able to connect to the broker, regardless of if the client’s certificate is inside the truststore or not.
2. Black-Listing through Erlang CRL (ssl_crl_has_dir) and advanced.config
Due to the lack of documentation, this is indeed a challenging process that took me many attempts and troubleshooting. I have included all the automation script in the set up of the broker, certificate and CRL generation, as well as detailed step-by-step guide in the readme file.While I am able to enable the CRL checking module, I do face issues in the hashing of the CRL files.
I tried to use the chained CRL file and rehash it with “openssl crl -hash” command, but this leads to {bad_crls,no_relevant_crls} errors.
I also tried to use individual CRL files generated at each CA level, rehash with “openssl rehash crl_dir” command, but this leads to {bad_crl,invalid_signature}
Please refer to the "Current Issue" Section in the readme file for more information.
I would appreciate it if you can give me some insights in resolving this issue. Which would be the correct CRL form, and how should I re-hash it.
Once we resolved the issue, I would like to make a pull request on rabbitmq-website to include the documentation on how to enable CRL check on RabbitMQ into the TLS Support Page for others to take reference as well.