20 KiB
title | date | author | tags | categories | ||
---|---|---|---|---|---|---|
MongoDB 安全认证 | 2021-01-10 | ac |
|
|
MongoDB
的安全认证
安全认证
1.用户和角色权限简介
默认情况下,MongoDB
实例启动运行时是没有启用用户访问权限控制的,也就是说,在实例本机服务器上都可以随意连接到实例进行各种操作,MongoDB
不会对连接客户端进行用户验证,这是非常危险的。
MongoDB
官网上说,为了能保障MongoDB
的安全可以做以下几个步骤:
- 使用新的端口,默认的
27017
端口。 - 设置
MongoDB
的网络环境,最好将mongodb部署到公司服务器内网。 - 开启安全认证。认证要同时设置服务器之间的内部认证方式,同时要设置客户端连接到集群的账号密码认证方式。
为了强制开启用户访问控制(用户验证),则需要在MongoDB
实例启动时使用选项--auth
或在指定的启动文件中添加选项auth=true
。
在开始之前需要了解的概念
-
启用访问控制
MongoDB
使用的是基于角色的访问控制(Role-Based Access Control
,RBAC
)来管理用户对实例的访问。通过对用户授予一个或多个角色来控制用户访问数据库资源的权限和数据库操作的权限,在对用户分配角色之前,用户无法访问实例。 -
角色
在
MongoDB
中通过角色对用户授予相应数据库资源的操作权限,每个角色当中的权限可以显示指定,也可以通过继承其他角色的权限,或者两者都存在的权限。 -
权限
权限由指定的数据库资源(resource)以及允许在指定资源上进行的操作(action)组成。
- 资源(resource):数据库、集合、部分集合和集群;
- 操作(action):对资源进行的增删改查(CRUD)操作
在角色定义时可以包含一个或多个已经存在的角色,新创建的角色会继承包含的角色所有的权限。在同一个数据库中新创建角色可以继承其他角色的权限,在admin
数据库中创建的角色可以继承在其它任意数据库中角色的权限。
常用的内置角色:
- 数据库用户角色:
read
、readWrite
; - 所有数据库用户角色:
readAnyDatabase
、readWriteAnyDatabase
、userAdminAnyDatabase
、dbAdminAnyDatabase
; - 数据库管理角色:
dbAdmin
、dbOwner
、userAdmin
; - 集群管理角色:
clusterAdmin
、clusterManager
、clusterMonitor
、hostManager
; - 备份恢复角色:
backup
、restore
; - 超级用户角色:
root
; - 内部角色:
system
关于角色权限的查看:
# 查询所有角色权限(仅用户自定义角色)
db.runCommand({rolesInfo:1})
#查询所有角色权限(包含内置角色)
db.runCommand({rolesInfo:1,showBuiltinRoles:true})
#查询当前数据库的某角色的权限
db.runCommand({rolesInfo:"<rolename>"})
#查询其他数据库中指定的角色权限
db.runCommand({rolesInfo:{role:"<rolename>",db:"<database>"}})
角色说明
角色 | 权限描述 |
---|---|
read |
可以读取指定数据库中任何数据。 |
readWrite |
可以读写指定数据库中任何数据,包括创建、重命名、删除集合 |
readAnyDatabase |
可以读取所有数据库中任何数据(除了数据库config 和local 之外) |
userAdminAnyDatabase |
可以在指定数据库创建和修改用户(除了数据库config 和local 之外) |
readWriteAnyDatabase |
可以读写所有数据库中任何数据(除了数据库config 和local 之外) |
dbAdminAnyDatabase |
可以读取任何数据库以及对数据库进行清理、修改、压缩、获取统计信息、执行检查等操作(除了数据库config 和local 之外) |
dbAdmin |
可以读取指定数据库以及对数据库进行清理、修改、压缩、获取统计信息、执行检查等操作。 |
userAdmin |
可以在指定数据库创建和修改用户。 |
clusterAdmin |
可以对整个集群或数据库系统进行管理操作。 |
backup |
备份MongoDB 数据最小的权限。 |
restore |
从备份文件中还原恢复MongoDB 数据(除了system.profile 集合)的权限。 |
root |
超级账号,超级权限 |
2.单实例环境
对单实例的
MongoDB
服务开启安全认证,这里的单实例指的是未开启副本集或分片的MongoDB
实例
关闭已开启的服务(可选)
增加mongod
的单实例的安全认证功能,可以在服务搭建的时候直接添加,也可以在之前搭建好的服务上添加。
这里使用之前搭建好的服务,因此,先停止之前的服务。
关闭服务有两种方式:
-
快速关闭:使用
kill
命令直接杀死进程#通过进程编号关闭节点 kill -2 进程号
-
标准关闭:通过
mongo
个客户端中的shutdownServer
命令来关闭服务#客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。 mongo --port 27017 #切换到admin库 use admin #如果不是admin数据库,则会报如下错误 shutdown command only works with the admin database; try 'use admin' #关闭服务 db.shutdownServer()
必须是在
admin
库下执行该关闭命令;如果没有开启认证,必须是从
localhost
登陆才能执行关闭服务命令;非
localhost
的、通过远程登陆的,必须登陆且必须登陆用户有对admin
操作权限才可以。
添加用户权限
-
先按照普通无授权认证的配置,来配置服务端的配置文件
/mongodb/single/mongod.conf
systemLog: destination: file path: "/home/qiusj/.local/mongodb/singlesite/log/mongod.log" logAppend: true storage: dbPath: "/home/qiusj/.local/mongodb/singlesite/data/db" journal: enabled: true net: #添加本机在局域网内的ip bindIp: 127.0.0.1,192.168.0.152 port: 27017 setParameter: enableLocalhostAuthBypass: false processManagement: fork: true pidFilePath: "/home/qiusj/.local/mongodb/singlesite/log/mongod.pid"
-
按照之前未开启认证的方式(不添加
--auth
参数)来启动MongoDB
服务:qiusj@u20:~$ /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/singlesite/mongod.conf
-
使用
Mongo
客户端登陆qiusj@u20:~$ /usr/local/mongodb/bin/mongo --port=27017
-
创建两个管理员用户,一个系统的超级管理员
myroot
,一个是admin
库的管理员用户myadmin
:#切换到admin库 > use admin switched to db admin #创建系统超级用户myroot,密码123456,角色root #> db.createUser({user:"myroot",pwd:"123456",roles:[{"role":"root","db":"admin"}]}) > db.createUser({user:"myroot",pwd:"123456",roles:["root"]}) Successfully added user: { "user" : "myroot", "roles" : [ "root" ] } #创建专门用来管理admin库的账号myadmin,只用来作为用户权限的管理 > db.createUser({user:"myadmin",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]}) Successfully added user: { "user" : "myadmin", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } #查看已经创建了的用户的情况 > db.system.users.find() { "_id" : "admin.myroot", "userId" : UUID("9ae2bb4d-d289-4135-884f-2082cb6b20aa"), "user" : "myroot", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "I2oNFoKRK0ktT9pM4to5fw==", "storedKey" : "Nxuoez/RCQ1AeyQxF2FKEyTsopE=", "serverKey" : "L740F4turO7raGtNr92H1GoRErk=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "iZ7PX1mFDZdCKwyOIrvyvLW7SywqR8sJANp+SA==", "storedKey" : "ngkeL6kE94IKXuuHjjSZjo87fo4yZ3ivxGeFsWK0/V4=", "serverKey" : "SpcYUVj+J3ZO3Iv3SU4AOx9POmWc7bc2WLreAxFtypI=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] } { "_id" : "admin.myadmin", "userId" : UUID("4a901dd2-75ce-4ea4-ab2e-5c06de29ba20"), "user" : "myadmin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "eCn7OmqaJHgX4kxGij2eew==", "storedKey" : "qXWbRh5vgKQJQ4Ri4in1W7KyTq0=", "serverKey" : "tattdTXuWm2wsozuaWgtZgn2I4M=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "z3gBxcUUIgV4BjZk1RPWkjWHlDZF6r5ZDcSV6A==", "storedKey" : "2oQpybEAs0mdvNTZnIuKA3hVRHJxKcR6UZXq6At/fkg=", "serverKey" : "cMuUfnaDScuIJOQ4Y/g2y/1s/1W7FZNrM8T9H/pMbAI=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
-
用户相关操作
#删除用户 > db.dropuser("myadmin") #修改密码 > db.changeUserPassword("myroot","123456") #认证测试 > db.auth("myroot","123456") 1
和其他数据库一样,权限的管理都差不多一样,也是将用户和权限信息保存在数据库对应的表中。MongoDB
存储所有用户信息在admin
数据库中的system.users
集合中,保存着用户名、密码和数据库信息。
如果不指定数据库,则创建的指定的权限的用户在所有的数据库上有效。如{role:"userAdmin",db:""}
-
创建普通用户
创建普通用户可以在没有开启认证的时候添加,也可以在开启认证后添加,但开启之后,必须使用有操作
admin
库的用户登录认证后才能操作。底层都是将用户信息保存在admin
数据库的system.users
集合中> use meface > db.createUser({user:"star",pwd:"star",roles:[{role:"readWrite",db:"meface"}]}) Successfully added user: { "user" : "star", "roles" : [ { "role" : "readWrite", "db" : "meface" } ] } > db.auth("star","star") 1
如果开启了认证,登陆的客户端的用户必须使用
admin
库的角色,如果拥有root
劫色的myadmin
用户,再通过myadmin
用户去创建其他角色的用户。
服务端开启认证和客户端连接登陆
有两种方式开启权限认证启动服务:参数方式、配置文件方式
-
参数方式
在启动时指定参数
--auth
,示例:/usr/local/mongodb/bin/mongd -f /mongodb/single/mongod.conf --auth
-
配置文件方式
在
mongod.conf
配置文件中加入:security: #开启授权认证 authorization: enabled
启动时可以不加
--auth
参数
开启了认证的情况下的客户端登陆,有两种方式:先连接再登陆、登陆时直接认证
-
开启认证后再登陆,如查询
admin
库中的system.user
集合的用户:> use admin switched to db admin > db.auth("myadmin","123456") 1 > db.system.users.find()
查询
meface
库中的article
集合的内容:> use meface switched to db meface > db.article.find() Error: error: { "ok" : 0, "errmsg" : "not authorized on meface to execute command { find: \"article\", filter: {}, lsid: { id: UUID(\"a2215a94-d86a-4bdc-bdef-1e62033aee89\") }, $db: \"meface\" }", "code" : 13, "codeName" : "Unauthorized" }
需要退出来,再使用
star
用户去操作> exit bye qiusj@u20:~$ /usr/local/mongodb/bin/mongo --port=27017 > db.auth("star","star") Error: Authentication failed. 0 > use meface switched to db meface > db.auth("star","star") 1 > db.article.find()
-
登陆时直接认证:
/usr/local/mongodb/bin/mongo --port=27017 --username=star --password=star --authenticationDatabase=meface
qiusj@u20:~$ /usr/local/mongodb/bin/mongo --port=27017 --username=star --password=star --authenticationDatabase=meface MongoDB shell version v4.4.2 connecting to: mongodb://127.0.0.1:27017/?authSource=meface&compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("0cabba54-185e-4332-a8f8-2a1b1b8753a3") } MongoDB server version: 4.4.2 > db test > use meface switched to db meface > db.article.find() { "_id" : ObjectId("5fed2b1b232584d8ba357db0"), "articleid" : "100000", "content" : "今天天气真好,阳光明 媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2020-12-31T01:36:27.784Z"), "likenum" : 10, "state" : null } { "_id" : "1", "likenum" : 1001 } { "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 666, "state" : "1" } { "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船 长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" } { "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "小李", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" } { "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "小李", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" } >
Compass连接认证
mongodb://star:star@192.168.0.152:27017/?authSource=meface
SpringData
连接认证
使用用户名和密码连接到MongoDB
服务器,必须使用username:password@hostname/dbname
格式。
application.yml
spring:
#数据源配置
data:
mongodb:
#连接分片集群的路由节点,多个路由用逗号分隔,mongodb会有其负载均衡的策略
# uri: mongodb://192.168.0.152:27017,192.168.0.152:27117/meface
# host: 192.168.0.152
# database: meface
# port: 27017
#使用uri的方式
# uri:mongodb://192.168.0.152:27017/meface
uri: mongodb://star:star@192.168.0.152:27017/meface
3.副本集环境
对于搭建好的mongodb
副本集,为了安全,启动安全认证,使用账号密码登陆。
副本集环境使用之前搭建好的,架构如下:
先通过主节点增加一个管理员账号
在开启认证之前,创建超管用户:myroot/123456
只需要在主节点上添加用户,副本集会自动同步。
myrs:PRIMARY> use admin
switched to db admin
myrs:PRIMARY> db.createUser({user:"myroot",pwd:"123456",roles:[{role:"root",db:"admin"}]})
Successfully added user: {
"user" : "myroot",
"roles" : [
{
"role" : "root",
"db" : "admin"
}
]
}
关闭副本集
主节点必须最后一个成员关闭义避免潜在的回滚。
$ ps -ef|grep mongo
qiusj 4004546 1 0 10:38 ? 00:00:02 /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/replica_sets/myrs_27017/mongod.conf
qiusj 4004640 1 0 10:38 ? 00:00:02 /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/replica_sets/myrs_27018/mongod.conf
qiusj 4004739 1 0 10:38 ? 00:00:01 /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/replica_sets/myrs_27019/mongod.conf
qiusj 4006158 3989038 0 10:45 pts/1 00:00:00 grep --color=auto mongo
$ kill -2 4004640 4004739 4004546
创建副本集认证的key文件
第一步:生成一个key文件到当前文件夹中。
可以使用任何方法生成密钥文件。例如,以下操作使用openssl
生成加密文件,然后使用chmod
来更改文件权限,仅为文件所有者提供读取权限。
# 查看安装的ssl版本
qiusj@u20:~$ openssl version -a
OpenSSL 1.1.1f 31 Mar 2020
qiusj@u20:~$ openssl rand -out /home/qiusj/.local/mongodb/mongo.keyfile -base64 90
所有副本集节点都必须要用同一份
keyfile
,一般是在一台机器上生成,然后拷贝到其他机器上,且必须有读取权限,否则将来会报错。
一定要保证密钥文件一致,文件位置随便。
第二步:将生成的加密文件拷贝到节点的目录下
$ cp mongo.keyfile /home/qiusj/.local/mongodb/replica_sets/myrs_27017
$ cp mongo.keyfile /home/qiusj/.local/mongodb/replica_sets/myrs_27018
$ cp mongo.keyfile /home/qiusj/.local/mongodb/replica_sets/myrs_27019
第三步:修改加密文件的权限
$ ll
-rw-r--r-- 1 qiusj intplanet 122 1月 21 17:44 mongo.keyfile
#如果这种权限启动服务会报错:“permissions on ../mongo.keyfile are too open”当前加密文件的权限过大
#修改成只对当前用户只读
$ chmod 400 ./mongo.keyfile
-r-------- 1 qiusj intplanet 122 1月 21 17:44 mongo.keyfile
修改配置文件指定keyfile
分别编辑几个服务的mongod.conf
文件,添加相关内容:
$ vi /home/qiusj/.local/mongodb/replica_sets/myrs_27017/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /home/qiusj/.local/mongodb/replica_sets/myrs_27017/mongo.keyfile
# 开启认证方式
authorization: enabled
security:
# KeyFile鉴权文件
keyFile: /home/qiusj/.local/mongodb/replica_sets/myrs_27018/mongo.keyfile
# 开启认证方式
authorization: enabled
security:
# KeyFile鉴权文件
keyFile: /home/qiusj/.local/mongodb/replica_sets/myrs_27019/mongo.keyfile
# 开启认证方式
authorization: enabled
启动副本集
如果副本集是开启状态,则分别关闭副本集中的每个mongod
进程,从次节点开始,直到副本集的所有成员都离线,包括仲裁者。主节点必须最后一个成员关闭义避免潜在的回滚。
分别启动副本集节点:
$ /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/replica_sets/myrs_27017/mongod.conf
$ /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/replica_sets/myrs_27018/mongod.conf
$ /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/replica_sets/myrs_27019/mongod.conf
$ /usr/local/mongodb/bin/mongo --port=27017
在主节点上添加普通账号
myrs:PRIMARY> use admin
switched to db admin
myrs:PRIMARY> db.auth("myroot","123456")
1
myrs:PRIMARY> show dbs
admin 0.000GB
article 0.000GB
config 0.000GB
local 0.002GB
#切换到article库
myrs:PRIMARY> use article
switched to db article
#创建操作article库的普通用户moon
myrs:PRIMARY> db.createUser({user:"moon",pwd:"moon",roles:[{role:"readWrite",db:"article"}]})
Successfully added user: {
"user" : "moon",
"roles" : [
{
"role" : "readWrite",
"db" : "article"
}
]
}
SpringData连接副本集
使用用户名和密码连接到MongoDB服务器,必须使用username:password@hostname/dbname
格式
application.yml
spring:
#数据源配置
data:
mongodb:
#连接分片集群的路由节点,多个路由用逗号分隔,mongodb会有其负载均衡的策略
# uri: mongodb://192.168.0.152:27017,192.168.0.152:27117/meface
# host: 192.168.0.152
# database: meface
# port: 27017
#使用uri的方式
# uri:mongodb://192.168.0.152:27017/meface
#开启安全认证后的单机连接uri
# uri: mongodb://star:star@192.168.0.152:27017/meface
#开启安全认证后的副本集连接uri
uri: mongodb://moon:moon@192.168.0.152:27017,192.168.0.152:27018,192.168.0.152:27019/article?connect=replicaSet&slaveOk=true&replicaSet=myrs
参考文章
[1] Replication
https://docs.mongodb.com/manual/replication/
[2] Sharding
https://docs.mongodb.com/manual/sharding/
[3] Sharding reference
https://docs.mongodb.com/manual/reference/sharding/
[4] Security Reference
https://docs.mongodb.com/manual/reference/security/