4、用户名密码认证:配置MQTT Broker的ACL,实现基于用户/主题的细粒度权限控制

好,咱们接着聊。上一章我们把TLS/SSL证书体系搭起来了,设备能安全地连上Broker了。但有个问题——连上来之后,它能干什么?

说白了,一个温度传感器能不能去控制路灯?一个只该上报数据的设备,能不能去订阅别人的控制指令?

答案显然是不行。这就是我们今天要解决的问题——ACL(访问控制列表)。

4.1 为什么有了用户名密码还不够?

很多刚入行的朋友觉得,我配了用户名密码,设备认证通过了,不就安全了吗?

嗯,这里有个误区。认证(Authentication)和授权(Authorization)是两码事。

  • 认证:证明你是谁。比如你掏出身份证,证明你是张三。
  • 授权:证明你能干什么。比如张三能不能进这间机房?

我在项目里见过一个真实案例。某工厂把所有传感器都用同一个账号连Broker,结果一个调试用的客户端误操作,往控制主题发了一条错误指令,整条产线停了两个小时。为什么?因为没有做主题级别的权限隔离。

所以,用户名密码只是第一道门,ACL才是真正的看门狗。

4.2 ACL的核心模型:谁 + 能做什么 + 对哪个主题

ACL的规则其实特别简单,就三个要素:

要素 含义 示例
用户/客户端ID 谁在请求操作 sensor_temp_01
操作类型 发布(publish)、订阅(subscribe)、读写(readwrite) publish
主题过滤器 允许或拒绝操作的主题模式 factory/floor1/temperature/#

你想想看,这三样东西一组合,权限就能切得非常细。比如:

  • 温度传感器只能往 sensor/temperature/# 发布数据。
  • 监控大屏只能订阅 alarm/# 和 status/#。
  • 管理员账号可以读写所有 admin/# 主题。

4.3 实战:在Mosquitto中配置动态ACL

我个人习惯用Mosquitto做演示,因为它轻量、配置直观,而且支持动态ACL文件。咱们一步步来。

4.3.1 准备密码文件

首先,创建用户。Mosquitto提供了 mosquitto_passwd 工具:

# 创建密码文件,并添加用户 sensor_temp
sudo mosquitto_passwd -c /etc/mosquitto/passwd sensor_temp
# 系统会提示输入密码,比如输入 Temp@2024

# 添加第二个用户 dashboard_monitor
sudo mosquitto_passwd /etc/mosquitto/passwd dashboard_monitor
# 输入密码 Monitor@2024

# 添加管理员用户 admin_iot
sudo mosquitto_passwd /etc/mosquitto/passwd admin_iot
# 输入密码 Admin@2024
小技巧: 我建议密码文件不要用默认路径,单独放在 /etc/mosquitto/conf.d/ 下,方便后续做配置分离管理。

4.3.2 编写ACL规则文件

接下来是重头戏。创建 /etc/mosquitto/acl 文件,写入以下规则:

# 只允许本地管理员读取ACL文件
user admin_iot
topic readwrite admin/#

# 温度传感器:只能发布数据,不能订阅
user sensor_temp
topic write sensor/temperature/+
topic write sensor/humidity/+

# 监控大屏:只能订阅告警和状态,不能发布
user dashboard_monitor
topic read alarm/#
topic read status/#

# 匿名用户:全部拒绝(默认行为)
topic readwrite #

# 模式匹配:所有以 sensor_ 开头的客户端,只能写对应主题
pattern write sensor/%u/#

这里有个关键点——规则是从上往下匹配的,匹配到第一条就生效。所以要把最严格的规则放前面,宽松的放后面。

注意: 最后一行 topic readwrite # 是给匿名用户的拒绝规则。如果你忘了写这一行,Mosquitto默认会允许所有未匹配的客户端访问所有主题。我曾经因为这个疏忽,在生产环境上出了个大篓子,排查了一整天才发现是ACL兜底规则没配。

4.3.3 修改Mosquitto主配置文件

编辑 /etc/mosquitto/mosquitto.conf,加入或修改以下配置:

# 开启密码认证
allow_anonymous false
password_file /etc/mosquitto/passwd

# 开启ACL
acl_file /etc/mosquitto/acl

# 开启ACL严格模式(未匹配的客户端默认拒绝)
acl_deny_unknown true

重启Mosquitto服务:

sudo systemctl restart mosquitto

4.4 验证ACL效果

我们来测试一下。用 mosquitto_sub 和 mosquitto_pub 模拟不同用户的行为。

# 测试1:温度传感器发布数据(应该成功)
mosquitto_pub -h localhost -u sensor_temp -P Temp@2024 -t sensor/temperature/room1 -m "25.3"

# 测试2:温度传感器尝试订阅告警主题(应该被拒绝)
mosquitto_sub -h localhost -u sensor_temp -P Temp@2024 -t alarm/critical -d
# 你会看到 Connection refused: not authorized 的错误

# 测试3:监控大屏订阅状态主题(应该成功)
mosquitto_sub -h localhost -u dashboard_monitor -P Monitor@2024 -t status/gateway -d

# 测试4:监控大屏尝试发布控制指令(应该被拒绝)
mosquitto_pub -h localhost -u dashboard_monitor -P Monitor@2024 -t admin/restart -m "reboot"
# 同样会收到授权失败的错误

4.5 动态ACL vs 静态ACL

刚才我们用的是静态ACL文件。修改文件后需要重启Broker才能生效。但在生产环境中,重启意味着断连,这往往不可接受。

所以,我推荐使用动态ACL。Mosquitto 2.0以上版本支持通过插件实现动态ACL,比如 mosquitto-go-auth 或 auth-plugin。这些插件可以把ACL规则存在MySQL、Redis或PostgreSQL里,修改后实时生效。

对比项 静态ACL文件 动态ACL(数据库)
生效方式 需重启Broker 实时生效
管理方式 手动编辑文件 API或管理后台
适用场景 设备数量少、规则固定 大规模、频繁变更
性能开销 低 中等(取决于数据库查询)

4.6 核心逻辑流程图

下面这张图,把客户端从连接Broker到执行操作的完整ACL判断流程画清楚了。

MQTT ACL 判断流程 客户端发起连接 用户名密码认证 认证通过? 拒绝连接 客户端请求操作 ACL规则 匹配? 拒绝操作 允许执行操作

4.7 避坑指南与最佳实践

做ACL配置这几年,我踩过不少坑。挑几个典型的说说:

  • 主题通配符滥用:有些人图省事,直接写 topic readwrite # 给所有用户。这等于没配ACL。我建议能用具体主题就别用通配符,实在要用,+(单级通配符)比 #(多级通配符)更安全。
  • 忘记兜底规则:前面说了,Mosquitto默认行为是允许未匹配的客户端。一定要显式加上拒绝规则,或者开启 acl_deny_unknown true。
  • 密码文件权限:密码文件里存的是哈希值,但也不能让所有人读。记得 chmod 640,属主设为mosquitto用户。
  • 日志审计:开启Mosquitto的日志功能,记录ACL拒绝事件。这样出了问题能快速定位是哪个客户端在违规操作。

核心原则:最小权限原则

每个客户端只给它能完成本职工作所需的最小权限。多一个权限都不要给。这是物联网安全的第一条铁律。

好了,ACL这块就聊到这儿。你只要把用户、操作、主题这三个要素理清楚,再配上合理的兜底规则,基本上就能挡住绝大多数越权访问了。