I'm trying to implement an internet-facing instance of Mosquitto MQTT. Naturally, I want to make it as secure as I can.
I've successfully implemented SSL, and user authentication and access. But, I'm failing to get ACLs (so that users are restricted to which topics they can publish or subscribe). Despite my efforts, (authenticated) users are able to publish or subscribe to anything - even random topics.
What am I doing wrong?
here's my conf file: UPDATED to reflect useful comments
# === All ===
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
allow_anonymous false
# ==== EXTERNAL TLS Listener (8883) ====
listener 8883
cafile /etc/mosquitto/certs/fullchain.pem
certfile /etc/mosquitto/certs/cert.pem
keyfile /etc/mosquitto/certs/privkey.pem
require_certificate false
# ==== INTERNAL (LOCALHOST ONLY) Listener (1883) ====
listener 1883 127.0.0.1
here's my acl file: UPDATED to reflect useful comments
# Remote is restricted
user remote
topic read control/request
topic write control/report
topic write control/advertise
# Hub is unrestricted
user hub
topic readwrite control/request
topic readwrite control/report
topic readwrite control/advertise
And yes, the acl file is where it should be ;-)
~ $ ls -l /etc/mosquitto/acl
-rw-r----- 1 root mosquitto 288 Jun 4 17:21 /etc/mosquitto/acl
UPDATE Mosquitto version 2.0.11
UPDATE 2 It seems that Publish attempts to Topics are correctly restricted by the ACL, but that a user can successfully Subscribe to any random Topic. I guess that since nothing can publish to the random Topic, we're technically all good. But, it doesn't seem like that's the way it should be. Am I missing something?
UPDATE 3 In a bid to cut down on the amount of bad code available for copy/paste, I've updated this question, taking on board the useful comments below.
As per the comments, when using acl_file
in Mosquitto, SUBSCRIBE
is not restricted. Instead a check is made when a message is published (does the publisher have access to publish, and can subscribers receive it), and the message is only delivered to clients with read
access to the topic.
This is covered in this issue comment:
The ACLs in an ACL file are currently exclusively related to publishing - write indicates whether the client is allowed to send a publish to a topic, and read indicates whether a client is allowed to receive a publish on a topic.
Roger does not state why it works this way but my assumption would be that this allows the client to use a wildcard when subscribing without needing knowledge of exactly what topics it has been granted access to. For instance, in your example remote
could just subscribe to #
and would then receive messages with the topic control/request
(and only that topic).
If you want more granular control (for instance denying a SUBSCRIBE
) take a look at the Dynamic Security Plugin.
Note that there are some challenges to implementing access control on SUBSCRIBE
due to sessions outlasting connections. For example let's say remote
subscribes to control/request
, you then change it's access to deny this subscription, what should happen? (the subscription can survive loss of connection). This means that you may still need to check ACL's when delivering the messages regardless of checks on SUBSCRIBE
(obviously this is use-case dependent).