amqp-rs / lapin

AMQP client library in Rust, with a clean, futures based API
MIT License
1.04k stars 92 forks source link

Connecting to Amazon MQ RabbitMQ Instance #396

Closed Barbacamanitu closed 2 months ago

Barbacamanitu commented 7 months ago

I'm looking for any information that will help me connect to my Amazon MQ RabbitMQ instance. You have to use TLS to connect to these instances. I plan on deploying my app via a docker image, and in other apps I've had to use the rustls TLS crate in order to get them to compile, so I'm trying to use the rustls feature of lapin in order to connect. This is where I'm at so far:

let uri = AMQPUri {
            scheme: AMQPScheme::AMQP,
            authority: AMQPAuthority {
                userinfo: AMQPUserInfo {
                    username: "my_username".into(),
                    password: "my_password".into(),
                },
                host: "{my-rabbitmq-hostname}.mq.us-east-2.amazonaws.com".into(),
                port: 5671,
            },
            vhost: "/".into(),
            query: AMQPQueryString::default(),
        };

I'm not sure what the query field is for, so I just tried the default one. When I try to connect using this uri, I get the following error: IOError(Custom { kind: InvalidData, error: InvalidCertificate(UnknownIssuer) })

If I try to follow along with the TLS example and parse a url to get a uri:

let url = "ampq:://{my_broker_id}.mq.us-east-2.amazonaws.com:5671";
let uri = url.parse::<AMQPUri>().unwrap();

I get the following error: Invalid URL: 'ampq:://{my_broker_id}.mq.us-east-2.amazonaws.com:5671'"

Has anyone had success in using lapin to connect to AmazonMQ based RabbitMQ instances? Is it something with the query that I need to configure? I've gotten a python script to connect to my RabbitMQ instance and I didn't need to provide any certificates or anything, so I'm pretty sure that's not necessary. The only TLS options I see on the amqprs library require you to provide certificates, so I don't think I can use that crate. I'd like to use lapin if at all possible, since I prefer its API.

Barbacamanitu commented 7 months ago

I also tried copying the TLS example exactly. I get this error when using native-tls:

IOError(Custom { kind: AlreadyExists, error: "already a TLS stream" })

I'm copying the example from here: https://github.com/amqp-rs/lapin/blob/main/examples/custom_tls_connection.rs

This happens when I manually build the uri. I cannot use the parse() function with an amazon url for some reason.

Barbacamanitu commented 7 months ago

Problem solved. Here's the updated code:

let connect = move |uri: &AMQPUri| {
        let conn = uri.connect().and_then(|stream| {
            let connector = RustlsConnector::new_with_native_certs().unwrap();
            // Perform here your custom TLS setup, with tls_builder.identity or whatever else you need
            stream.into_rustls(&connector, &uri.authority.host)
        });
        conn
    };

I had to use RustlsConnector::new_with_native_certs() instead of ::default. I also had to use scheme: AMQPScheme::AMQP in the uri. Trying to use AMQPScheme::AMQPS as the scheme did not work, even though the amazon host starts with ampqs://

Keruspe commented 2 months ago

Note that enabling the rustls-native-tls feature should be the same as this

Keruspe commented 2 months ago

(Context for the AMQP VS AMQPS: if you use amqps, lapin does the tls itself, if you use amqp it doesn't. Since you're doing the TLS yourself here, that's why you have to use amqp