MongoDB是一款高性能的nosql數(shù)據(jù)庫(kù)荞膘,因?yàn)樵跀?shù)據(jù)結(jié)構(gòu)的定義上有著極大的靈活性,所以在獲取個(gè)人信息玉工、社交網(wǎng)絡(luò)羽资、地理位置、行為日志等互聯(lián)網(wǎng)場(chǎng)景中有著廣泛的應(yīng)用遵班。默認(rèn)情況下屠升,MongoDB實(shí)例啟動(dòng)運(yùn)行時(shí)是沒(méi)有啟用用戶訪問(wèn)權(quán)限控制的,也就是說(shuō)MongoDB不會(huì)對(duì)連接客戶端進(jìn)行用戶驗(yàn)證狭郑,用戶可以以root權(quán)限執(zhí)行任何操作腹暖,這顯然在生產(chǎn)環(huán)境下是不行的,本篇文章討論MongoDB的認(rèn)證及權(quán)限控制功能的配置翰萨。
之前的一篇文章深入理解Kubernetes的認(rèn)證與授權(quán)機(jī)制其實(shí)已經(jīng)提到微服,任何系統(tǒng)的權(quán)限管理的核心是認(rèn)證和授權(quán),mongodb自然也不例外缨历。認(rèn)證方面,我們考慮最簡(jiǎn)單的用戶名密碼方式實(shí)現(xiàn)(其實(shí)mongo還支持x509證書糙麦、kerberos辛孵、LDAP等方式)。權(quán)限管理方面赡磅,mongo使用的也是rbac模型魄缚,通過(guò)將用戶和一組角色進(jìn)行綁定,來(lái)進(jìn)行數(shù)據(jù)庫(kù)各類操作的權(quán)限控制焚廊。
角色設(shè)計(jì)
mongo對(duì)于數(shù)據(jù)庫(kù)的各項(xiàng)操作我總結(jié)抽象為以下幾類:
- 對(duì)于數(shù)據(jù)庫(kù)數(shù)據(jù)的讀冶匹、寫操作
- 對(duì)于數(shù)據(jù)庫(kù)管理的各類操作,例如與schema相關(guān)咆瘟、索引嚼隘、收集統(tǒng)計(jì)信息,對(duì)數(shù)據(jù)庫(kù)進(jìn)行清理袒餐、修改飞蛹、壓縮谤狡、獲取統(tǒng)計(jì)信息、執(zhí)行檢查等操作卧檐。
- 對(duì)于數(shù)據(jù)庫(kù)用戶和角色的管理操作墓懂,可以分配scope范圍內(nèi)的角色給指定用戶
所謂的權(quán)限管理就是對(duì)上述操作進(jìn)行各種排列組合,定義出一組角色霉囚,并且賦予給對(duì)應(yīng)的用戶捕仔。為了方便用戶使用,mongodb已經(jīng)內(nèi)置了一組角色盈罐,在絕大部分場(chǎng)景下已經(jīng)足夠用了榜跌。需要注意的是,MongoDB在每個(gè)數(shù)據(jù)庫(kù)上都提供內(nèi)置的數(shù)據(jù)庫(kù)用戶角色和數(shù)據(jù)庫(kù)管理角色暖呕,但只在admin數(shù)據(jù)庫(kù)中提供其它的內(nèi)置角色斜做。同時(shí),角色有scope(作用域)的概念湾揽,一般有指定數(shù)據(jù)庫(kù)和所有數(shù)據(jù)庫(kù)兩種瓤逼。官方內(nèi)置的角色列表如下:
數(shù)據(jù)庫(kù)用戶角色(Database User Roles)
- read:可以讀取指定數(shù)據(jù)庫(kù)中任何數(shù)據(jù)。
- readWrite:可以讀寫指定數(shù)據(jù)庫(kù)中任何數(shù)據(jù)库物,包括創(chuàng)建霸旗、重命名、刪除集合戚揭。
數(shù)據(jù)庫(kù)管理角色(Database Administration Roles)
- dbAdmin:包含執(zhí)行某些管理任務(wù)(與schema相關(guān)诱告、索引、收集統(tǒng)計(jì)信息)的權(quán)限民晒,該角色不包含用戶和角色管理的權(quán)限精居。
- dbOwner:包含對(duì)指定數(shù)據(jù)庫(kù)所有的管理操作權(quán)限。即角色readWrite潜必、dbAdmin和userAdmin的集合靴姿。
- userAdmin:包含對(duì)當(dāng)前數(shù)據(jù)庫(kù)創(chuàng)建和修改角色和用戶的權(quán)限。該角色允許向其它任何用戶(包括自身)授予任何權(quán)限磁滚,所以這個(gè)角色也提供間接對(duì)超級(jí)用戶(root)的訪問(wèn)權(quán)限佛吓,如果限定在admin數(shù)據(jù)中,也包括集群管理的權(quán)限垂攘。
集群管理角色(Cluster Administration Roles)
此類角色僅在mongo運(yùn)行在集群模式(包含但不限于replica set或者sharded cluster)時(shí)使用维雇,只有admin數(shù)據(jù)庫(kù)中含有這些角色:
- clusterManager:包含對(duì)集群監(jiān)控和管理操作的權(quán)限。擁有此角色的用戶能夠訪問(wèn)集群中的config數(shù)據(jù)庫(kù)和local數(shù)據(jù)庫(kù)(集群模式為sharding或者replication)晒他。
- clusterMonitor:clusterMonitor角色包含針對(duì)監(jiān)控工具具有只讀操作的權(quán)限吱型。如MongoDB Cloud Manager和Ops Manager。
- hostManager:hostManager角色包含針對(duì)數(shù)據(jù)庫(kù)服務(wù)器的監(jiān)控和管理操作權(quán)限陨仅。
- clusterAdmin:clusterAdmin角色包含MongoDB集群管理最高的操作權(quán)限唁影。該角色包含clusterManager耕陷、clusterMonitor和hostManager三個(gè)角色的所有權(quán)限,并且還擁有dropDatabase操作命令的權(quán)限据沈。
備份和恢復(fù)角色(Backup and Restoration Roles)
- backup:包含備份MongoDB數(shù)據(jù)最小的權(quán)限哟沫。
- restore:包含從備份文件中還原恢復(fù)MongoDB數(shù)據(jù)(除了system.profile集合)的權(quán)限。
全數(shù)據(jù)庫(kù)級(jí)角色(All-Database Roles)
以下角色只存在于admin數(shù)據(jù)庫(kù)锌介,全局級(jí)別嗜诀,并且適用于除了config和local之外所有的數(shù)據(jù)庫(kù)。
- readAnyDatabase:包含對(duì)所有數(shù)據(jù)庫(kù)的只讀權(quán)限孔祸。同時(shí)對(duì)于整個(gè)集群包含listDatabases命令操作隆敢。
- readWriteAnyDatabase:包含對(duì)所有數(shù)據(jù)庫(kù)的讀寫權(quán)限。同時(shí)對(duì)于整個(gè)集群包含listDatabases命令操作崔慧。
- userAdminAnyDatabase:包含類似于userAdmin角色對(duì)于所有數(shù)據(jù)庫(kù)的用戶管理權(quán)限拂蝎。
- dbAdminAnyDatabase:包含類似于dbAdmin角色對(duì)于所有數(shù)據(jù)庫(kù)管理權(quán)限。
超級(jí)用戶角色(Superuser Roles)
- root:包含角色readWriteAnyDatabase惶室、dbAdminAnyDatabase温自、userAdminAnyDatabase、clusterAdmin皇钞、restore和backup聯(lián)合之后所有的權(quán)限悼泌。
內(nèi)部角色(Internal Role)
- __system:MongoDB將此角色授予代表集群成員的用戶對(duì)象,如副本集(replica set)成員或mongos實(shí)例夹界。該角色允許用戶對(duì)于需要的數(shù)據(jù)庫(kù)操作都具有相應(yīng)的權(quán)限馆里,不要將該角色授予應(yīng)用程序用戶或其它管理員用戶。
創(chuàng)建自定義角色
雖然MongoDB提供了一系列內(nèi)置角色可柿,但有時(shí)內(nèi)置角色所包含的權(quán)限并不滿足所有需求鸠踪,所以MongoDB也提供了創(chuàng)建自定義角色的方法。當(dāng)創(chuàng)建一個(gè)自定義角色時(shí)需要進(jìn)入指定數(shù)據(jù)庫(kù)進(jìn)行操作复斥,因?yàn)镸ongoDB通過(guò)數(shù)據(jù)庫(kù)和角色名稱對(duì)角色進(jìn)行唯一標(biāo)識(shí)营密。
除了在admin數(shù)據(jù)庫(kù)中創(chuàng)建的角色之外,在其它數(shù)據(jù)庫(kù)中創(chuàng)建的自定義角色包含的權(quán)限只適用于角色所在的數(shù)據(jù)庫(kù)永票,并且只能繼承同數(shù)據(jù)庫(kù)其它角色的權(quán)限。在admin數(shù)據(jù)庫(kù)中創(chuàng)建的自定義角色則不受此限制滥沫。
MongoDB將所有的角色信息存儲(chǔ)在admin數(shù)據(jù)庫(kù)的system.roles集合中侣集,不建議直接訪問(wèn)此集合內(nèi)容,而是通過(guò)角色管理命令來(lái)查看和編輯自定義角色兰绣。
使用下面的命令可創(chuàng)建自定義角色:
db.createRole({
"role" : "role1",
"db" : "test",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ],
"privileges" : [
{
"resource" : {
"db" : "bocsh",
"collection" : ""
},
"actions" : [
"changeStream",
"collStats",
"convertToCapped",
"createCollection",
"createIndex",
"dbHash",
"dbStats",
"dropCollection",
"dropIndex",
"emptycapped",
"find",
"insert",
"killCursors",
"listCollections",
"listIndexes",
"planCacheRead",
"remove",
"renameCollectionSameDB",
"update"
]
}
]
})
上述命令在test
這個(gè)db中創(chuàng)建了一個(gè)名為role1
的角色世分,這個(gè)角色能進(jìn)行的操作在action
中進(jìn)行了定義(可以創(chuàng)建集合,新增缀辩、修改文檔等)臭埋,可以根據(jù)自身的實(shí)際需要靈活定義踪央。
實(shí)際操作
添加用戶
mongo默認(rèn)是沒(méi)有用戶的,首先我們先來(lái)添加一些用戶用于測(cè)試權(quán)限:
1瓢阴、添加一個(gè)root用戶用于全局管理:
db.createUser(
{
user: "root",
pwd: "password",
roles: [{"role":"root","db":"admin"}]
}
)
2畅蹂、添加一個(gè)writer用戶用于操作bocsh數(shù)據(jù)庫(kù)(也可以在認(rèn)證開(kāi)啟后使用root用戶創(chuàng)建),這里我們創(chuàng)建readWrite
類型的角色:
db.createUser(
{
user: "writer",
pwd: "password",
roles: [{"role":"readWrite","db":"bocsh"}]
}
)
啟用認(rèn)證
首先要開(kāi)啟mongo的用戶認(rèn)證功能荣恐,可以通過(guò)如下方式啟用:
1液斜、在mongod啟動(dòng)命令中添加--auth
,例如:
./mongod --dbpath /data/db/ --auth
2叠穆、在配置文件中啟用安全認(rèn)證:
security:
authorization: enabled
3少漆、docker中啟用認(rèn)證:
docker run --name=mongo mongo:4.0.18 --auth
k8s中也是類似,在args字段中加入啟動(dòng)參數(shù)即可
關(guān)于docker的cmd和kubernetes的args參數(shù)說(shuō)明硼被,請(qǐng)參考k8s中的command和docker的entrypoint區(qū)別
啟動(dòng)數(shù)據(jù)庫(kù)以后示损,可以驗(yàn)證一下,執(zhí)行mongo命令連接數(shù)據(jù)庫(kù):
$ mongo
MongoDB shell version v4.2.3
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("9e273833-874e-48fa-a0e6-417ac78d041f") }
MongoDB server version: 4.2.3
> use bocsh
switched to db bocsh
> db.user.find({})
Error: error: {
"ok" : 0,
"errmsg" : "command find requires authentication",
"code" : 13,
"codeName" : "Unauthorized"
}
>
可以看到嚷硫,因?yàn)闆](méi)有權(quán)限(匿名用戶)检访,所以mongo直接返回了Unauthorized
權(quán)限驗(yàn)證
使用我們剛才創(chuàng)建的writer用戶登陸數(shù)據(jù)庫(kù)
$ mongo -u "writer" --authenticationDatabase "bocsh"
MongoDB shell version v4.2.3
Enter password:
connecting to: mongodb://127.0.0.1:27017/?authSource=bocsh&compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("b4c6e5b0-6062-4d81-a621-a8340cb9d004") }
MongoDB server version: 4.2.3
> show dbs
bocsh 0.002GB
> use bocsh
switched to db bocsh
> db.user.find({})
{ "_id" : ObjectId("5e4965d207d7692d8f29bfca"), "name" : "張三", "age" : 30, "sexy" : "male" }
{ "_id" : ObjectId("5e496600a3ae9e2e0c4f3331"), "name" : "李四", "age" : 32, "sexy" : "male" }
可以看到能夠正常查詢到bocsh數(shù)據(jù)庫(kù)中的數(shù)據(jù),執(zhí)行show dbs
也只能看到bocsh這一個(gè)數(shù)據(jù)庫(kù)论巍,讓我們來(lái)實(shí)驗(yàn)一下使用這個(gè)用戶來(lái)創(chuàng)建一個(gè)包含read
角色的用戶:
> db.createUser(
... {
... user: "reader",
... pwd: "password",
... roles: [{"role":"read","db":"bocsh"}],
...
... }
... )
2020-05-23T13:21:22.917+0800 E QUERY [js] uncaught exception: Error: couldn't add user: not authorized on bocsh to execute command { createUser: "reader", pwd: "xxx", roles: [ { role: "read", db: "bocsh" } ], digestPassword: true, writeConcern: { w: "majority", wtimeout: 600000.0 }, lsid: { id: UUID("b2c99a8f-0abf-4a3b-8336-ac09cef977c3") }, $db: "bocsh" } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1370:11
@(shell):1:1
可以看到報(bào)錯(cuò)權(quán)限不足烛谊,因?yàn)閳?zhí)行這個(gè)操作需要userAdmin
角色中包含的權(quán)限,而writer用戶并沒(méi)有這個(gè)角色嘉汰,這是符合預(yù)期的丹禀。
接下來(lái)我們給writer用戶賦予userAdmin
角色(使用之前創(chuàng)建的root用戶):
db.getSiblingDB("bocsh").updateUser(
"writer",
{
customData: {},
roles: [{ "role": "readWrite", "db": "bocsh" },
{ "role": "userAdmin", "db": "bocsh" }],
}
)
writer用戶再次執(zhí)行添加用戶操作:
> db.createUser(
... ... {
... ... user: "reader",
... ... pwd: "password",
... ... roles: [{"role":"read","db":"bocsh"}],
... ...
... ... }
... ... )
Successfully added user: {
"user" : "reader",
"roles" : [
{
"role" : "read",
"db" : "bocsh"
}
]
}
試驗(yàn)成功!
參考資料
https://www.cnblogs.com/dbabd/p/10811523.html
https://docs.mongodb.com/manual/reference/built-in-roles/#database-user-roles