背景
出于安全因素,数据管理员通过权限管理来保护数据, 防止数据库的数据被恶意或者错误删除。数据库基本上也提供这样的功能。
本文的测试版本是基于mongodb 3.2.10
开启mongodb的权限管理功能
mongodb 启动的时候通过--auth 参数来开启权限管理功能。需要说明的是,第一次启动mongodb时, 数据库里只有local 一个数据库,而数据库的用户数据是存在admin数据库的system.users collection中, 因此第一次创建mongodb时, 数据库管理员需要通过mongo shell 登陆到数据中创建管理员用户。 在mongodb中, 用户分两种:
- 数据库用户
用于操作数据库, 比如对数据库进行添加、 删除、 修改、 查找等
- 管理数据库用户的用户(超级用户)
用于添加、删除、修改数据库用户。超级用户的role 是UserAdmin, 后面用例子说明userAdmin 和userAdminAnyDatabase的区别
第一次启动和添加超级用户
启动后用mongo shell 连接数据库,通过show dbs 查看,并没有admin 数据库
[17:12 kxing@bcdev4 article] mongod --dbpath /home/kxing/mongodb/article --logpath /home/kxing/mongodb/article/log --port 56000 --fork
about to fork child process, waiting until server is ready for connections.
forked process: 112787
child process started successfully, parent exiting
[17:12 kxing@bcdev4 article]
[17:12 kxing@bcdev4 article] mongo --port 56000
MongoDB shell version: 3.2.10
connecting to: 127.0.0.1:56000/test
Server has startup warnings:
2019-07-15T17:12:29.353+0800 I CONTROL [initandlisten]
2019-07-15T17:12:29.353+0800 I CONTROL [initandlisten] ** WARNING: /proc/sys/vm/overcommit_memory is 2
2019-07-15T17:12:29.353+0800 I CONTROL [initandlisten] ** Journaling works best with it set to 0 or 1
2019-07-15T17:12:29.353+0800 I CONTROL [initandlisten]
2019-07-15T17:12:29.353+0800 I CONTROL [initandlisten] ** WARNING: soft rlimits too low. rlimits set to 8192 processes, 262144 files. Number of processes should be at least 131072 : 0.5 times number of files.
>
> show dbs
local 0.000GB
>
> use admin #先use admin, 然后再用createUser创建用户
switched to db admin
> db.createUser({user: "root", pwd: "root", roles: [{role: "userAdminAnyDatabase", db: "admin"}]}) #创建一个超级管理员
Successfully added user: {
"user" : "root",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
> db.system.users.find() #用户已经添加到数据库中, 只有role是userAdmin的用户才能添加、删除、修改用户
{
"_id" : "admin.root",
"user" : "root",
"db" : "admin",
"credentials" : {
"SCRAM-SHA-1" : {
"iterationCount" : 10000,
"salt" : "H0qjUARDao5pvIW2Uf8VrQ==",
"storedKey" : "uVRbobfJLZO/73mYAE+d7LnA1vc=",
"serverKey" : "qFQylQpcN/Bbho1MUkHD67asNys="
}
},
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
这里是先use admin后再通过createUser 创建用户, 因此被创建的用户必须在admin下验证, 不能在其他数据库下验证。
规则一:用户是跟着数据库走的,在那个数据库下创建,就在该数据库下验证
解释下面这条语句:
db.createUser({user: "root", pwd: "root", roles: [{role: "userAdminAnyDatabase", db: "admin"}]})
user: 用户名
pwd: 密码
roles: 指定用户角色, 是一个数组的数据类型, 意味一个用户可以用多个角色, 举例说明:
db.createUser({user: "test", pwd: "test", roles: [ {role: "read", db: "test_1"},
{role: "readWrite", db: "test_2"},
]})
用户test对test_1 数据库用户读的权限, 同时对test_2数据库有读写权限。
关闭mongodb然后加--auth参数重启
> mongod --dbpath /home/kxing/mongodb/article --logpath /home/kxing/mongodb/article/log --port 56000 --fork --auth
添加数据库用户和验证后操作数据库
用mongo shell 连接数据库, 用show dbs查看会数据库就报错。原因是此时数据库已经开启了权限控制功能, 必须要先输入用户和密码后才能查看数据库。
[17:35 kxing@bcdev4 article] mongo --port 56000
MongoDB shell version: 3.2.10
connecting to: 127.0.0.1:56000/test
>
> show dbs
2019-07-15T17:35:29.278+0800 E QUERY [thread1] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
"code" : 13
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:761:19
shellHelper@src/mongo/shell/utils.js:651:15
@(shellhelp2):1:1
>
由于已经启动了权限控制功能, 先要验证后才可以操作。
> use A
switched to db A
> db.auth("root", "root")
Error: Authentication failed. #验证不成功, 因为root用户是在admin下创建的。参考规则一
0
>
> use admin
switched to db admin
> db.auth("root", "root")
1
> use A
switched to db A
> db.A.insert({"title": "test authorization"}) #在admin验证了root用户, 但root用户的role是
WriteResult({ #userAdminAnyDatabase, 换句话说root用户只能添加、删除、修改用户,
"writeError" : { #不能操作数据库, 下一步应该用root用户来创建数据库用户
"code" : 13,
"errmsg" : "not authorized on A to execute command { insert: \"A\", documents: [ { _id: ObjectId('5d2d23715f5c1a61441a0222'), title: \"test authorization\" } ], ordered: true }"
}
})
下面在A数据库下创建两个用户, 一个用户只能读, 另一个用户可以读写操作。
> use admin
switched to db admin
> db.auth("root", "root") #一定要先去admin数据库验证root用户才能有权限添加用户
> use A
switched to db A
> db.createUser({user: "read_A", pwd: "read_A", roles:[{role: "read", db: "A"}]})
Successfully added user: {
"user" : "read_A",
"roles" : [
{
"role" : "read",
"db" : "A"
}
]
}
> db.createUser({user: "write_A", pwd: "write_A", roles:[{role: "readWrite", db: "A"}]})
Successfully added user: {
"user" : "write_A",
"roles" : [
{
"role" : "readWrite",
"db" : "A"
}
]
}
#创建用户后, 可以在A数据库下用show users查看当前数据库下有多少个用户
> show users;
{
"_id" : "A.read_A",
"user" : "read_A", #只读用户
"db" : "A",
"roles" : [
{
"role" : "read",
"db" : "A"
}
]
}
{
"_id" : "A.write_A",
"user" : "write_A", #读写用户
"db" : "A",
"roles" : [
{
"role" : "readWrite",
"db" : "A"
}
]
}
到此已经创建了两个用户, 但是还不能读写A数据库, 还需要在A数据库下验证, 想往A数据库中插入数据, 那么我们需要验证write_A用户,验证read_A是不能插入数据的,只能读。
> db.auth("read_A", "read_A")
1
> db.test.insert({"title": "This is a test for authorization"}) #插入不成功。
WriteResult({
"writeError" : {
"code" : 13,
"errmsg" : "not authorized on A to execute command { insert: \"test\", documents: [ { _id: ObjectId('5d2d2851f5c3c3e1771e2707'), title: \"This is a test for authorization\" } ], ordered: true }"
}
})
> db.auth("write_A", "write_A")
1
> db.test.insert({"title": "This is a test for authorization"})
WriteResult({ "nInserted" : 1 })
> db.test.find()
{
"_id" : ObjectId("5d2d2865f5c3c3e1771e2708"),
"title" : "This is a test for authorization"
}
>
以上就是简单的用户创建和用户验证操作数据库。接下来我们看看用户的角色(role)说明。
用户角色(role)
mongodb 有以下的内置角色(Built-In Roles).
1. 数据库用户角色:read、readWrite;
2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
4. 备份恢复角色:backup、restore;
5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
6. 超级用户角色:root
#这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)
7. 内部角色:__system
Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
#只能在admin数据库中用的意思是: 如果用户的角色(role)是以下这些角色, 那么db必须是admin([role: 'xxx', db: "admin"])
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
#root 角色的用户既可以操作所有的数据库,也可以编辑所有的用户。
root:只在admin数据库中可用。超级账号,超级权限
修改role
append role to user
db.grantRolesToUser("read_or_write", [{role: "readWrite", db: "A"}])
remove role from user
db.revokeRolesFromUser("read_or_write", [ {role: "readWrite", db: "A"}])
update user's role
db.updateUser("read_or_write", { roles: [ {role: "readWrite", db: "A"}]})
> use A
switched to db A
> db.createUser({user:"read_or_write", pwd: "read", roles: [{role: "read", db: "A"}]})
Successfully added user: {
"user" : "read_or_write",
"roles" : [
{
"role" : "read",
"db" : "A"
}
]
}
> db.auth("read_or_write", "read")
1
> show tables
test
> db.test.find()
{
"_id" : ObjectId("5d2d2865f5c3c3e1771e2708"),
"title" : "This is a test for authorization"
}
...
> db.test.insert({"title": "hello world"})
WriteResult({
"writeError" : {
"code" : 13,
"errmsg" : "not authorized on A to execute command { insert: \"test\", documents: [ { _id: ObjectId('5d2d88c5f5c3c3e1771e270d'), title: \"hello world\" } ], ordered: true }"
}
})
> db.grantRolesToUser("read_or_write", [{role: "readWrite", db: "A"}])
> show users
{
"_id" : "A.read_or_write",
"user" : "read_or_write",
"db" : "A",
"roles" : [
{
"role" : "readWrite",
"db" : "A"
},
{
"role" : "read",
"db" : "A"
}
]
}
> db.test.insert({"title": "hello world"})
WriteResult({ "nInserted" : 1 })
> db.revokeRolesFromUser("read_or_write", [ {role: "readWrite", db: "A"}])
> show users
{
"_id" : "A.read_or_write",
"user" : "read_or_write",
"db" : "A",
"roles" : [
{
"role" : "read",
"db" : "A"
}
]
}
> db.test.insert({"title": "hello world"})
WriteResult({
"writeError" : {
"code" : 13,
"errmsg" : "not authorized on A to execute command { insert: \"test\", documents: [ { _id: ObjectId('5d2d9198f5c3c3e1771e2710'), title: \"hello world\" } ], ordered: true }"
}
})
> db.updateUser("read_or_write", { roles: [ {role: "readWrite", db: "A"}]})
> show users
{
"_id" : "A.read_or_write",
"user" : "read_or_write",
"db" : "A",
"roles" : [
{
"role" : "readWrite",
"db" : "A"
}
]
}
> db.test.insert({"title": "hello world"})
WriteResult({ "nInserted" : 1 })
> db.test.find()
{
"_id" : ObjectId("5d2d2865f5c3c3e1771e2708"),
"title" : "This is a test for authorization"
}
...
>
自定义role
db.createRole({role: "custonRole", privileges: [{resource:{db:"A", collection:"test"}, actions:["find"]}],roles:[]})
> show users
{
"_id" : "A.read_or_write",
"user" : "read_or_write",
"db" : "A",
"roles" : [
{
"role" : "read",
"db" : "A"
}
]
}
> db.test.insert({"title": "hello world"})
WriteResult({
"writeError" : {
"code" : 13,
"errmsg" : "not authorized on A to execute command { insert: \"test\", documents: [ { _id: ObjectId('5d2d95fcf5c3c3e1771e2711'), title: \"hello world\" } ], ordered: true }"
}
})
> db.createRole({role: "customRole_2", privileges: [{resource:{db:"A", collection:"test"}, actions:["find", "insert"]}],roles:[]})
{
"role" : "customRole_2",
"privileges" : [
{
"resource" : {
"db" : "A",
"collection" : "test"
},
"actions" : [
"find",
"insert"
]
}
],
"roles" : [ ]
}
> db.updateUser("read_or_write", { roles: [ {role: "customRole_2", db: "A"}]})
> db.test.insert({"title": "hello world"})
WriteResult({ "nInserted" : 1 })
> show users
{
"_id" : "A.read_or_write",
"user" : "read_or_write",
"db" : "A",
"roles" : [
{
"role" : "customRole_2",
"db" : "A"
}
]
}
>
db.createUser({user:"write", pwd: "write", roles:[{role: "readWrite", db: "A"}]})
Successfully added user: {
"user" : "write",
"roles" : [
{
"role" : "readWrite",
"db" : "A"
}
]
}
> db.auth("write", "write")
1
> db.Person.insert({"name": "kxing"})
WriteResult({ "nInserted" : 1 })
> show tables
Person
test
> db.auth("read_or_write", "read")
1
> db.Person.insert({"name": "kxing"})
WriteResult({
"writeError" : {
"code" : 13,
"errmsg" : "not authorized on A to execute command { insert: \"Person\", documents: [ { _id: ObjectId('5d2d978cf5c3c3e1771e2715'), name: \"kxing\" } ], ordered: true }"
}
})
> db.test.insert({"name": "kxing"})
WriteResult({ "nInserted" : 1 })
登陆验证
- mongo shell 登陆
mongo --port 27017 -u manager -p 12345678 --authenticationDatabase admin
- mongo-c-driver 登陆
mongoc_client_t *client = mongoc_client_new ("mongodb://user:password@localhost/?authSource=mydb");
userAdmin 和 userAdminAnyDatabase的区别
这里主要针对mongo shell 连接的验证
- userAdminAnyDatabase的用户可以看到所有的数据库, 也可以在任何数据库下创建用户
- userAdmin只能在admin数据库下验证后创建admin的用户(db: "admin")
> use admin
switched to db admin
> show users #有两个用户root 和 uad, role 分别是userAdminAnyDatabase和userAdmin
{
"_id" : "admin.root",
"user" : "root",
"db" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
{
"_id" : "admin.uad",
"user" : "uad",
"db" : "admin",
"roles" : [
{
"role" : "userAdmin",
"db" : "admin"
}
]
}
> db.auth("uad", "uad")
1
> show dbs
2019-07-16T16:00:03.763+0800 E QUERY [thread1] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
"code" : 13
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:761:19
shellHelper@src/mongo/shell/utils.js:651:15
@(shellhelp2):1:1
> db.auth("root", "root")
1
> show dbs
A 0.000GB
B 0.000GB
admin 0.000GB
local 0.000GB
>
> use A
switched to db A
> show users
{
"_id" : "A.write_A",
"user" : "write_A",
"db" : "A",
"roles" : [
{
"role" : "readWrite",
"db" : "A"
}
]
}
{
"_id" : "A.write_B",
"user" : "write_B",
"db" : "A",
"roles" : [
{
"role" : "readWrite",
"db" : "B"
}
]
}
> db.createUser({user:"read", pwd: "read", roles: [{role: "read", db: "A"}]})
Successfully added user: { "user" : "read", "roles" : [ { "role" : "read", "db" : "A" } ] }
> use admin
switched to db admin
> db.auth("uad", "uad")
1
> use A
switched to db A
> db.createUser({user:"read_1", pwd: "read_1", roles: [{role: "read", db: "A"}]})
2019-07-16T16:02:43.644+0800 E QUERY [thread1] Error: couldn't add user: not authorized on A to execute command { createUser: "read_1", pwd: "xxx", roles: [ { role: "read", db: "A" } ], digestPassword: false, writeConcern: { w: "majority", wtimeout: 30000.0 } } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1267:15
@(shell):1:1
> use admin
switched to db admin
> db.createUser({user:"read_1", pwd: "read_1", roles: [{role: "read", db: "A"}]})
2019-07-16T16:02:57.852+0800 E QUERY [thread1] Error: couldn't add user: not authorized on admin to execute command { createUser: "read_1", pwd: "xxx", roles: [ { role: "read", db: "A" } ], digestPassword: false, writeConcern: { w: "majority", wtimeout: 30000.0 } } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1267:15
@(shell):1:1
> show users
{
"_id" : "admin.root",
"user" : "root",
"db" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
{
"_id" : "admin.uad",
"user" : "uad",
"db" : "admin",
"roles" : [
{
"role" : "userAdmin",
"db" : "admin"
}
]
}
> db.auth("uad", "uad")
1
> db.createUser({user:"read_1", pwd: "read_1", roles: [{role: "read", db: "A"}]})
2019-07-16T16:03:37.790+0800 E QUERY [thread1] Error: couldn't add user: not authorized on admin to execute command { createUser: "read_1", pwd: "xxx", roles: [ { role: "read", db: "A" } ], digestPassword: false, writeConcern: { w: "majority", wtimeout: 30000.0 } } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1267:15
@(shell):1:1
> db.createUser({user:"read_1", pwd: "read_1", roles: [{role: "read", db: "admin"}]})
Successfully added user: {
"user" : "read_1",
"roles" : [
{
"role" : "read",
"db" : "admin"
}
]
}
>