MongoDB的RBAC仅提供数据库级权限控制,无法实现租户隔离,因其不校验IP、租户上下文或业务标识,且副本集共享oplog与端口,无网络层隔离;应用若误连或配置错误(如未限定authSource和database),权限即失效。

副本集本身不提供租户隔离能力,RBAC 权限只能控制「谁能在哪个数据库里做什么」,无法阻止租户 A 的应用误连租户 B 的数据库——这得靠连接层和应用层双重把关。
为什么不能只靠 userAdmin 或 dbOwner 角色实现租户隔离
MongoDB 的 RBAC 是数据库粒度的,dbOwner 对 tenant_a 数据库有全部权限,但对 tenant_b 默认无权访问;可一旦应用代码写错连接字符串(比如把 tenant_id=abc 解析成 tenant_b),或配置漏掉数据库名直接连到 admin 库,权限就形同虚设。更危险的是:所有租户共用同一套副本集 oplog 和网络端口,没有网络层隔离。
- RBAC 不校验请求来源 IP、租户上下文或业务逻辑标识,只认
db+role+action - 一个用户可以被授予多个数据库权限,比如同时有
tenant_a和tenant_b的readWrite,只要连接时指定对应authSource和database - 使用
mongosh或第三方工具直连时,权限约束完全依赖客户端是否主动切换use tenant_x
createUser 时必须显式绑定 db 并禁用跨库操作
为每个租户创建独立用户时,db 参数必须是该租户专属数据库名(如 tenant_123),且不能在 roles 数组中混入其他库的权限。MongoDB 不会自动拒绝跨库写入,但你可以用最小权限原则卡死:
- 用
db.createUser({ user: "t123_app", pwd: "...", roles: [{ role: "readWrite", db: "tenant_123" }] }),不要加clusterAdmin或root - 避免使用
admin库作为authSource以外的任何操作目标——租户应用绝不应use admin - 若用 Atlas,启用
Network Peering或VPC Access List配合用户 IP 白名单,从网络侧缩小攻击面
连接字符串里必须固化 authSource 和 database
租户应用启动时的连接 URI 不能只写 mongodb://u:p@rs0.example.com:27017/,否则默认 authSource 是 admin,而实际操作库未限定,极易越界。正确写法要带两个关键参数:
mongodb://t123_app:secret@rs0.example.com:27017/?authSource=tenant_123&database=tenant_123
-
authSource=tenant_123表示密码和角色定义在tenant_123库(不是admin),降低全局账号泄露风险 -
database=tenant_123是驱动层默认操作库,MongoTemplate或mongosh的db上下文会自动绑定到这里 - Spring Boot 中通过
spring.data.mongodb.uri配置,别用database单独字段覆盖,它不参与 authSource 解析
真正容易被忽略的点:副本集成员间无租户感知,readPreference 可能绕过权限检查
当租户应用设置 readPreference=secondaryPreferred 时,驱动可能把查询发到从节点——而某些旧版 MongoDB(getMore 或聚合时,若未显式 use tenant_x,权限校验可能不严格。这不是 bug,是设计使然:副本集节点共享同一份权限元数据,但执行上下文由客户端驱动维护。
- 务必在应用层确保每次操作前都明确指定数据库上下文,例如 Node.js 驱动中用
db.collection('users').find(...)而非client.db().collection(...) - 禁用
maxStalenessSeconds等模糊参数,防止驱动自动降级到不一致节点 - 审计日志(
system.profile或 Atlas 审计功能)要打开,重点过滤跨库find、insert操作,而非只看失败请求











