背景
出于安全因素,數(shù)據(jù)管理員通過權(quán)限管理來保護(hù)數(shù)據(jù)普办, 防止數(shù)據(jù)庫的數(shù)據(jù)被惡意或者錯(cuò)誤刪除讯柔。數(shù)據(jù)庫基本上也提供這樣的功能藕畔。
本文的測(cè)試版本是基于mongodb 3.2.10
開啟mongodb的權(quán)限管理功能
mongodb 啟動(dòng)的時(shí)候通過--auth 參數(shù)來開啟權(quán)限管理功能。需要說明的是录语,第一次啟動(dòng)mongodb時(shí)倍啥, 數(shù)據(jù)庫里只有l(wèi)ocal 一個(gè)數(shù)據(jù)庫,而數(shù)據(jù)庫的用戶數(shù)據(jù)是存在admin數(shù)據(jù)庫的system.users collection中钦无, 因此第一次創(chuàng)建mongodb時(shí)逗栽, 數(shù)據(jù)庫管理員需要通過mongo shell 登陸到數(shù)據(jù)中創(chuàng)建管理員用戶。 在mongodb中失暂, 用戶分兩種:
- 數(shù)據(jù)庫用戶
用于操作數(shù)據(jù)庫彼宠, 比如對(duì)數(shù)據(jù)庫進(jìn)行添加、 刪除弟塞、 修改凭峡、 查找等
- 管理數(shù)據(jù)庫用戶的用戶(超級(jí)用戶)
用于添加、刪除决记、修改數(shù)據(jù)庫用戶摧冀。超級(jí)用戶的role 是UserAdmin, 后面用例子說明userAdmin 和userAdminAnyDatabase的區(qū)別
第一次啟動(dòng)和添加超級(jí)用戶
啟動(dòng)后用mongo shell 連接數(shù)據(jù)庫系宫,通過show dbs 查看索昂,并沒有admin 數(shù)據(jù)庫
[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創(chuàng)建用戶
switched to db admin
> db.createUser({user: "root", pwd: "root", roles: [{role: "userAdminAnyDatabase", db: "admin"}]}) #創(chuàng)建一個(gè)超級(jí)管理員
Successfully added user: {
"user" : "root",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
> db.system.users.find() #用戶已經(jīng)添加到數(shù)據(jù)庫中扩借, 只有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 創(chuàng)建用戶潮罪, 因此被創(chuàng)建的用戶必須在admin下驗(yàn)證康谆, 不能在其他數(shù)據(jù)庫下驗(yàn)證。
規(guī)則一:用戶是跟著數(shù)據(jù)庫走的嫉到,在那個(gè)數(shù)據(jù)庫下創(chuàng)建沃暗,就在該數(shù)據(jù)庫下驗(yàn)證
解釋下面這條語句:
db.createUser({user: "root", pwd: "root", roles: [{role: "userAdminAnyDatabase", db: "admin"}]})
user: 用戶名
pwd: 密碼
roles: 指定用戶角色, 是一個(gè)數(shù)組的數(shù)據(jù)類型何恶, 意味一個(gè)用戶可以用多個(gè)角色孽锥, 舉例說明:
db.createUser({user: "test", pwd: "test", roles: [ {role: "read", db: "test_1"},
{role: "readWrite", db: "test_2"},
]})
用戶test對(duì)test_1 數(shù)據(jù)庫用戶讀的權(quán)限, 同時(shí)對(duì)test_2數(shù)據(jù)庫有讀寫權(quán)限细层。
關(guān)閉mongodb然后加--auth參數(shù)重啟
> mongod --dbpath /home/kxing/mongodb/article --logpath /home/kxing/mongodb/article/log --port 56000 --fork --auth
添加數(shù)據(jù)庫用戶和驗(yàn)證后操作數(shù)據(jù)庫
用mongo shell 連接數(shù)據(jù)庫, 用show dbs查看會(huì)數(shù)據(jù)庫就報(bào)錯(cuò)忱叭。原因是此時(shí)數(shù)據(jù)庫已經(jīng)開啟了權(quán)限控制功能隔崎, 必須要先輸入用戶和密碼后才能查看數(shù)據(jù)庫。
[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
>
由于已經(jīng)啟動(dòng)了權(quán)限控制功能韵丑, 先要驗(yàn)證后才可以操作爵卒。
> use A
switched to db A
> db.auth("root", "root")
Error: Authentication failed. #驗(yàn)證不成功, 因?yàn)閞oot用戶是在admin下創(chuàng)建的撵彻。參考規(guī)則一
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驗(yàn)證了root用戶钓株, 但root用戶的role是
WriteResult({ #userAdminAnyDatabase, 換句話說root用戶只能添加、刪除陌僵、修改用戶轴合,
"writeError" : { #不能操作數(shù)據(jù)庫, 下一步應(yīng)該用root用戶來創(chuàng)建數(shù)據(jù)庫用戶
"code" : 13,
"errmsg" : "not authorized on A to execute command { insert: \"A\", documents: [ { _id: ObjectId('5d2d23715f5c1a61441a0222'), title: \"test authorization\" } ], ordered: true }"
}
})
下面在A數(shù)據(jù)庫下創(chuàng)建兩個(gè)用戶碗短, 一個(gè)用戶只能讀受葛, 另一個(gè)用戶可以讀寫操作。
> use admin
switched to db admin
> db.auth("root", "root") #一定要先去admin數(shù)據(jù)庫驗(yàn)證root用戶才能有權(quán)限添加用戶
> 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"
}
]
}
#創(chuàng)建用戶后偎谁, 可以在A數(shù)據(jù)庫下用show users查看當(dāng)前數(shù)據(jù)庫下有多少個(gè)用戶
> 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"
}
]
}
到此已經(jīng)創(chuàng)建了兩個(gè)用戶总滩, 但是還不能讀寫A數(shù)據(jù)庫, 還需要在A數(shù)據(jù)庫下驗(yàn)證巡雨, 想往A數(shù)據(jù)庫中插入數(shù)據(jù)闰渔, 那么我們需要驗(yàn)證write_A用戶,驗(yàn)證read_A是不能插入數(shù)據(jù)的铐望,只能讀冈涧。
> 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"
}
>
以上就是簡單的用戶創(chuàng)建和用戶驗(yàn)證操作數(shù)據(jù)庫正蛙。接下來我們看看用戶的角色(role)說明督弓。
用戶角色(role)
mongodb 有以下的內(nèi)置角色(Built-In Roles).
1. 數(shù)據(jù)庫用戶角色:read、readWrite;
2. 數(shù)據(jù)庫管理角色:dbAdmin乒验、dbOwner愚隧、userAdmin;
3. 集群管理角色:clusterAdmin徊件、clusterManager奸攻、clusterMonitor蒜危、hostManager虱痕;
4. 備份恢復(fù)角色:backup、restore辐赞;
5. 所有數(shù)據(jù)庫角色:readAnyDatabase部翘、readWriteAnyDatabase、userAdminAnyDatabase响委、dbAdminAnyDatabase
6. 超級(jí)用戶角色:root
#這里還有幾個(gè)角色間接或直接提供了系統(tǒng)超級(jí)用戶的訪問(dbOwner 新思、userAdmin窖梁、userAdminAnyDatabase)
7. 內(nèi)部角色:__system
Read:允許用戶讀取指定數(shù)據(jù)庫
readWrite:允許用戶讀寫指定數(shù)據(jù)庫
dbAdmin:允許用戶在指定數(shù)據(jù)庫中執(zhí)行管理函數(shù),如索引創(chuàng)建夹囚、刪除纵刘,查看統(tǒng)計(jì)或訪問system.profile
userAdmin:允許用戶向system.users集合寫入,可以找指定數(shù)據(jù)庫里創(chuàng)建荸哟、刪除和管理用戶
#只能在admin數(shù)據(jù)庫中用的意思是: 如果用戶的角色(role)是以下這些角色假哎, 那么db必須是admin([role: 'xxx', db: "admin"])
clusterAdmin:只在admin數(shù)據(jù)庫中可用,賦予用戶所有分片和復(fù)制集相關(guān)函數(shù)的管理權(quán)限鞍历。
readAnyDatabase:只在admin數(shù)據(jù)庫中可用舵抹,賦予用戶所有數(shù)據(jù)庫的讀權(quán)限
readWriteAnyDatabase:只在admin數(shù)據(jù)庫中可用,賦予用戶所有數(shù)據(jù)庫的讀寫權(quán)限
userAdminAnyDatabase:只在admin數(shù)據(jù)庫中可用劣砍,賦予用戶所有數(shù)據(jù)庫的userAdmin權(quán)限
dbAdminAnyDatabase:只在admin數(shù)據(jù)庫中可用惧蛹,賦予用戶所有數(shù)據(jù)庫的dbAdmin權(quán)限。
#root 角色的用戶既可以操作所有的數(shù)據(jù)庫刑枝,也可以編輯所有的用戶香嗓。
root:只在admin數(shù)據(jù)庫中可用。超級(jí)賬號(hào)仅讽,超級(jí)權(quán)限
修改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 })
登陸驗(yàn)證
- 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的區(qū)別
這里主要針對(duì)mongo shell 連接的驗(yàn)證
- userAdminAnyDatabase的用戶可以看到所有的數(shù)據(jù)庫陶缺, 也可以在任何數(shù)據(jù)庫下創(chuàng)建用戶
- userAdmin只能在admin數(shù)據(jù)庫下驗(yàn)證后創(chuàng)建admin的用戶(db: "admin")
> use admin
switched to db admin
> show users #有兩個(gè)用戶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"
}
]
}
>