给 Mosquitto 配置 Go Auth 插件
Mosquitto Go Auth 是 Mosquitto MQTT 代理的身份验证和授权插件。之所以叫这个名字,是因为历史的原因,现在改名字太晚了,影响太大。
Mosquitto 是一个很流行的开源 MQTT 代理。go-auth 主要使用 Go 语言编写,它使用 cgo 来调用 mosquitto 的 auth-plugin 函数。
它支持并实现了以下后端:
- 文件
- Postgresql 数据库
- Mysql 数据库
- Sqlite3 数据库
- MongoDB 数据库
- Redis
- JWT
- HTTP
- gRPC
- Javascript 解释器
- 定制后端
每个后端都提供用户、超级用户和 ACL 检查,并包括适当的测试。
我们先来构建它,构建它需要 cgo 环境,并且需要先构建 mosquitto。我们在 Linux 主机上安装 gcc,并安装 golang 环境,golang 版本要求 1.18 以上。
我们从https://github.com/eclipse/mosquitto
下载源码文件。然后参考说明文档编译安装 mosquitto。我使用的 CentOS7,直接通过yum install mosquitto
安装,安装的 mosquitto 版本为 1.6.10。所以我要下载 mosquitto1.6.10 的源代码。将代码中的 mosquitto.h,mosqutto_plugin.h 和 mosquitto_broker.h 文件复制到/usr/local/include 目录。
我们从https://github.com/iegomez/mosquitto-go-auth
下载 go auth 的源码文件。我下载的当前版本为 2.1.0,解压缩并进入到源文件目录。输入命令make
,将编译一个 pw 二进制文件和一个 go-auth.so 文件。我们将 go-auth.so 文件复制到/usr/local/lib
目录,将 pw 二进制文件复制到/usr/local/bin
目录。pw 可以用来生成密码,go-auth.so 是 mosquitto 调用的库。
现在我们调整配置,启用 go auth 插件。在/etc/mosquitto/mosquitto.conf 文件中添加如下内容:
include_dir /etc/mosquitto/conf.d
然后,在/etc/mosquitto 目录下,创建 conf.d 文件夹。进入 conf.d 文件夹,创建 go-auth.conf 文件。在该文件中,先加入如下内容:
auth_plugin /etc/mosquitto/conf.d/go-auth.so
auth_opt_backends files, postgres
## 添加日志
auth_opt_log_level debug
auth_opt_log_dest file
auth_opt_log_file /var/log/mosquitto.log
## 添加加密算法
auth_opt_hasher bcrypt
auth_opt_hasher_cost 10
我只使用了文件和 PG 数据库这两种后端,所以先讲这两种的配置方法。先来配置文件。
auth_opt_files_password_path /etc/mosquitto/conf.d/password_file
auth_opt_files_acl_path /etc/mosquitto/conf.d/acl_file
先给这两个文件修改拥有者和属性。这样 mosquitto 服务启动后,可以有权限调用这两个文件。
chown mosquitto:mosquitto password_file
chown mosquitto:mosquitto acl_file
chmod 0600 password_file
chmod 0600 acl_file
使用 pw 为用户生成密码,
pw -h brcrypt -p 123456(你的密码)
password_file 格式如下:
test1:$2a$10$ATi9XlzxcevYuiznP90cuuWDCvrKJKguF6KBhMKrIgWWtBSjd44XO
test2:$2a$10$DSbIaUqwJ8nTBFHyEt.5GOvSbOcRVREJGNFdquOnRdk9.4QopcOjC
test3:$2a$10$do17Uiopj9kQfPsmRIboh.3KwbUNHAS/7cUtxN8a44kUBQiAqbZ6i
注意,你的密码肯定和我的不一样。
acl_file 格式如下:
user test1
topic write test/topic/1
topic read test/topic/2
user test2
topic read test/topic/+
user test3
topic read test/#
pattern read test/%u
pattern read test/%c
重启 mosquitto 服务,文件后端配置就生效了。
下面我们再来讲讲如何配置 PG 数据库。需要先创建两个表,表的结构如下:
create table test_user(
id bigserial primary key,
username character varying (100) not null,
password_hash character varying (200) not null,
is_admin boolean not null);
create table test_acl(
id bigserial primary key,
test_user_id bigint not null references test_user on delete cascade,
topic character varying (200) not null,
rw int not null);
更具体的 PG 创建数据库和用户就不细节了。在库中创建这两个表。然后添加如下配置到 go-auth.conf 文件中。
auth_opt_pg_host localhost
auth_opt_pg_port 5432
auth_opt_pg_dbname appserver
auth_opt_pg_user appserver
auth_opt_pg_password appserver
auth_opt_pg_connect_tries 5
auth_opt_pg_userquery select password_hash from test_user where username = $1 limit 1
auth_opt_pg_superquery select count(*) from test_user where username = $1 and is_admin = true
auth_opt_pg_aclquery SELECT a.topic FROM test_user u left join test_acl a on u.id = a.test_user_id WHERE (u.username = $1) AND a.rw = $2
上面的配置信息仅作为参考,请根据你实际的情况进行调整。
在实际调试连接时,碰到两个问题,记录下来,以备查询。
1,连接 pg 数据库后,使用 mqtt 客户端无法连接,一直报错没有认证,数据报文 mqtt3.1.1 返回 5,mqtt5.0 返回 135。
经过排查,是配置文件问题,我使用的 mosquitto 的版本为 1.6.10。在 mosquitto 配置文件中,将下面两行注释掉,让代理取 go-auth 中的配置。
allow_anonymous false
#password_file /etc/mosquitto/pwfile
#acl_file /etc/mosquitto/aclfile
include_dir /etc/mosquitto/conf.d
2,使用 pg 的账户连接成功后,一直无法订阅主题,提示权限问题。
经过排查,是在 pg 数据库设置订阅权限问题,Readme 中有提到,但没有注意。
Mosquitto 1.5 introduced a new ACL access value, MOSQ_ACL_SUBSCRIBE, which is similar to the classic MOSQ_ACL_READ value but not quite the same:
Also, these are the current available values from mosquitto:
#define MOSQ_ACL_NONE 0x00
#define MOSQ_ACL_READ 0x01
#define MOSQ_ACL_WRITE 0x02
#define MOSQ_ACL_SUBSCRIBE 0x04
所以,如果你使用 1.5 版本以后,需要添加 MOSQ_ACL_SUBSCRIBE 0x04。否则没有权限。
下面是调通之后的正常日志:
time="2024-09-30T11:44:07+08:00" level=debug msg="Superuser check with backend Postgres"
time="2024-09-30T11:44:07+08:00" level=debug msg="Acl check with backend Postgres"
time="2024-09-30T11:44:07+08:00" level=debug msg="user c7a610f7176ebf8f0056 acl authenticated with backend Postgres"
time="2024-09-30T11:44:07+08:00" level=debug msg="Acl is true for user c7a610f7176ebf8f0056"