您好,登錄后才能下訂單哦!
對于一個完善的數據庫系統,必然是需要權限控制,當然mongodb也不例外.沒有認證的數據庫已經被證明是******的一個突破口,所以我們無論是出于什么原因,數據庫認證對于一個生產系統而言,至關重要.
在MongoDB 3.0 以后,用戶登錄的密碼認證機制有:SCRAM-SHA-1(默認,基于加鹽的應答式認證),MONGODB-CR(普通應答式認證,3.6廢棄,4.0刪除),x.509 Certificate(基于證書的SSL/TLS加密認證),LDAP Proxy(基于LDAP系統的鑒權認證,僅企業版支持),Kerberos(基于Kerberos鑒權,僅企業版支持),一般而言,默認的就已經很不錯了.
然后mongodb還有一個內部鑒權策略,主要是防止數據被攔截,有:keyfile(基于SCRAM的應答式認證),x.509 Certificate(基于證書的SSL/TLS加密),對于內部來說,如非特殊情況,使用keyfile就足夠了.
對單臺數據庫增加mongodb認證信息(基本認證知識)
首先要講一講的是,mongodb本身并沒有要求一定要認證登錄,也就是免認證直接登錄是允許的,不過出于安全考慮的話,我們應該更加嚴謹一些,增加認證登錄來使用,但是mongodb又不同于mysql和oracle的授權方式,比較奇怪.下面來看.
首先,也是要打開參數
#打開配置文件 vim /usr/local/mongodb/mongod_data_40001.conf . . . #是否開啟認證模式,現在開啟來使用 auth = true #關閉認證模式,和上面的沖突,之前是開啟的,現在關閉了 #noauth = true #指定集群認證文件,沒開認證就不用指定,注釋關閉即可,需要用openssl來生成,暫時不研究 #keyFile = /data/mongodb/data/keyfile #指定訪問地址,3.4之前默認全網,之后則默認是127.0.0.1,但是在3.6之后必須制定這個參數才能啟動.配置0.0.0.0代表全網匹配 #bind_ip=0.0.0.0
參數打開了,需要重啟一下登錄
#登錄進去操作 mongo -port=40001 MongoDB shell version v3.4.16-rc0 connecting to: mongodb://127.0.0.1:40001/ MongoDB server version: 3.4.16-rc0 #操作一下 > show dbs 2018-07-17×××5:04:34.009+0800 E QUERY [thread1] Error: listDatabases failed:{ "ok" : 0, "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }", "code" : 13, "codeName" : "Unauthorized" } : _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:788:19 shellHelper@src/mongo/shell/utils.js:678:15 @(shellhelp2):1:1 >
好像報錯了,但是請淡定,這是正常現象,因為之前默認是免認證,現在開啟了認證,你又沒創建用戶,那肯定是報錯的,不過不用擔心,因為你原本是沒用戶密碼的,所以是可以新建的.
但是要注意,在初始無賬戶密碼狀態下,只能通過登錄127.0.0.1這個地址你才能創建用戶和密碼,所以就需要注意參數bind_ip的值了.
#進入admin數據庫,也是當前用戶認證庫 > use admin switched to db admin #授權 > db.createUser({user:"adminuser",pwd:"admin123",roles:[{role:"userAdminAnyDatabase",db:"admin"}]}) Successfully added user: { "user" : "adminuser", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } #再創建多一個試試 > db.createUser({user:"root",pwd:"root123",roles:[{role:"root",db:"admin"}]}) 2018-07-17×××5:05:04.167+0800 E QUERY [thread1] Error: couldn't add user: not authorized on admin to execute command { createUser: "root", pwd: "xxx", roles: [ { role: "root", db: "admin" } ], digestPassword: false, writeConcern: { w: "majority", wtimeout: 600000.0 } } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 DB.prototype.createUser@src/mongo/shell/db.js:1292:15 @(shell):1:1 >
又報錯了?沒錯,這個時候你已經有用戶了,所以就拒絕你的操作了,你要先認證一下你自己剛建好的用戶了
#認證一下你剛才創建的用戶 > db.auth("adminuser","admin123") 1 > use admin switched to db admin #再次創建用戶 > db.createUser({user:"root",pwd:"root123",roles:[{role:"root",db:"admin"}]}) Successfully added user: { "user" : "root", "roles" : [ { "role" : "root", "db" : "admin" } ] } > db.auth("root","root123") 1 > show dbs admin 0.000GB local 0.000GB >
這次沒問題了,解決了問題,要想創建更多用戶,甚至細化到個別數據庫來創建用戶,你可以這樣:
use foo; db.createUser({user: 'foo', pwd: 'bar', roles: [{role: 'readWrite', db: 'foo'}]}) db.auth('foo', 'bar')
這里就涉及一個mongodb特別的知識點---認證庫的概念.
mongodb和別的數據庫不同,認證的信息是細化到庫的,而并不是像mysql,oracle,sql server那樣集中管理,都存放到一個user表.
不同數據庫的用戶可以存放到不同的數據庫,例如:foo庫的用戶foo只存放在foo庫里面,他不能登錄admin庫,在admin庫里面是沒有foo用戶信息.同理,admin庫的用戶root是不存在于foo庫的,但是root用戶是能登陸foo的,原因是root用戶的權限更大一些(廢話).但是,你如果把foo庫刪除了,那么foo用戶也會"順便"被一起刪除了,也就是這個用戶和這個庫也徹底不再了.
所以我們有兩種不同的理念,基于方便管理的概念來說,我們應該集中管理,對于認證庫這個概念,我們的思路應該把它們都建立在admin庫更佳,然后再細分權限,刪除庫有時候可以只是刪除登錄用戶就可以了.基于安全考慮問題,我們不能讓一些廢棄用戶存在,因為mongodb的特性是沒有create動作,只要有權限,就可以自動創建庫和表的.
然后還有第二個mongodb的知識點---角色權限管理
mongodb創建的用戶是按role角色來區分權限的,跟我們熟悉的oracle和sql server相似(mysql8.0后才支持角色管理),這點倒不是特別了.至于有什么role選擇呢,你可以show roles看看.我們主要常用的有全局超級管理員userAdminAnyDatabase(也是我們第一個需要創建的用戶權限),readWriteAnyDatabase,readWrite,readAnyDatabase,read,root等.
每一個角色代表著有不同的權限集合,可以細化到每個用戶的權限范圍,例如read就只能find查詢,readWrite就是典型的增刪查改了,還有我們熟悉的root就是完全控制權限了.
mongos> show roles { "role" : "__system", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "backup", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { . . . } { "role" : "read", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "readAnyDatabase", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "readWrite", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "readWriteAnyDatabase", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "restore", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "root", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "userAdmin", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] } { "role" : "userAdminAnyDatabase", "db" : "admin", "isBuiltin" : true, "roles" : [ ], "inheritedRoles" : [ ] }
這里就不詳細解析了,大多數和字面意思差不多,非常贊.
既然創建完成了,我們嘗試下帶用戶名的登陸方式:
[root@localhost ~]# mongo 10.21.14.16:40001/admin -u root -p "root123" MongoDB shell version v3.4.16-rc0 connecting to: mongodb://10.21.14.16:40001/admin MongoDB server version: 3.4.16-rc0 > show dbs admin 0.000GB local 0.000GB >
可以正常使用了.
當然了,用戶就必須是可以修改和刪除信息的,這里不詳細講,附上命令參考
#假設我們新建了一個用戶ttt,這里就不解析了 >use admin >db.createUser({user:"ttt",pwd:"123",roles:[{role:"root",db:"admin"}]}) >db.auth("ttt","123") #查看現在所有的用戶信息,也就多了個ttt了. > db.system.users.find() { "_id" : "admin.adminuser", "user" : "adminuser", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "jLubKc6ODHMxCnjFeeJuog==", "storedKey" : "l1cL39bnvkw2fecw1DHdKM0TM7s=", "serverKey" : "ZD+EZymr8OhlwMZ/0h35Qn8QHE4=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } { "_id" : "admin.root", "user" : "root", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "Fx2BRB2ZIJeD2X+bvM0ZIg==", "storedKey" : "Yyo+vcxhv40vNXZwUNfnBTz×××30=", "serverKey" : "th4UbT+/aJcgOXvKx4TFDhX242k=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] } { "_id" : "admin.ttt", "user" : "ttt", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "X58qg8jiiM3ju8v8Cywu8A==", "storedKey" : "MO4lwHhFUn50Ja0/QCHeN4hObRQ=", "serverKey" : "N9iUXgshDP9beTD8pNKfrmtl0V0=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] } #另一個命令也能看到 > db.getUsers() [ { "_id" : "admin.adminuser", "user" : "adminuser", "db" : "admin", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }, { "_id" : "admin.root", "user" : "root", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] }, { "_id" : "admin.ttt", "user" : "ttt", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] } ] #再看看新建的那個用戶 > db.getUser("ttt") { "_id" : "admin.ttt", "user" : "ttt", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] } #我們修改用戶的所有信息,都可以通過下面這條命令實現, #db.updateUser("UESR",{修改信息}) #現在我們需要修改的是密碼 > db.updateUser("ttt",{pwd:"789"}) #修改完成,舊密碼登錄就會報錯 > db.auth("ttt","123") Error: Authentication failed. 0 #新密碼就沒事了 > db.auth("ttt","789") 1 #不過,修改密碼的方式并不是只有一種,下面這種也行 > db.changeUserPassword("ttt","456") #同理,舊密碼登錄就會報錯了 > db.auth("ttt","123") Error: Authentication failed. 0 #新密碼就沒事了 > db.auth("ttt","456") 1 #刪除用戶就很簡單了 > db.dropUser("ttt") true #現在你還想登錄,當然是不行的 > db.getUser("ttt") 2018-07-18T09:38:38.504+0800 E QUERY [thread1] Error: not authorized on admin to execute command { usersInfo: "ttt" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 DB.prototype.getUser@src/mongo/shell/db.js:1518:1 @(shell):1:1 #登錄到其他用戶就行了 > db.auth("root","root123") 1 > db.dropUser("ttt") false > db.getUser("ttt") null > db.getUsers() [ { "_id" : "admin.adminuser", "user" : "adminuser", "db" : "admin", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }, { "_id" : "admin.root", "user" : "root", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] } ] >
關于單臺服務器的認證方式就說到這里了.
對集群數據庫增加mongodb認證信息
正如我之前說的,使用mongodb,大部分人不會只用單臺,因為這就是源生的分布式數據庫.而使用集群的認證,比起單臺,則需要增加一個keyfile,當然你也能用另一種,這里不展開講太多.
我這里前置條件說明一下,這個時候集群是已經搭建好了,但是集群內的用戶還沒有創建起來,因為你沒有創建keyfile也是走不起來.
首先,要在所有節點配置都打開keyfile,并配上路徑,并確保mongodb有這個文件的權限,無論你是分片集群,還是單純副本集,在mongos端,config端,share端,都要一起啟用,要不然沒有配置的就會報權限錯誤,如果是副本集而又授權了,你還需要重新做一遍才行.
#打開配置文件 vim /usr/local/mongodb/mongod_data_40001.conf . . . #是否開啟認證模式,現在開啟來使用 auth = true #關閉認證模式,和上面的沖突,之前是開啟的,現在關閉了 #noauth = true #指定集群認證文件,沒開認證就不用指定,注釋關閉即可,需要用openssl來生成,暫時不研究 keyFile = /data/mongodb/data/keyfile #指定訪問地址,3.4之前默認全網,之后則默認是127.0.0.1,但是在3.6之后必須制定這個參數才能啟動.配置0.0.0.0代表全網匹配 #bind_ip=0.0.0.0
改完之后,沒啟動就先不要急著啟動,而已經啟動了的,也不要急著重啟,稍等再重啟.
然后,我們要生成這個keyfile文件
#用openssl命令生成一個64位的秘鑰文件 openssl rand -base64 64 > keyfile #把它權限設成600,不然就報錯權限過高的錯誤 chmod 600 keyfile #把他移到目的目錄 mv keyfile /data/mongodb/data/ #記得把權限搞一搞 chown mongodb:mongodb /data/mongodb/data/keyfile
有些人好奇,為什么是64位的秘鑰文件?沒錯,真的可以更多,或者更少,例如:
openssl rand -base64 741 >keyfile openssl rand -base64 16 >keyfile
這些都可以用,但是,要考慮系統性能問題和數據安全的問題.秘鑰文件越復雜,那么你內部系統的加密與解密就需要更耗費資源,尤其在高并發環境,可以講比較悲催.但是太簡單,那么你的數據被破解的幾率就更高,安全性就談不上了.我這里只是折衷,所以是64,各位有興趣可以根據實際情況來設置.
再然后,重新啟動各節點,或者說你沒啟動的話,就現在啟動了,按以下順序重啟所有服務
config副本集:先主庫,再從庫,讓他慢慢切換.
router服務:隨便重啟.
shard副本集:先主庫,再從庫,讓他慢慢切換.
最后,就開始創建用戶授權了,就和上面一樣操作就可以了
#如果我們沒有做好副本集或集群,那就還需要先做,詳細解析我就不做了. > config = {_id:"sljd_shard1",members:[{_id:0, host:"172.25.40.80:40001" },{_id:1, host:"172.25.40.81:40001" },{_id:2, host:"172.25.40.82:40001" }]} > rs.initiate(config) > rs.status() #然后進入admin數據庫,也是當前用戶認證庫 shard1:PRIMARY> use admin switched to db admin #授權 shard1:PRIMARY> db.createUser({user:"root",pwd:"admin123",roles:[{role:"userAdminAnyDatabase",db:"admin"}]}) Successfully added user: { "user" : "adminuser", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } #然后登陸 shard1:PRIMARY> db.auth("root","admin123") #或者 mongo 172.25.40.80:40001/admin -u root -p "admin123"
然后,我們看到用戶了
#登陸上主庫,注意認證庫 mongo 172.25.40.80:40001/admin -u root -p "admin123" #在主庫上查看一下用戶情況 shard1:PRIMARY> db.getUsers() [ { "_id" : "admin.root", "user" : "root", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] } ] #登陸上從庫.注意認證庫 mongo 172.25.40.81:40001/admin -u root -p "admin123" #要多做一步,允許在從庫執行查詢,不然會報錯,因為從庫默認是只讀的 shard1:SECONDARY> rs.slaveOk() #再在從庫執行一下 shard1:SECONDARY> db.getUsers() [ { "_id" : "admin.root", "user" : "root", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] } ]
好了,那就沒問題了.
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。