溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

建立mongodb的登錄認證功能

發(fā)布時間:2020-07-17 20:39:12 來源:網絡 閱讀:3925 作者:arthur376 欄目:MongoDB數據庫

對于一個完善的數據庫系統(tǒng),必然是需要權限控制,當然mongodb也不例外.沒有認證的數據庫已經被證明是******的一個突破口,所以我們無論是出于什么原因,數據庫認證對于一個生產系統(tǒng)而言,至關重要.

在MongoDB 3.0 以后,用戶登錄的密碼認證機制有:SCRAM-SHA-1(默認,基于加鹽的應答式認證),MONGODB-CR(普通應答式認證,3.6廢棄,4.0刪除),x.509 Certificate(基于證書的SSL/TLS加密認證),LDAP Proxy(基于LDAP系統(tǒng)的鑒權認證,僅企業(yè)版支持),Kerberos(基于Kerberos鑒權,僅企業(yè)版支持),一般而言,默認的就已經很不錯了.

然后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
>

好像報錯了,但是請淡定,這是正?,F象,因為之前默認是免認證,現在開啟了認證,你又沒創(chuàng)建用戶,那肯定是報錯的,不過不用擔心,因為你原本是沒用戶密碼的,所以是可以新建的.

但是要注意,在初始無賬戶密碼狀態(tài)下,只能通過登錄127.0.0.1這個地址你才能創(chuàng)建用戶和密碼,所以就需要注意參數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"
        }
    ]
}
#再創(chuàng)建多一個試試
> 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
>

又報錯了?沒錯,這個時候你已經有用戶了,所以就拒絕你的操作了,你要先認證一下你自己剛建好的用戶了

#認證一下你剛才創(chuàng)建的用戶
> db.auth("adminuser","admin123")
1
> use admin
switched to db admin
#再次創(chuàng)建用戶
> 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
>

這次沒問題了,解決了問題,要想創(chuàng)建更多用戶,甚至細化到個別數據庫來創(chuàng)建用戶,你可以這樣:

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動作,只要有權限,就可以自動創(chuàng)建庫和表的.


然后還有第二個mongodb的知識點---角色權限管理

mongodb創(chuàng)建的用戶是按role角色來區(qū)分權限的,跟我們熟悉的oracle和sql server相似(mysql8.0后才支持角色管理),這點倒不是特別了.至于有什么role選擇呢,你可以show roles看看.我們主要常用的有全局超級管理員userAdminAnyDatabase(也是我們第一個需要創(chuàng)建的用戶權限),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" : [ ]
}

這里就不詳細解析了,大多數和字面意思差不多,非常贊.


既然創(chuàng)建完成了,我們嘗試下帶用戶名的登陸方式:

[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,當然你也能用另一種,這里不展開講太多.

我這里前置條件說明一下,這個時候集群是已經搭建好了,但是集群內的用戶還沒有創(chuàng)建起來,因為你沒有創(chuàng)建keyfile也是走不起來.

首先,要在所有節(jié)點配置都打開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

這些都可以用,但是,要考慮系統(tǒng)性能問題和數據安全的問題.秘鑰文件越復雜,那么你內部系統(tǒng)的加密與解密就需要更耗費資源,尤其在高并發(fā)環(huán)境,可以講比較悲催.但是太簡單,那么你的數據被破解的幾率就更高,安全性就談不上了.我這里只是折衷,所以是64,各位有興趣可以根據實際情況來設置.


再然后,重新啟動各節(jié)點,或者說你沒啟動的話,就現在啟動了,按以下順序重啟所有服務
config副本集:先主庫,再從庫,讓他慢慢切換.

router服務:隨便重啟.

shard副本集:先主庫,再從庫,讓他慢慢切換.


最后,就開始創(chuàng)建用戶授權了,就和上面一樣操作就可以了

#如果我們沒有做好副本集或集群,那就還需要先做,詳細解析我就不做了.
> 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"
#要多做一步,允許在從庫執(zhí)行查詢,不然會報錯,因為從庫默認是只讀的
shard1:SECONDARY> rs.slaveOk()
#再在從庫執(zhí)行一下
shard1:SECONDARY> db.getUsers()
[
    {
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
            {
                "role" : "root",
                "db" : "admin"
            }
        ]
    }
]

好了,那就沒問題了.







向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI