mosquito / aio-pika

AMQP 0.9 client designed for asyncio and humans.
https://aio-pika.readthedocs.org/
Apache License 2.0
1.18k stars 186 forks source link

Unable to use tls protected connection #631

Open GoodManWEN opened 4 weeks ago

GoodManWEN commented 4 weeks ago

Hi all, I am trying to connect to rabbitmq server with aio_pika and use tls to protect the connection, but I am encountering and ConnectionResetError with no other explanation. I was wondering if anyone can help me with some error fix tips.

I ubuntu system and created my rabbitmq service using docker. The certificate generation and image configuration files are as follows:

Dockerfile:

FROM rabbitmq:3.13-management

# copy rabbitmq.config to container
COPY rabbitmq.config /etc/rabbitmq/rabbitmq.config

# copy tls certificates and key to container
COPY rabbitmq-server-cert.pem /etc/rabbitmq/certs/rabbitmq-server-cert.pem
COPY rabbitmq-server-key.pem /etc/rabbitmq/certs/rabbitmq-server-key.pem
COPY ca-certificate.pem /etc/rabbitmq/certs/ca-certificate.pem

# expose ports for RabbitMQ server
EXPOSE 5671 5672 15672

# Start RabbitMQ server
CMD ["rabbitmq-server"]

create_image.sh

# 1. Generate or obtain a CA certificate (ca_certificate.pem)
openssl genpkey -algorithm RSA -out ca-key.pem -pkeyopt rsa_keygen_bits:2048
openssl req -x509 -new -key ca-key.pem -days 3650 -out ca-certificate.pem -subj "/CN=MyCA"

# 2. Generate a RabbitMQ Server Private Key and Certificate Signing Request (CSR)
openssl genpkey -algorithm RSA -out rabbitmq-server-key.pem -pkeyopt rsa_keygen_bits:2048
openssl req -new -key rabbitmq-server-key.pem -out rabbitmq-server-csr.pem -subj "/CN=rabbitmq-server"

# 3. Sign the RabbitMQ Server Certificate with a CA Certificate
openssl x509 -req -in rabbitmq-server-csr.pem -CA ca-certificate.pem -CAkey ca-key.pem -CAcreateserial -out rabbitmq-server-cert.pem -days 3650

# Remove unnecessary files
rm ca-key.pem && rm rabbitmq-server-csr.pem

cat <<EOF > rabbitmq.config
[
 {rabbit, [
   {tcp_listeners, [{"0.0.0.0", 5672}]},
   {ssl_listeners, [{"0.0.0.0", 5671}]},
   {ssl_options, [{cacertfile, "/etc/rabbitmq/certs/ca-certificate.pem"},
                  {certfile,   "/etc/rabbitmq/certs/rabbitmq-server-cert.pem"},
                  {keyfile,    "/etc/rabbitmq/certs/rabbitmq-server-key.pem"},
                  {verify,     verify_peer},
                  {fail_if_no_peer_cert, true}]}
 ]}
].
EOF

docker build -t my-rabbitmq .

docker run -d --name my-rabbitmq -p 5672:5672 -p 5671:5671 -p 15672:15672 \
    -e RABBITMQ_DEFAULT_USER=admin \
    -e RABBITMQ_DEFAULT_PASS=123456 \
    my-rabbitmq

As with the image booting smoothly, I currently have normal access to the control panel via port 15672 and normal activity via port 5672.

Executing rabbitmq-diagnostics listeners command yields the following result, which according to my understanding means that port 5671 has been successfully loaded and protected by tls.

root@82029c15869e:/# rabbitmq-diagnostics listeners
Asking node rabbit@82029c15869e to report its protocol listeners ...
Interface: [::], port: 15672, protocol: http, purpose: HTTP API
Interface: [::], port: 15692, protocol: http/prometheus, purpose: Prometheus exporter API over HTTP
Interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Interface: 0.0.0.0, port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Interface: 0.0.0.0, port: 5671, protocol: amqp/ssl, purpose: AMQP 0-9-1 and AMQP 1.0 over TLS

Use nc localhost 5671 command to check that port 5671 is listening for connections.

On this basis, I would like to make a basic connection test using aio_pika

# -*- coding: utf-8 -*-
# File name: client.py
import asyncio
import aio_pika
from aio_pika.abc import SSLOptions
import ssl

async def main():
    connection = await aio_pika.connect(
        host='localhost',
        port=5671,
        login='admin',
        password='123456',
        ssl=True,
        ssl_options=SSLOptions(
            cafile="ca-certificate.pem",
            certfile="rabbitmq-server-cert.pem",
            keyfile="rabbitmq-server-key.pem",
            no_verify_ssl=ssl.CERT_REQUIRED,
        ),
        client_properties={"connection_name": "aio-pika external credentials"},
    )
    print(connection)
    await connection.close()

asyncio.run(main())

Got the following trace log:

Traceback (most recent call last):
  File "C:\Program Files\Python\Python310\lib\site-packages\aiormq\connection.py", line 455, in connect
    reader, writer = await asyncio.open_connection(
  File "C:\Program Files\Python\Python310\lib\asyncio\streams.py", line 48, in open_connection
    transport, _ = await loop.create_connection(
  File "C:\Program Files\Python\Python310\lib\asyncio\base_events.py", line 1103, in create_connection
    transport, protocol = await self._create_connection_transport(
  File "C:\Program Files\Python\Python310\lib\asyncio\base_events.py", line 1133, in _create_connection_transport
    await waiter
ConnectionResetError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\USER\Downloads\Tesging\test2.py", line 44, in <module>
    asyncio.run(main())
  File "C:\Program Files\Python\Python310\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Program Files\Python\Python310\lib\asyncio\base_events.py", line 649, in run_until_complete
    return future.result()
  File "C:\Users\USER\Downloads\Tesging\test2.py", line 24, in main
    connection = await aio_pika.connect(
  File "C:\Program Files\Python\Python310\lib\site-packages\aio_pika\connection.py", line 388, in connect
    await connection.connect(timeout=timeout)
  File "C:\Program Files\Python\Python310\lib\site-packages\aio_pika\connection.py", line 118, in connect
    self.transport = await UnderlayConnection.connect(
  File "C:\Program Files\Python\Python310\lib\site-packages\aio_pika\abc.py", line 671, in connect
    connection = await cls.make_connection(
  File "C:\Program Files\Python\Python310\lib\site-packages\aio_pika\abc.py", line 659, in make_connection
    connection: aiormq.abc.AbstractConnection = await asyncio.wait_for(
  File "C:\Program Files\Python\Python310\lib\asyncio\tasks.py", line 408, in wait_for
    return await fut
  File "C:\Program Files\Python\Python310\lib\site-packages\aiormq\connection.py", line 918, in connect
    await connection.connect(client_properties or {})
  File "C:\Program Files\Python\Python310\lib\site-packages\aiormq\base.py", line 164, in wrap
    return await self.create_task(func(self, *args, **kwargs))
  File "C:\Program Files\Python\Python310\lib\site-packages\aiormq\abc.py", line 44, in __inner
    return await self.task
  File "C:\Program Files\Python\Python310\lib\site-packages\aiormq\connection.py", line 462, in connect
    raise AMQPConnectionError(*e.args) from e
aiormq.exceptions.AMQPConnectionError
[Finished in 3.5s]

I tried to load the tls certificate using the ssl module that comes with python stl, and it didn't report an error, so maybe that means there's nothing wrong with the connection part of the code. Does anyone know the cause of the problem?

===

Upd:

I tried to follow the checking procedure in the rabbitmq documentation to test the availability of the certificate using the openssl self-composition loop, and got a result that showed that the certificate itself works fine.

server side command:

openssl s_server -accept 8443 \
  -cert rabbitmq-server-cert.pem -key rabbitmq-server-key.pem -CAfile ca-certificate.pem

client side command:

openssl s_client -connect localhost:8443 \
  -cert rabbitmq-server-cert.pem -key rabbitmq-server-key.pem -CAfile ca-certificate.pem \
  -verify 8 -verify_hostname rabbitmq-server

stdout:

Using default temp DH parameters
ACCEPT
-----BEGIN SSL SESSION PARAMETERS-----
MIGDAgEBAgIDBAQCEwIEIMIT2QGuxJ1lZ3G02EYPlfGv5WF1wG+NcxixxX8E9V7E
BDCeBYDvjBp/FSh5KQCDngt3KQ2+ecCN73jtn2xMgGaSnoMF4DLzgmrdJl1X84z2
3BmhBgIEZluW+KIEAgIcIKQGBAQBAAAArgcCBQDjfD8cswMCAR0=
-----END SSL SESSION PARAMETERS-----

Shared ciphers:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA
Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224:DSA+SHA224:DSA+SHA256:DSA+SHA384:DSA+SHA512
Shared Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224

Supported groups: x25519:secp256r1:x448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192
Shared groups: x25519:secp256r1:x448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192
CIPHER is TLS_AES_256_GCM_SHA384

Secure Renegotiation IS supported
    Start Time: 1717278872
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0

=== Upd:

Trying to connect directly to port 5671 using s_client. Observing the information returned from the port, the connection seems to be established successfully. However, the connection fails immediately and does not reflect in the logs that a connection was attempted, as described in the official documentation.

client stdout

root@user-ubuntu:~/RabiBridge/config# openssl s_client -connect localhost:5671   -cert rabbitmq-server-cert.pem -key rabbitmq-server-key.pem -CAfile ca-certificate.pem
CONNECTED(00000003)
405726C2087D0000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:../ssl/record/rec_layer_s3.c:308:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 300 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---