MongoDB 4.x 的權(quán)限管理說明

MongoDB是一款高性能的nosql數(shù)據(jù)庫,因?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í)是沒有啟用用戶訪問權(quán)限控制的,也就是說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模型,通過將用戶和一組角色進(jìn)行綁定,來進(jìn)行數(shù)據(jù)庫各類操作的權(quán)限控制。

角色設(shè)計(jì)

mongo對(duì)于數(shù)據(jù)庫的各項(xiàng)操作我總結(jié)抽象為以下幾類:

  • 對(duì)于數(shù)據(jù)庫數(shù)據(jù)的讀、寫操作
  • 對(duì)于數(shù)據(jù)庫管理的各類操作,例如與schema相關(guān)、索引、收集統(tǒng)計(jì)信息,對(duì)數(shù)據(jù)庫進(jìn)行清理、修改、壓縮、獲取統(tǒng)計(jì)信息、執(zhí)行檢查等操作。
  • 對(duì)于數(shù)據(jù)庫用戶和角色的管理操作,可以分配scope范圍內(nèi)的角色給指定用戶

所謂的權(quán)限管理就是對(duì)上述操作進(jìn)行各種排列組合,定義出一組角色,并且賦予給對(duì)應(yīng)的用戶。為了方便用戶使用,mongodb已經(jīng)內(nèi)置了一組角色,在絕大部分場(chǎng)景下已經(jīng)足夠用了。需要注意的是,MongoDB在每個(gè)數(shù)據(jù)庫上都提供內(nèi)置的數(shù)據(jù)庫用戶角色數(shù)據(jù)庫管理角色,但只在admin數(shù)據(jù)庫中提供其它的內(nèi)置角色。同時(shí),角色有scope(作用域)的概念,一般有指定數(shù)據(jù)庫和所有數(shù)據(jù)庫兩種。官方內(nèi)置的角色列表如下:

數(shù)據(jù)庫用戶角色(Database User Roles)

  • read:可以讀取指定數(shù)據(jù)庫中任何數(shù)據(jù)。
  • readWrite:可以讀寫指定數(shù)據(jù)庫中任何數(shù)據(jù),包括創(chuàng)建、重命名、刪除集合。

數(shù)據(jù)庫管理角色(Database Administration Roles)

  • dbAdmin:包含執(zhí)行某些管理任務(wù)(與schema相關(guān)、索引、收集統(tǒng)計(jì)信息)的權(quán)限,該角色不包含用戶和角色管理的權(quán)限。
  • dbOwner:包含對(duì)指定數(shù)據(jù)庫所有的管理操作權(quán)限。即角色readWrite、dbAdmin和userAdmin的集合。
  • userAdmin:包含對(duì)當(dāng)前數(shù)據(jù)庫創(chuàng)建和修改角色和用戶的權(quán)限。該角色允許向其它任何用戶(包括自身)授予任何權(quán)限,所以這個(gè)角色也提供間接對(duì)超級(jí)用戶(root)的訪問權(quán)限,如果限定在admin數(shù)據(jù)中,也包括集群管理的權(quán)限。

集群管理角色(Cluster Administration Roles)

此類角色僅在mongo運(yùn)行在集群模式(包含但不限于replica set或者sharded cluster)時(shí)使用,只有admin數(shù)據(jù)庫中含有這些角色:

  • clusterManager:包含對(duì)集群監(jiān)控和管理操作的權(quán)限。擁有此角色的用戶能夠訪問集群中的config數(shù)據(jù)庫和local數(shù)據(jù)庫(集群模式為sharding或者replication)。
  • clusterMonitor:clusterMonitor角色包含針對(duì)監(jiān)控工具具有只讀操作的權(quán)限。如MongoDB Cloud Manager和Ops Manager。
  • hostManager:hostManager角色包含針對(duì)數(shù)據(jù)庫服務(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ù)庫級(jí)角色(All-Database Roles)

以下角色只存在于admin數(shù)據(jù)庫,全局級(jí)別,并且適用于除了configlocal之外所有的數(shù)據(jù)庫。

  • readAnyDatabase:包含對(duì)所有數(shù)據(jù)庫的只讀權(quán)限。同時(shí)對(duì)于整個(gè)集群包含listDatabases命令操作。
  • readWriteAnyDatabase:包含對(duì)所有數(shù)據(jù)庫的讀寫權(quán)限。同時(shí)對(duì)于整個(gè)集群包含listDatabases命令操作。
  • userAdminAnyDatabase:包含類似于userAdmin角色對(duì)于所有數(shù)據(jù)庫的用戶管理權(quán)限。
  • dbAdminAnyDatabase:包含類似于dbAdmin角色對(duì)于所有數(shù)據(jù)庫管理權(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ù)庫操作都具有相應(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ù)庫進(jìn)行操作,因?yàn)镸ongoDB通過數(shù)據(jù)庫和角色名稱對(duì)角色進(jìn)行唯一標(biāo)識(shí)。

除了在admin數(shù)據(jù)庫中創(chuàng)建的角色之外,在其它數(shù)據(jù)庫中創(chuàng)建的自定義角色包含的權(quán)限只適用于角色所在的數(shù)據(jù)庫,并且只能繼承同數(shù)據(jù)庫其它角色的權(quán)限。在admin數(shù)據(jù)庫中創(chuàng)建的自定義角色則不受此限制。

MongoDB將所有的角色信息存儲(chǔ)在admin數(shù)據(jù)庫的system.roles集合中,不建議直接訪問此集合內(nè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)是沒有用戶的,首先我們先來添加一些用戶用于測(cè)試權(quán)限:

1、添加一個(gè)root用戶用于全局管理:

db.createUser(
   {
     user: "root",
     pwd: "password",     
     roles: [{"role":"root","db":"admin"}]
   }
)

2、添加一個(gè)writer用戶用于操作bocsh數(shù)據(jù)庫(也可以在認(rèn)證開啟后使用root用戶創(chuàng)建),這里我們創(chuàng)建readWrite類型的角色:

db.createUser(
   {
     user: "writer",
     pwd: "password",
     roles: [{"role":"readWrite","db":"bocsh"}]
   }
)

啟用認(rèn)證

首先要開啟mongo的用戶認(rèn)證功能,可以通過如下方式啟用:

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ù)說明,請(qǐng)參考k8s中的command和docker的entrypoint區(qū)別

啟動(dòng)數(shù)據(jù)庫以后,可以驗(yàn)證一下,執(zhí)行mongo命令連接數(shù)據(jù)庫:

$ 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)闆]有權(quán)限(匿名用戶),所以mongo直接返回了Unauthorized

權(quán)限驗(yàn)證

使用我們剛才創(chuàng)建的writer用戶登陸數(shù)據(jù)庫

$ 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ù)庫中的數(shù)據(jù),執(zhí)行show dbs也只能看到bocsh這一個(gè)數(shù)據(jù)庫,讓我們來實(shí)驗(yàn)一下使用這個(gè)用戶來創(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用戶并沒有這個(gè)角色,這是符合預(yù)期的。

接下來我們給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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容