分片集群权限必须在admin数据库统一配置,mongos仅从config server的admin.system.users读取用户信息,其他库创建的用户无法被识别。

分片集群的权限必须在 admin 数据库中统一配置
分片集群(Sharded Cluster)没有“每个分片单独配权限”这回事。所有用户和角色都必须在 admin 数据库中创建,否则 mongos 路由层无法识别该用户,连接会直接被拒绝——哪怕你在某个 shard 的本地 test 库里建了用户,mongos 也根本不会去查它。
这是因为 mongos 只从 config server 的 admin.system.users 和 admin.system.roles 读取认证与授权元数据,其他数据库的用户表对路由节点完全不可见。
- 启动
mongos时必须指定--auth或配置文件中启用security.authorization: enabled - 所有
db.createUser()、db.createRole()操作必须在use admin后执行 - 连接
mongos时,认证数据库必须显式指定为admin,例如:mongo --host mongos-host:27017 -u myuser -p --authenticationDatabase admin
自定义角色要明确声明 resource 范围,否则默认作用于整个集群
在 admin 数据库中创建自定义角色时,如果不指定 resources,MongoDB 会把该角色的权限默认应用到“所有数据库和集合”,这极易造成越权。比如你只想让某角色能对 orders 库的 payments 集合执行 find,但漏写 resource,结果它获得了对 config 或 local 库的意外访问权。
正确做法是显式限定范围:
db.createRole({
role: "orders_payments_reader",
privileges: [{
resource: { db: "orders", collection: "payments" },
actions: ["find"]
}],
roles: []
})
-
resource: { db: "", collection: "" }表示全局命令权限(如listDatabases),慎用 - 对分片集群中的特定库表授权,
db字段必须写实际库名,不能写通配符 - 若需跨库权限(如同时读
orders和users),需在privileges数组中分别声明多个resource条目
内置角色如 readWriteAnyDatabase 在分片集群中行为不变,但风险更高
readWriteAnyDatabase 这类“AnyDatabase”角色在分片集群中依然有效,但它授予的是对所有分片上所有数据库的读写权限——包括那些你可能没意识到已被自动创建的系统库(如 config)。一旦该角色被误绑给应用账号,攻击者可通过 mongos 直接修改分片路由规则或删除 chunk 元数据。
- 生产环境禁止将
readWriteAnyDatabase、root或clusterAdmin绑给任何应用服务账号 - 即使是 DBA 账号,也建议拆分为多个专用角色(如一个只读监控角色 + 一个受限的运维角色),并通过
db.grantRolesToUser()动态附加 - 使用
db.runCommand({ connectionStatus: 1 })可实时查看当前连接用户已解析出的有效角色列表,验证是否有多余继承
权限变更后,现有连接不会自动刷新,必须重连或等待 authMode 切换
在 admin 库中修改用户角色或更新自定义角色权限后,已建立的 mongos 连接仍沿用旧的权限缓存,直到连接断开重建。这意味着你改完权限,立刻测试可能发现“不起作用”。
- MongoDB 不支持运行时权限热刷新;
mongos缓存用户权限约 30 分钟(受security.authorizationCacheExpirationMinutes控制,默认值) - 最可靠的方式是主动终止客户端连接,或重启应用连接池
- 若用
mongosh测试,退出后重新登录即可,不要依赖db.logout()—— 它不触发权限重载
分片集群的 RBAC 看似和单机一样写法,但真正容易出问题的,从来不是语法,而是对 mongos 的元数据加载逻辑、权限缓存机制和 resource 边界意识的缺失。配完记得用真实连接走一遍最小操作路径,别只信 shell 里的 show users。

















