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判断流程画清楚了。
4.7 避坑指南与最佳实践
做ACL配置这几年,我踩过不少坑。挑几个典型的说说:
- 主题通配符滥用:有些人图省事,直接写
topic readwrite #给所有用户。这等于没配ACL。我建议能用具体主题就别用通配符,实在要用,+(单级通配符)比#(多级通配符)更安全。 - 忘记兜底规则:前面说了,Mosquitto默认行为是允许未匹配的客户端。一定要显式加上拒绝规则,或者开启
acl_deny_unknown true。 - 密码文件权限:密码文件里存的是哈希值,但也不能让所有人读。记得
chmod 640,属主设为mosquitto用户。 - 日志审计:开启Mosquitto的日志功能,记录ACL拒绝事件。这样出了问题能快速定位是哪个客户端在违规操作。
核心原则:最小权限原则
每个客户端只给它能完成本职工作所需的最小权限。多一个权限都不要给。这是物联网安全的第一条铁律。
好了,ACL这块就聊到这儿。你只要把用户、操作、主题这三个要素理清楚,再配上合理的兜底规则,基本上就能挡住绝大多数越权访问了。