Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SASL mechanism ANONYMOUS #11999

Merged
merged 5 commits into from
Aug 15, 2024
Merged

Add SASL mechanism ANONYMOUS #11999

merged 5 commits into from
Aug 15, 2024

Conversation

ansd
Copy link
Member

@ansd ansd commented Aug 14, 2024

This PR is a breaking change for AMQP 1.0 and MQTT users, scheduled to ship in RabbitMQ 4.0.

Note that this PR also changes nothing around the intentional default connectivity restrictions for the default (anonymous connection) user. So the default security profile is not affected.

1. Introduce new SASL mechanism ANONYMOUS

What?

Introduce a new rabbit_auth_mechanism implementation for SASL
mechanism ANONYMOUS called rabbit_auth_mechanism_anonymous.

Why?

As described in AMQP section 5.3.3.1, ANONYMOUS should be used when the
client doesn't need to authenticate.

Introducing a new rabbit_auth_mechanism consolidates and simplifies how anonymous
logins work across all RabbitMQ protocols that support SASL. This commit
therefore allows AMQP 0.9.1, AMQP 1.0, stream clients to connect out of
the box to RabbitMQ without providing any username or password.

Today's AMQP 0.9.1 and stream protocol client libs hard code RabbitMQ default credentials
guest:guest for example done in:

Hard coding RabbitMQ specific default credentials in dozens of different
client libraries is an anti-pattern in my opinion.
Furthermore, there are various AMQP 1.0 and MQTT client libraries which
we do not control or maintain and which still should work out of the box
when a user is getting started with RabbitMQ (that is without
providing guest:guest credentials).

How?

The old RabbitMQ 3.13 AMQP 1.0 plugin default_user
configuration
is replaced with the following two new rabbit configurations:

{anonymous_login_user, <<"guest">>},
{anonymous_login_pass, <<"guest">>},

We call it anonymous_login_user because this user will be used for
anonymous logins. The subsequent commit uses the same setting for
anonymous logins in MQTT. Hence, this user is orthogonal to the protocol
used when the client connects.

Setting anonymous_login_pass could have been left out.
This commit decides to include it because our documentation has so far
recommended:

It is highly recommended to pre-configure a new user with a generated username and password or delete the guest user
or at least change its password to reasonably secure generated value that won't be known to the public.

By having the new module rabbit_auth_mechanism_anonymous internally
authenticate with anonymous_login_pass instead of blindly allowing
access without any password, we protect operators that relied on the
sentence:

or at least change its password to reasonably secure generated value that won't be known to the public

To ease the getting started experience, since RabbitMQ already deploys a
guest user with full access to the default virtual host /, this commit
also allows SASL mechanism ANONYMOUS in rabbit setting auth_mechanisms.

In production, operators should disable SASL mechanism ANONYMOUS by
setting anonymous_login_user to none (or by removing ANONYMOUS from
the auth_mechanisms setting). This is documented in rabbitmq/rabbitmq-website#2017.
Even if operators forget or don't read the docs, this new ANONYMOUS
mechanism won't do any harm because it relies on the default user name
guest and password guest, which is recommended against in
production, and who by default can only connect from the local host.

2. Require SASL security layer in AMQP 1.0

What?

An AMQP 1.0 client must use the SASL security layer.

Why?

This is in line with the mandatory usage of SASL in AMQP 0.9.1 and
RabbitMQ stream protocol.
Since (presumably) any AMQP 1.0 client knows how to authenticate with a
username and password using SASL mechanism PLAIN, any AMQP 1.0 client
also (presumably) implements the trivial SASL mechanism ANONYMOUS.

Skipping SASL is not recommended in production anyway.
By requiring SASL, configuration for operators becomes easier.
Following the principle of least surprise, when an an operator
configures auth_mechanisms to exclude ANONYMOUS, anonymous logins
will be prohibited in SASL and also by disallowing skipping the SASL
layer.

How?

This commit implements AMQP 1.0 figure 2.13.

A follow-up commit needs to be pushed to v3.13.x which will use SASL
mechanism anon instead of none in the Erlang AMQP 1.0 client
such that AMQP 1.0 shovels running on 3.13 can connect to 4.0 RabbitMQ nodes.

3. Remove mqtt.default_user and mqtt.default_pass

What?

Remove mqtt.default_user and mqtt.default_pass
Instead, rabbit.anonymous_login_user and rabbit.anonymous_login_pass should be used.

Why?

RabbitMQ 4.0 simplifies anonymous logins.
There is now a single configuration place

rabbit.anonymous_login_user
rabbit.anonymous_login_pass

that is used for anonymous logins for any protocol.

Anonymous login is orthogonal to the protocol the client uses.
Hence, there should be a single configuration place which can then be
used for MQTT, AMQP 1.0, AMQP 0.9.1, and RabbitMQ Stream protocol.

This will also simplify switching to SASL for MQTT 5.0 in the future.

@ansd ansd added this to the 4.0.0 milestone Aug 14, 2024
@ansd ansd force-pushed the sasl-anon branch 3 times, most recently from 03f6e13 to 6bfb690 Compare August 14, 2024 14:29
@acogoluegnes
Copy link
Contributor

Tested against the AMQP 091 and stream Java client, it's working. Will add a test case in each test suite.

@ansd ansd force-pushed the sasl-anon branch 6 times, most recently from fc37d2e to 01788bb Compare August 15, 2024 10:42
 ## 1. Introduce new SASL mechanism ANONYMOUS

 ### What?
Introduce a new `rabbit_auth_mechanism` implementation for SASL
mechanism ANONYMOUS called `rabbit_auth_mechanism_anonymous`.

 ### Why?
As described in AMQP section 5.3.3.1, ANONYMOUS should be used when the
client doesn't need to authenticate.

Introducing a new `rabbit_auth_mechanism` consolidates and simplifies how anonymous
logins work across all RabbitMQ protocols that support SASL. This commit
therefore allows AMQP 0.9.1, AMQP 1.0, stream clients to connect out of
the box to RabbitMQ without providing any username or password.

Today's AMQP 0.9.1 and stream protocol client libs hard code RabbitMQ default credentials
`guest:guest` for example done in:
* https://github.com/rabbitmq/rabbitmq-java-client/blob/0215e85643a9ae0800822869be0200024e2ab569/src/main/java/com/rabbitmq/client/ConnectionFactory.java#L58-L61
* https://github.com/rabbitmq/amqp091-go/blob/ddb7a2f0685689063e6d709b8e417dbf9d09469c/uri.go#L31-L32

Hard coding RabbitMQ specific default credentials in dozens of different
client libraries is an anti-pattern in my opinion.
Furthermore, there are various AMQP 1.0 and MQTT client libraries which
we do not control or maintain and which still should work out of the box
when a user is getting started with RabbitMQ (that is without
providing `guest:guest` credentials).

 ### How?
The old RabbitMQ 3.13 AMQP 1.0 plugin `default_user`
[configuration](https://github.com/rabbitmq/rabbitmq-server/blob/146b4862d8e570b344c99c37d91246760e218b18/deps/rabbitmq_amqp1_0/Makefile#L6)
is replaced with the following two new `rabbit` configurations:
```
{anonymous_login_user, <<"guest">>},
{anonymous_login_pass, <<"guest">>},
```
We call it `anonymous_login_user` because this user will be used for
anonymous logins. The subsequent commit uses the same setting for
anonymous logins in MQTT. Hence, this user is orthogonal to the protocol
used when the client connects.

Setting `anonymous_login_pass` could have been left out.
This commit decides to include it because our documentation has so far
recommended:
> It is highly recommended to pre-configure a new user with a generated username and password or delete the guest user
> or at least change its password to reasonably secure generated value that won't be known to the public.

By having the new module `rabbit_auth_mechanism_anonymous` internally
authenticate with `anonymous_login_pass` instead of blindly allowing
access without any password, we protect operators that relied on the
sentence:
> or at least change its password to reasonably secure generated value that won't be known to the public

To ease the getting started experience, since RabbitMQ already deploys a
guest user with full access to the default virtual host `/`, this commit
also allows SASL mechanism ANONYMOUS in `rabbit` setting `auth_mechanisms`.

In production, operators should disable SASL mechanism ANONYMOUS by
setting `anonymous_login_user` to `none` (or by removing ANONYMOUS from
the `auth_mechanisms` setting. This will be documented separately.
Even if operators forget or don't read the docs, this new ANONYMOUS
mechanism won't do any harm because it relies on the default user name
`guest` and password `guest`, which is recommended against in
production, and who by default can only connect from the local host.

 ## 2. Require SASL security layer in AMQP 1.0

 ### What?
An AMQP 1.0 client must use the SASL security layer.

 ### Why?
This is in line with the mandatory usage of SASL in AMQP 0.9.1 and
RabbitMQ stream protocol.
Since (presumably) any AMQP 1.0 client knows how to authenticate with a
username and password using SASL mechanism PLAIN, any AMQP 1.0 client
also (presumably) implements the trivial SASL mechanism ANONYMOUS.

Skipping SASL is not recommended in production anyway.
By requiring SASL, configuration for operators becomes easier.
Following the principle of least surprise, when an an operator
configures `auth_mechanisms` to exclude `ANONYMOUS`, anonymous logins
will be prohibited in SASL and also by disallowing skipping the SASL
layer.

 ### How?
This commit implements AMQP 1.0 figure 2.13.

A follow-up commit needs to be pushed to `v3.13.x` which will use SASL
mechanism `anon` instead of `none` in the Erlang AMQP 1.0 client
such that AMQP 1.0 shovels running on 3.13 can connect to 4.0 RabbitMQ nodes.
This commit is a breaking change in RabbitMQ 4.0.

 ## What?
Remove mqtt.default_user and mqtt.default_pass
Instead, rabbit.anonymous_login_user and rabbit.anonymous_login_pass
should be used.

 ## Why?
RabbitMQ 4.0 simplifies anonymous logins.
There should be a single configuration place
```
rabbit.anonymous_login_user
rabbit.anonymous_login_pass
```
that is used for anonymous logins for any protocol.

Anonymous login is orthogonal to the protocol the client uses.
Hence, there should be a single configuration place which can then be
used for MQTT, AMQP 1.0, AMQP 0.9.1, and RabbitMQ Stream protocol.

This will also simplify switching to SASL for MQTT 5.0 in the future.
@ansd ansd marked this pull request as ready for review August 15, 2024 11:05
@michaelklishin michaelklishin merged commit 2058f44 into main Aug 15, 2024
3 of 5 checks passed
@michaelklishin michaelklishin deleted the sasl-anon branch August 15, 2024 17:12
michaelklishin added a commit that referenced this pull request Aug 15, 2024
ansd added a commit that referenced this pull request Aug 16, 2024
This commit ensures that AMQP 1.0 shovels will always use a
SASL security layer when connecting to an AMQP 1.0 broker.
Instead of skipping SASL, the client will use SASL mechanism ANONYMOUS.

#11999 mandates that
AMQP 1.0 clients use a SASL security layer when connecting to a RabbitMQ
4.0 node.

This commit is only applied to the `v3.13.x` branch such that a shovel
running on a 3.13.7 node will be able to connect via AMQP 1.0 to a
RabbitMQ 4.x node.
ansd added a commit to rabbitmq/cluster-operator that referenced this pull request Aug 19, 2024
See rabbitmq/rabbitmq-server#11999 for full
context.

Starting with RabbitMQ 4.0, anonymous login should be disabled in
production.

`anonymous_login_user` and `anonymous_login_pass` both default to `guest` in RabbitMQ 4.0.
The rabbitmq/cluster-operator complies already with best practices by
provisioning a new `default_user` and `default_pass` instead of using
RabbitMQ's default `guest` user.
Instead of having RabbitMQ advertise the ANONYMOUS mechanism, this commit disables
anonymous logins.

Because `anonymous_login_user` is a new RabbitMQ 4.0 `rabbitmq.conf`
setting and the cluster-operator doesn't know what RabbitMQ version it
deploys and setting `rabbitmq.conf` key `anonymous_login_user` in RabbitMQ 3.13
would make booting RabbitMQ fail, this commit modifies the `auth_mechanisms.*`
settings in `rabbitmq.conf`:
If the user provided a conscious choice on what `auth_mechanisms`
RabbitMQ should advertise, this configuration will be respected.
If the user did not configure `auth_mechanisms`, the cluster-operator will
disable ANONYMOUS logins by setting only:
```
auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = AMQPLAIN
```
ansd added a commit to rabbitmq/cluster-operator that referenced this pull request Aug 19, 2024
* Disable ANONYMOUS login

See rabbitmq/rabbitmq-server#11999 for full
context.

Starting with RabbitMQ 4.0, anonymous login should be disabled in
production.

`anonymous_login_user` and `anonymous_login_pass` both default to `guest` in RabbitMQ 4.0.
The rabbitmq/cluster-operator complies already with best practices by
provisioning a new `default_user` and `default_pass` instead of using
RabbitMQ's default `guest` user.
Instead of having RabbitMQ advertise the ANONYMOUS mechanism, this commit disables
anonymous logins.

Because `anonymous_login_user` is a new RabbitMQ 4.0 `rabbitmq.conf`
setting and the cluster-operator doesn't know what RabbitMQ version it
deploys and setting `rabbitmq.conf` key `anonymous_login_user` in RabbitMQ 3.13
would make booting RabbitMQ fail, this commit modifies the `auth_mechanisms.*`
settings in `rabbitmq.conf`:
If the user provided a conscious choice on what `auth_mechanisms`
RabbitMQ should advertise, this configuration will be respected.
If the user did not configure `auth_mechanisms`, the cluster-operator will
disable ANONYMOUS logins by setting only:
```
auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = AMQPLAIN
```

* Apply PR feedback
ansd added a commit that referenced this pull request Sep 25, 2024
ansd added a commit that referenced this pull request Sep 25, 2024
see #11999 for context

(cherry picked from commit 1245119)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants