Java-164 MongoDB 认证与权限实战:单实例与分片集群 整体认证配置实战 最小化授权/错误速查/回滚剧本

TL;DR

  • 场景:把 MongoDB 从"裸奔"切到最小权限,覆盖单实例 + 分片集群的认证与授权落地。
  • 结论:正确顺序=本机创建 root@admin → 开启 authorization → 按库分权(read/readWrite/dbOwner);分片用 KeyFile 做组件间认证,在 mongos 上统一建用户。10 分钟跑通,提供可回滚路径。
  • 产出:MRE 脚本、mongodb.conf 模板、角色授予清单、报错速查卡、回滚剧本;适配 MongoDB 7.0/8.0,示例使用 mongosh + URI(含 ?authSource)。

认证流程

创建 wzk_test1 数据库并创建了两个用户,zhangsan用户拥有读写权限,lisi用户拥有只读权限,测试这两个账户的权限。

这里需要以管理员登录测试权限。

创建管理员

MongoDB 安全认证机制详解

管理员账号的必要性

在开启 MongoDB 安全检查前,必须先在 admin 数据库中创建至少一个管理员账号。admin 数据库中的用户拥有特殊权限,能够执行管理操作和访问所有数据库。这些用户被视为全局管理员,对整个 MongoDB 实例拥有最高权限。

身份验证机制的工作原理

MongoDB 的身份验证机制遵循以下原则:

  1. admin 数据库优先:当启用身份验证时,MongoDB 首先会检查 admin 数据库中是否存在用户账号
  2. 权限继承机制:如果 admin 数据库为空,即使其他数据库(如 test、production)中存在用户账号,身份验证也不会完全生效
  3. 超级权限漏洞:当 admin 数据库为空时,客户端可以不提供任何认证信息就能获得完全的读写权限,这会使安全检查形同虚设

安全配置的正确步骤

为确保安全认证有效,应按以下顺序操作:

  1. 首先在 admin 数据库创建管理员账号:
javascript 复制代码
use admin
db.createUser(
  {
    user: "adminUser",
    pwd: "securePassword",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)
  1. 重启 MongoDB 服务并启用身份验证:
bash 复制代码
mongod --auth
  1. 连接时必须提供认证信息:
bash 复制代码
mongo -u adminUser -p securePassword --authenticationDatabase admin

实际应用场景示例

在企业环境中,通常会配置:

  • 1-2 个具有 userAdminAnyDatabase 角色的超级管理员账号
  • 针对具体应用创建专门的数据库用户,限制其权限范围
  • 定期轮换密码和检查权限分配

这种分层安全架构既能保证管理需要,又能遵循最小权限原则。

创建普通用户

如下所示 wzk_test1 是自己新建的新建库,没安全认证之前可以随意 CRUD,其余的都是 MongoDB 自带的数据库。

为 admin 库创建管理员之后,现在来为普通数据库创建普通用户,以 mydb1 为例,方式与创建管理员一致,切换到指定数据库进行创建即可。

为 wzk_test1 数据库创建了两个用户,zhangsan 拥有读写权限,lisi 拥有只读权限,密码123456

shell 复制代码
use wzk_test1

db.createUser({
  user:"zhangsan",
  pwd:"123456",
  roles:[{role:"readWrite",db:"wzk_test1"}]
})

db.createUser({
  user:"lisi",
  pwd:"123456",
  roles:[{role:"read",db:"wzk_test1"}]
})

接着从客户端关闭 MongoDB 服务端,之后服务端会以安全认证方式启动。

shell 复制代码
use admin
db.shutdownServer()

也可以重新后台上杀掉服务再重启也OK的。

别忘了启动的时候,配置里边的 auth 是 true

shell 复制代码
dbpath=/data/db/
port=27000
bind_ip=0.0.0.0
fork=true
logpath = /data/db/MongoDB.log
logappend = true
auth=true

启动服务:

shell 复制代码
./mongod -f mongodb.conf

验证权限

普通用户现在仍然可以像之前一样通过命令行客户端连接到 MongoDB 数据库实例,例如使用以下命令直接登录到 wzk_test1 数据库:

bash 复制代码
mongo 127.0.0.1:27017/wzk_test1 -u username -p password

虽然登录过程本身是成功的(系统不会拒绝连接),但在登录后用户会立即遇到诸多操作限制。具体表现为:

  1. 系统日志输出明显减少,不再显示完整的操作日志信息
  2. 尝试执行基础查询命令时会遇到权限不足的错误:
    • show dbs 命令失败 - 无法查看数据库列表
    • show tables 命令失败 - 无法查看集合列表
    • 即使访问那些不需要安全认证的数据库也会操作失败

这种限制的根本原因是 MongoDB 的访问控制机制在起作用。系统会严格遵循"最小权限原则",每个用户只能在自己的权限范围内进行操作。

正确的操作流程应该是:

  1. 先建立数据库连接
  2. 然后立即执行授权认证:
javascript 复制代码
db.auth("username", "password")
  1. 只有认证通过后,才能执行权限范围内的操作

例如,一个只有wzk_test1数据库读写权限的用户:

  • 可以正常查询wzk_test1中的集合数据
  • 可以创建/删除该库中的集合
  • 但无法查看其他数据库信息
  • 也不能执行任何数据库管理命令

这种设计确保了数据库的安全性,防止了权限越界操作。在实际应用中,DBA需要根据业务需求,通过db.grantRolesToUser()等方法精确地为每个用户配置适当的权限范围。

分片集群认证

PS:开启安全认证之前,进入路由创建管理员和普通用户

关闭所有配置

这里需要关闭所有的配置节点、分片节点、路由节点

shell 复制代码
killall mongod

生成秘钥

生成一个秘钥文件,并修改权限

shell 复制代码
openssl rand -base64 756 > testKeyFile.file
chmod 600 testKeyFile.file

配置秘钥

配置节点集群和分片节点集群,开启认证和指定秘钥文件:

shell 复制代码
auth=true
keyFile=testKeyFile.file

在路由配置文件中,设置秘钥文件:

shell 复制代码
keyFile=testKeyFile.file

启动服务

启动所有配置节点、分片节点、路由节点,使用路由进行权限验证。

shell 复制代码
./mongod -f config/config-17017.conf
./mongod -f config/config-17018.conf
./mongod -f config/config-17019.conf
./mongod -f shard/shard1/shard1-37017.conf
./mongod -f shard/shard1/shard1-37018.conf
./mongod -f shard/shard1/shard1-37019.conf
./mongod -f shard/shard2/shard2-47017.conf
./mongod -f shard/shard2/shard2-47018.conf
./mongod -f shard/shard2/shard2-47019.conf
./mongos -f route/route-27017.conf

最小化可运行

准备配置

mongodb.conf(最小模板):

yaml 复制代码
storage:
  dbPath: /data/db
systemLog:
  destination: file
  path: /data/db/mongodb.log
  logAppend: true
net:
  bindIp: 0.0.0.0
  port: 27017
processManagement:
  fork: true
# 第一次先不要开启 authorization,创建好用户再启用
# security:
#   authorization: enabled

启动:

shell 复制代码
mongod -f mongodb.conf

创建首个管理员(admin 库)

通过 mongosh 连接本机(触发 localhost 例外,仅用于创建首个用户)。

shell 复制代码
// 连接
mongosh --host 127.0.0.1 --port 27017

use admin

db.createUser({
  user: 'adminUser',
  pwd:  '强密码_建议16+位',
  roles: [ { role: 'root', db: 'admin' } ]
})

说明:相较 userAdminAnyDatabase,root 更贴合超管需求;若公司有分权要求,可拆分多个管理员角色。

启用授权并重启

编辑 mongodb.conf:

yaml 复制代码
security:
  authorization: enabled

重启:

shell 复制代码
mongod --shutdown --config mongodb.conf || true
mongod -f mongodb.conf

创建业务库与用户

shell 复制代码
mongosh -u adminUser -p '强密码_建议16+位' --authenticationDatabase admin \
  --host 127.0.0.1 --port 27017

use wzk_test1

db.createUser({
  user: 'zhangsan',
  pwd:  '建议强密码',
  roles: [ { role: 'readWrite', db: 'wzk_test1' } ]
})

db.createUser({
  user: 'lisi',
  pwd:  '建议强密码',
  roles: [ { role: 'read', db: 'wzk_test1' } ]
})

权限验证

只读用户 lisi:

shell 复制代码
mongosh 'mongodb://lisi:密码@127.0.0.1:27017/wzk_test1?authSource=wzk_test1'
shell 复制代码
// 允许:查询
use wzk_test1
 db.collection('demo').findOne()

// 拒绝:写入(返回 Unauthorized error 13)
db.collection('demo').insertOne({a:1})

读写用户 zhangsan:

shell 复制代码
mongosh 'mongodb://zhangsan:密码@127.0.0.1:27017/wzk_test1?authSource=wzk_test1'
shell 复制代码
// 允许:写入/查询
use wzk_test1
 db.collection('demo').insertOne({a:1})
 db.collection('demo').find({a:1})

// 默认不能查看"其他数据库列表"
show dbs  // 需要 listDatabases 权限

最小化授权

管理员分权

  • 平台管理员:root(仅少量人员掌握)。
  • DB 管理员:dbAdminAnyDatabase + userAdminAnyDatabase。
  • 集群管理员:clusterAdmin(分片/复制集管理)。

应用分权

  • 读写:readWrite@
  • 只读:read@
  • DDL/索引:dbOwner@ 或自定义角色(尽量别给 readWriteAnyDatabase)。

密码轮换

  • 新建临时用户 → 应用切换凭据 → 删除旧用户(或更新 pwd 并同步配置管理/密钥库)。

审计要点

开启 auditLog(企业版)或至少保留 systemLog;对高危操作(增删角色、授予 root)保留变更记录。

错误速查

现象/报错 可能原因 核验命令 解决动作
Authentication failed / SCRAM 用户/密码错;authSource 错 db.runCommand({connectionStatus:1,showPrivileges:true}) 用 URI 指定 ?authSource=<db>;核对用户是否建在 wzk_test1/admin
not authorized on <db> to execute 角色权限不足 db.getUser('<user>') 补授所需动作(如 readWrite/dbOwner
listDatabases 被拒 未授 listDatabases db.adminCommand({listDatabases:1}) 管理/只读账号按需授 readAnyDatabase(谨慎)
Failed to set up listener: key file permissions KeyFile 权限不安全 ls -l /path/keyfile chown mongod:mongod keyfile && chmod 600 keyfile
开启 authorization 后所有客户端都失败 先启用了授权但尚无 admin 用户 - 按"localhost 例外"在本机创建首个 admin(或临时停授权,见回滚)
user is not allowed to do action dropDatabase 角色不含 DDL db.getUser() 使用 dbOwner 或授予对应 actions 的自定义角色

回滚剧本

仅用于救援,执行前隔离网络或绑定 127.0.0.1,避免暴露无授权实例。

单实例:

  • 停服:mongod --shutdown --config mongodb.conf

  • 临时以无授权方式、仅绑定本机启动:

    mongod --port 27017 --bind_ip 127.0.0.1 --dbpath /data/db --fork

    --logpath /data/db/mongodb-rollback.log --logappend

  • 连接本机,修复用户/角色:创建/重置 adminUser 密码或增授权限。

  • 正常关闭后,按启用授权的配置重启。

分片集群:

  • 优先通过 mongos 使用 clusterAdmin/root 账号修复;避免逐节点关授权。
  • 如必须降级,先全员绑定 127.0.0.1,并在维护窗口逐步处理(顺序:configsvr→shard→mongos),修复后恢复授权。

其他系列

🚀 AI篇持续更新中(长期更新)

AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南!
AI-调查研究-108-具身智能 机器人模型训练全流程详解:从预训练到强化学习与人类反馈
🔗 AI模块直达链接

💻 Java篇持续更新中(长期更新)

Java-154 深入浅出 MongoDB 用Java访问 MongoDB 数据库 从环境搭建到CRUD完整示例

MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!
🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
🔗 大数据模块直达链接

相关推荐
jnrjian12 小时前
text index 查看index column index定义 index 刷新频率 index视图
数据库·oracle
瀚高PG实验室12 小时前
审计策略修改
网络·数据库·瀚高数据库
言慢行善13 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
韶博雅13 小时前
emcc24ai
开发语言·数据库·python
专吃海绵宝宝菠萝屋的派大星13 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
有想法的py工程师13 小时前
PostgreSQL 分区表排序优化:Append Sort 优化为 Merge Append
大数据·数据库·postgresql
2501_9333295513 小时前
技术架构深度解析:Infoseek舆情监测系统的全链路设计与GEO时代的技术实践
开发语言·人工智能·分布式·架构
大数据新鸟13 小时前
操作系统之虚拟内存
java·服务器·网络
Tong Z13 小时前
常见的限流算法和实现原理
java·开发语言
凭君语未可13 小时前
Java 中的实现类是什么
java·开发语言