MongoDB賬號管理及實踐
此文已由作者溫正湖授權網易雲社群釋出。
歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。
目前蜂巢(雲端計算基礎服務)MongoDB上已經有數十個例項,其中不少是企業使用者或公司內部產品使用者的。使用者多了,那就會反饋一些問題。其中一個就是MongoDB例項訪問賬號,雖能夠提供建立和刪除集合、索引,建立資料庫等使用者所需的許可權,但無法刪除資料庫,這個問題雖然不嚴重,但多少會影響使用者體驗。那麼這是為什麼呢?本文以此作為入口來談談MongoDB的賬號管理。
MongoDB作為一個成熟的資料庫,像MySQL一樣,也提供賬號管理,但又跟MySQL不大一樣,MongoDB使用基於角色的訪問許可權控制(Role-Based Access Control,RBAC),包括賬號(Users,直譯為使用者,但似乎賬號更好理解)、角色(Roles)和許可權(Privileges)三層關係。許可權指的是允許對某種資源進行的某些操作。這裡所說的資源,包括資料庫、集合和叢集等。在進行MongoDB許可權管理操作時,資源使用一個文件來表示,比如資料庫mydb下的集合mycoll作為一種資源表示為{db: "mydb", collection: "mycoll"}。{db: "mydb", collection: ""}表示資料庫mydb下的所有集合。對應地,{db: "", collection: "mycoll"}就是所有資料庫下的mycoll集合,叢集資源表示為{cluster: true},如果要將所有資料庫和叢集作為一種資源那麼可以表示為{anyResource: true}。所說的操作包括對集合的CRUD,檢視資料庫下的集合列表,檢視複製集或分片叢集當前狀態等。根據操作型別,又可以分為:讀寫操作,資料庫管理操作,叢集部署操作,複製集操作,分片叢集操作,系統管理操作,診斷操作,內部操作等8大類。
MongoDB對外提供的是賬號,作為訪問MongoDB認證單位。內部,一個賬號可以由0到多個角色組成,角色分為內建角色(Built-In Roles)和自定義角色(User-Defined Roles)。為了方便使用,MongoDB提供了多種內建角色,分為資料庫使用者,資料庫管理員,叢集管理員,備份和恢復角色,跨資料庫角色,超級使用者,內部使用者等7大類,每個大類下面有可以分為不同許可權的角色,比如資料庫使用者大類可細分為讀read和讀寫readWrite兩種角色,而每個角色擁有一定的許可權,比如readWrite角色具有建立/刪除集合、建立刪除索引和集合CRUD等16種許可權,跨資料庫角色表示該角色不僅對某個資料庫有指定的操作許可權,還對例項中其他所有(使用者建立的)的資料庫都具備同樣的許可權,比如readWriteAnyDatabase,具備對所有資料庫有readWrite許可權。這裡有個特例,就是給使用者授權角色時,如果授權時指定的資料庫是admin,則即使僅指定readWrite,也同樣具備readWriteAnyDatabase角色,也就是說對admin具有readWrite角色,那麼對其他資料庫也具有,天然具有AnyDatabase光輝。
蜂巢(雲端計算基礎服務)MongoDB提供了MongoDB複製集例項,使用者可以建立readWriteAnyDatabase許可權的賬號來訪問MongoDB,為什麼要AnyDatabase呢?因為我們還未提供MongoDB的資料庫和賬號管理功能(接管使用者所有的資料庫/集合、使用者建立和許可權管理操作),無法限制使用者建立資料庫,所以也就無法為特定某個資料庫授予readWrite許可權。readWriteAnyDatabase許可權具備了複製集場景下使用者所需的絕大部分許可權,包括集合、索引的建立和刪除,資料庫/集合等統計資訊。就像文章剛開始的描述一樣,其不具備刪除資料庫(dropDatabase)這個許可權,雖然有點坑,但還不是大問題,只需在後續提供MongoDB的資料庫和賬號管理功能中,將dropDatabase許可權納入管理即可。但在分片叢集場景下,readWriteAnyDatabase所具有的的許可權已經根本無法滿足使用者的正常操作,比如對資料庫啟用分片功能(enableSharding),人工進行分片的chunk拆分(splitChunk),在我們沒有資料庫和賬號管理功能前,這些操作都需要使用者端來執行,而readWriteAnyDatabase無法滿足。那麼是不是有其他內建角色滿足需求呢,查閱官方文件發現叢集管理員下的clusterManager角色提供了我們所需的許可權,但其還提供了諸如在分片叢集中新增和刪除分片伺服器,在複製集中進行復制集重配置等重型許可權,如果給使用者這些許可權將是非常危險的。所以,在蜂巢分片叢集例項中,無法通過為使用者提供擁有多個內建角色(如readWriteAnyDatabase、clusterManager兩個)的賬號來滿足使用者正常使用的需求。這個時候,自定義角色就派送用場了,在建立自定義角色時,既可以指定對資源的操作許可權,還可以選擇繼承另一個角色所擁有的許可權,比如,提供給使用者的新賬號繼承了readWriteAnyDatabase角色的所有許可權,還額外添加了dropDatabase、enableSharding和splitChunk等許可權,這樣一來就順利解決了面臨的問題。
關說不練假把式,結合以上的描述,演示如何為MongoDB進行賬號管理操作。
1、首先在mongod配置檔案中增加許可權相關設定 security: {authorization: enabled, keyFile: /home/mongo/keyfile}。其中authorization表示是否啟用訪問許可權認證,keyFile指定了MongoDB複製集或分片叢集內部各元件相互間通訊的認證檔案;MongoDB提供了本地例外機制,避免使用者在啟用認證前未設定賬號導致無法訪問MongoDB例項的尷尬;
2、建立使用者所需的資料庫賬號,如下:
mongos> use admin
mongos> db.createUser( { user: "myuser", pwd: "xxxxx", roles: [ { role: "readWrite", db: "admin" } ] } )
指定了認證資料庫為admin,角色採用內建的readWrite,由於指定的資料庫是admin,那麼等同於建立了readWriteAnyDatabase角色的賬號。用該賬號登陸:
use admin
db.auth("myuser","wzh123")
3、但該賬號無法執行如下這些操作:
mongos> use mydb mongos> db.dropDatabase() { "ok" : 0, "errmsg" : "not authorized on shardtest to execute command { dropDatabase: 1.0 }", "code" : 13, "codeName" : "Unauthorized" } mongos> sh.enableSharding("wzhshard") { "ok" : 0, "errmsg" : "not authorized on admin to execute command { enableSharding: \"wzhshard\" }", "code" : 13, "codeName" : "Unauthorized" }
4、所以,只能通過建立自定義角色來滿足需求,先切換到root賬號:
use admin
db.auth("root","wzh123") // root為已建立的具備超級使用者角色的管理賬號。
建立自定義角色: db.createRole({ role: "wzhRole", privileges: [{ resource: { db: "", collection: "" }, actions: ["enableSharding","dropDatabase" ] }], roles: ["readWriteAnyDatabase"] })
privileges欄位指定了該角色具有的對resource欄位所述資源具有actions欄位所述的操作許可權enableSharding和dropDatabase,同時通過roles欄位繼承了readWriteAnyDatabase的所有許可權。
5、進一步操作myuser賬號,先去掉其readWrite角色,操作如下:
db.revokeRolesFromUser( "myuser", [ { role: "readWrite", db: "admin" } ] )
確認許可權已收回:
mongos> db.getUser("myuser") { "_id" : "admin.myuser", "user" : "myuser", "db" : "admin", "roles" : [ ] }
6、為myuser增加wzhRole角色:
db.grantRolesToUser( "myuser", [ { role: "wzhRole", db: "admin" } ] )
確認許可權已經賦予:
db.getUser("myuser") { "_id" : "admin.myuser", "user" : "myuser", "db" : "admin", "roles" : [ { "role" : "wzhRole", "db" : "admin" } ] }
7、再使用myuser登陸
use admin
db.auth("myuser","wzh123")
8、執行操作:
mongos> sh.enableSharding("wzhshard") { "ok" : 1 } mongos> sh.shardCollection("wzhshard.table1",{mykey:1}) { "collectionsharded" : "wzhshard.table1", "ok" : 1 } mongos> use wzhshard switched to db wzhshard mongos> db.dropDatabase() { "dropped" : "wzhshard", "ok" : 1 }
一切看起來那麼美好!
MongoDB在許可權管理中引入了角色這一中間層,一般情況下,直接基於內建角色來建立賬號即可,有特殊需求的話,可以建立自定義角色來滿足需求,這樣一來就無需暴露繁多的具體許可權。對於新司機,更容易上手。但不足之處在於MongoDB資料庫並未像MySQL一樣未提供IP過濾功能(未提供Host欄位用來設定賬號所適用的主機IP列表)。
最後,網易資料庫團隊正在熱火朝天地調研和開發MongoDB分片叢集功能,計劃上半年在蜂巢(雲端計算基礎服務)上提供MongoDB分片叢集能力,屆時將帶給大家更加強大的文件資料庫能力。
網易雲資料庫RDS是一種穩定可靠、可彈性伸縮的線上關係型資料庫服務,當前支援MySQL引擎,提供基礎版,高可用版,金融版針對不同業務場景的高可用解決方案,同時提供多重安全防護措施,效能監控體系,專業的資料庫備份、恢復及優化方案,使您能專注於應用開發和業務發展。
參考資料:
1、https://docs.mongodb.com/manual/reference/built-in-roles
2、https://docs.mongodb.com/manual/reference/privilege-actions/
3、https://docs.mongodb.com/manual/reference/resource-document/
4、https://docs.mongodb.com/manual/core/authorization/
5、https://docs.mongodb.com/manual/core/security-user-defined-roles/
6、https://docs.mongodb.com/manual/tutorial/manage-users-and-roles/
網易雲免費體驗館,0成本體驗20+款雲產品!
更多網易技術、產品、運營經驗分享請點選。
相關文章:
【推薦】 InnoDB記錄壓縮及使用分析
【推薦】 年輕設計師如何做好商業設計