Authenticating rabbitmq using ExternalCredentials
Asked Answered
G

2

6

I have a rabbitmq server and use the pika library with Python to produce/consume messages. For development purposes, I was simply using

credentials = pika.PlainCredentials(<user-name>, <password>)

I want to change that to use pika.ExternalCredentials or TLS.

I have set up my rabbitmq server to listen for TLS on port 5671, and have configured it correctly. I am able to communicate with rabbitmq from localhost, but the moment I try to communicate with it from outside the localhost it doesn't like that. I have a feeling my "credentials" are based on the "guest" user in rabbitmq.

rabbitmq.config

%% -*- mode: erlang -*-

[
 {rabbit,
  [
   {ssl_listeners, [5671]},
   {auth_mechanisms, ['PLAIN', 'AMQPLAIN', 'EXTERNAL']},
   {ssl_options, [{cacertfile,"~/tls-gen/basic/result/ca_certificate.pem"},
                  {certfile,"~/tls-gen/basic/result/server_certificate.pem"},
                  {keyfile,"~/tls-gen/basic/result/server_key.pem"},
                  {verify,verify_none},
                  {ssl_cert_login_from, common_name},
                  {fail_if_no_peer_cert,false}]}
   
  ]}
].

I can confirm this works, since in my logs for rabbitmq I see:

2019-08-21 15:34:47.663 [info] <0.442.0> started TLS (SSL) listener on [::]:5671

Server-side everything seems to be set up, I have also generated certificates and all the .pem files required.

test_rabbitmq.py

import pika
import ssl
from pika.credentials import ExternalCredentials

context = ssl.create_default_context(cafile="~/tls-gen/basic/result/ca_certificate.pem")
context.load_cert_chain("~/tls-gen/basic/result/client_certificate.pem",
                            "~/tls-gen/basic/result/client_key.pem")
ssl_options = pika.SSLOptions(context, "10.154.0.27")
params = pika.ConnectionParameters(port=5671,ssl_options=ssl_options, credentials = ExternalCredentials())
connection = pika.BlockingConnection(params)
channel = connection.channel()

When I run the script locally

(<Basic.GetOk(['delivery_tag=1', 'exchange=', 'message_count=0', 'redelivered=False', 'routing_key=foobar'])>, <BasicProperties>, b'Hello, world!')

When I run the script from another instance

Traceback (most recent call last):
  File "pbbarcode.py", line 200, in <module>
    main()
  File "pbbarcode.py", line 187, in main
    connection = pika.BlockingConnection(params)
  File "/usr/local/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 359, in __init__
    self._impl = self._create_connection(parameters, _impl_class)
  File "/usr/local/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 450, in _create_connection
    raise self._reap_last_connection_workflow_error(error)
pika.exceptions.AMQPConnectionError

When I run the script locally, and delete the guest user

Traceback (most recent call last):
  File "test_mq.py", line 12, in <module>
    with pika.BlockingConnection(conn_params) as conn:
  File "/home/daudn/.local/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 359, in __init__
    self._impl = self._create_connection(parameters, _impl_class)
  File "/home/daudn/.local/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 450, in _create_connection
    raise self._reap_last_connection_workflow_error(error)
pika.exceptions.ProbableAuthenticationError: ConnectionClosedByBroker: (403) 'ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.'

It seems like SSL is configured with the user "guest" and rabbitmq doesn't allow connections to guest outside of localhost. How can I use SSL with a different user? When I delete the guest user, this is what the rabbitmq log says:

2019-08-22 10:14:40.054 [info] <0.735.0> accepting AMQP connection <0.735.0> (127.0.0.1:59192 -> 127.0.0.1:5671)
2019-08-22 10:14:40.063 [error] <0.735.0> Error on AMQP connection <0.735.0> (127.0.0.1:59192 -> 127.0.0.1:5671, state: starting):
PLAIN login refused: user 'guest' - invalid credentials
2019-08-22 10:14:40.063 [warning] <0.735.0> closing AMQP connection <0.735.0> (127.0.0.1:59192 -> 127.0.0.1:5671):
client unexpectedly closed TCP connection
2019-08-22 10:15:12.613 [info] <0.743.0> Creating user 'guest'
2019-08-22 10:15:28.370 [info] <0.750.0> Setting user tags for user 'guest' to [administrator]
2019-08-22 10:15:51.352 [info] <0.768.0> Setting permissions for 'guest' in '/' to '.*', '.*', '.*'
2019-08-22 10:15:54.237 [info] <0.774.0> accepting AMQP connection <0.774.0> (127.0.0.1:59202 -> 127.0.0.1:5671)
2019-08-22 10:15:54.243 [info] <0.774.0> connection <0.774.0> (127.0.0.1:59202 -> 127.0.0.1:5671): user 'guest' authenticated and granted access to vhost '/'

This also clearly means the SSL is still using the username and password to connect to rabbitmq? HELP!

References:

tls_official_example

pika_official_tls_docs

added_authentication_external

Granado answered 21/8, 2019 at 15:59 Comment(0)
G
3

Going to leave this here for future reference

ssl_options = pika.SSLOptions(context, "rabbitmq-node-name")
params = pika.ConnectionParameters(host="rabbitmq-node-name",port=5671,ssl_options=ssl_options, credentials = ExternalCredentials())

The confusion was that I believed when doing SSLOptions(context, "rabbitmq-node-name") I thought I had supplied the host here and did not have to supply it again in the args for ConnectionParameters(). But turns out that's incorrect, if no host is supplied, it defaults to localhost. Which is why the script ran locally and not outside of the local network.

Granado answered 27/8, 2019 at 10:46 Comment(1)
In case you get an error module 'pika' has no attribute 'ExternalCredentials', then you need to import ExternalCredentials properly, for example by qualifying with pika.credentials.ExternalCredentials.Rawdin
P
1

You will have to enable the rabbitmq-auth-mechanism-ssl plugin , i think you are missing that part.

To enable the plugin do the following ( showing the example for a Windows setup)

rabbitmq-plugins.bat enable rabbitmq_auth_mechanism_ssl
Persuade answered 21/8, 2019 at 17:54 Comment(7)
I have edited my question, the problem is that SSL is configured with the default 'guest' user, and so I can't access it from outside the local environment.Granado
Can you share the rabbitmq logs when access is denied to the user guest whiel logging in from a remote system ?Persuade
Nothing appears in the logs since it directly throws pika.exceptions.AMQPConnectionErrorGranado
.... If you have a look at my code "test_rabbitmq.py" I don't specify a user/password since I am trying to access it over SSL? When the similar code is run on the localhost, the logs say: 2019-08-22 10:14:40.063 [error] <0.735.0> Error on AMQP connection <0.735.0> (127.0.0.1:59192 -> 127.0.0.1:5671, state: starting): PLAIN login refused: user 'guest' - invalid credentialsGranado
Humm.. can you give External the first precedence like this {auth_mechanisms, ['EXTERNAL','PLAIN', 'AMQPLAIN'},Persuade
This is the problem: 2019-08-22 11:36:45.660 [info] <0.615.0> accepting AMQP connection <0.615.0> (127.0.0.1:59680 -> 127.0.0.1:5671) 2019-08-22 11:36:45.666 [info] <0.615.0> connection <0.615.0> (127.0.0.1:59680 -> 127.0.0.1:5671): user 'guest' authenticated and granted access to vhost '/' It uses "guest" and not the user I have created. How to make it use a different user!Granado
Hello, I am one of Pika's maintainers. Please continue the discussion via the pika-python mailing list.Chairborne

© 2022 - 2024 — McMap. All rights reserved.