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案例 详解
🔗 大数据模块直达链接

相关推荐
憧憬blog2 小时前
【Kiro开发集训营】拒绝“屎山”堆积:在 Kiro 中重构“需求-代码”的血缘关系
java·开发语言·kiro
青春:一叶知秋2 小时前
【Redis存储】List列表
数据库·redis·缓存
e***74953 小时前
Spring Security 官网文档学习
java·学习·spring
n***i953 小时前
Java NIO文件操作
java·开发语言·nio
笃行客从不躺平4 小时前
接口幂等性(Idempotency)
java
爆更小哇4 小时前
MyBatis的TypeHandler :优雅地实现数据加密与解密
数据库·后端·mybatis
Hero | 柒4 小时前
JAVA反射机制
java·spring·反射
j***63085 小时前
Springboot项目中线程池使用整理
java·spring boot·后端
likuolei5 小时前
Eclipse 创建 Java 接口
java·数据库·eclipse
q***54755 小时前
Spring Boot 经典九设计模式全览
java·spring boot·设计模式