本文來自MongoDB中文社區:http://www.mongoing.com/mongodb
本文討論保護MongoDB數據庫所需的訪問控制。具體來講,咱們可使用這些特性來確保只有通過受權的用戶才能訪問數據庫。每一個MongoDB用戶應該只能訪問他們在組織中所扮演的角色所須要的數據,這由組織中負責管理數據安全的人員來決定。這是管理數據和遵照國際要求所必需的良好特質。shell
訪問控制確保訪問數據庫的人員獲得明確的標識,而且可以訪問、更新或刪除他們有權訪問的數據。這是咱們將在本文中討論的主題。在數據庫中,咱們能夠處理客戶機的身份驗證和它們但願執行的操做的受權。數據庫
當客戶機或用戶訪問數據庫時,第一個任務是檢查該用戶是不是已知用戶,並提供憑證以確保可以使人信服地識別他們,這就是所謂的身份驗證。使用MongoDB,咱們可使用如下工具之一來處理認證問題。數組
SCRAM:MongoDB默認身份驗證機制。它根據用戶名、密碼來進行數據庫身份驗證。
x.509證書:該機制使用x.509證書代替用戶名和密碼。基於副本集或分片集羣中的服務器或成員對客戶機進行身份驗證。維基百科上說:「x.509證書包含公鑰和標識,由證書頒發機構或自簽名,持有證書的人能夠依賴證書所包含的公鑰來創建安全通訊」。安全
LDAP:這個協議最多見的用途是提供一箇中心服務器來存儲用戶名和密碼,容許不一樣的應用程序鏈接到LDAP服務器來驗證用戶。
Kerberos:這是一個基於票據的行業標準認證協議。
註解:外部工具只在MongoDB企業版中提供。服務器
做爲一種最佳實踐,咱們將爲須要訪問數據庫的每一個實體建立登陸憑據,但只針對這些實體。這樣作,咱們將可以審計全部用戶所作的全部活動,並完成GDPR要求。除了用戶身份驗證以外,還須要對服務器和網絡進程進行身份驗證。在一套副本或分片集羣的全部節點檢查彼此不斷爲了確保都是已知的訪問用戶(換句話說,確認他們的會員),以及其餘任務,好比檢查每一個成員的健康爲了肯定副本必須完成一次新的選舉。那麼什麼是選舉呢?在MongoDB中,只有一個節點可以執行寫操做。當此節點關閉或網絡部分開始工做時,其他節點開始進行一次選擇,以便選擇新的主節點並使服務在不中止的狀況下運行。網絡
數據庫管理員負責向用戶授予或拒絕對數據庫資源進行操做的權限。經過使用角色,咱們能夠指定對資源執行什麼操做。所以,角色是授予用戶使用特定資源執行特定任務的權限。機器學習
資源←動做←角色(權限)→用戶工具
MongoDB提供內置角色,還容許您根據數據庫的特定需求定義新的角色。這些角色是根據對資源的操做來定義的。動做是咱們能夠對數據庫進行全部類型的操做,例如查找、刪除、插入、更新或建立索引。資源能夠是集合、文檔、索引、數據庫等等。使用只讀視圖,管理員經過限制對只公開其子集的敏感數據的訪問來得到字段級安全性。對視圖授予的權限與授予底層集合的權限是分開指定的。每一個角色只應該爲該角色授予必要的權限,而且只應該爲用戶分配適合其需求的角色。學習
MongoDB用戶必須使用最初建立它們的數據庫來標識本身。這一般是管理數據庫,但也能夠是其餘數據庫。不管在哪一個數據庫上建立了用戶,若是將適當的角色授予了用戶,他們將可以對其餘數據庫採起操做。
在啓用訪問控制以前,應該建立一個用戶,該用戶能夠在啓用訪問控制後建立用戶併爲用戶分配角色。而後,這個用戶管理員將用於建立和維護其餘用戶和角色,所以須要分配一個合適的角色來支持。若是你不建立此管理用戶,則在啓用訪問控制時將沒法登陸或建立新用戶和角色。
若是在沒有建立至少一個管理用戶的狀況下啓用訪問控制,則沒法登陸。localhost異常容許您在啓用訪問控制以後建立第一個用戶,從而避免了這個問題。要作到這一點,你須要:
啓用訪問控制
鏈接到localhost接口
在管理數據庫中建立第一個用戶,該用戶必須具備足夠的權限來管理其餘用戶和角色。
這個localhost異常只適用於仍然沒有建立用戶的狀況。您必須在兩個選項中進行選擇,在啓用訪問控制以前建立第一個用戶,或者在啓用訪問控制以後使用localhost異常建立第一個用戶。
在啓動mongod服務時,可使用參數指定數據庫的特性,或者更好的方法是使用配置文件。不管哪一種方式,你都必須使用安全選項:
security
authorization:enabled
此設置啓用或禁用基於角色的訪問控制(譯者注:上面的配置是激活狀態)。
在建立MongoDB用戶以前,有必要考慮一下用戶將要執行的任務。可能會有幾個具備相同權限級別的用戶,因此最明智的選擇是建立一個角色並將其分配給每一個用戶。經過只更改一個角色,您將更新全部使用它的用戶的權限。不然,須要爲每一個用戶對一組或一類用戶的訪問需求進行更改。操做步驟以下:
第一步:將上下文更改成要建立角色的數據庫:
use admin 第二步:執行這個命令:
<pre>
db.createUser({
user : '<userName>',
pwd : '<password>',
roles : [ { role : '<roleName>', db : '<dbName>' } | '<roleName>', …]
})
</pre>
若是您想建立一個用戶而不爲該用戶分配任何角色,您只需指定一個空的roles字段。
註解:若是您還在掌握MongoDB查詢語言,像MongoDB IDE Studio 3T這樣的工具備一個直觀的用戶管理器特性,這使得用戶管理更加直觀和直觀。
MongoDB IDE Studio 3T地址:https://studio3t.com/
用戶管理器地址:https://studio3t.com/knowledg...
假設您有合適的登錄角色並容許刪除用戶,您將須要將上下文更改到建立數據庫的時候,
use admin
以後執行以下命令: db.dropUser('<userName>')
要檢查用戶,必須將上下文更改成建立用戶的數據庫的情景,例如管理員數據庫。
<pre>
> use '<dbName>' 而後您可使用其中之一 > db.system.users.find() 或者 > db.getUsers() 可是,若是您只想詢問特定的用戶,請使用如下命令: > db.getUser('<userName>')
</pre>
有三種可能的狀況,顯然它們都有相同的哲學。讓咱們來看看:
<pre>
$ mongo
use '<dbName>'
db.auth('<userName>','<password>')
</pre>
我不建議您使用此方法,由於在您鍵入密碼時密碼是可見的。
<pre>
$ mongo --authenticationDatabase <dbName> -u <userName> -p
MongoDB shell version v3.6.4-rc0
Enter password:
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.4-rc0
MongoDB Enterprise >
</pre>
這是個人首選。在本例中,若是不指定authenticationDatabase參數,數據庫將始終嘗試根據將要鏈接到的數據庫對用戶進行身份驗證。若是咱們不指定要鏈接的數據庫名稱,就像我在上面的示例中所作的那樣,服務器將對「test」數據庫執行此操做。
從MongoDB客戶端,咱們必須使用這樣的鏈接字符串:
<pre>
mongo://<userName>:<password>@<hostName>:27017/<dbName>?options
</pre>
註銷結束當前身份驗證會話。您必須在通過身份驗證的同一數據庫中執行此操做。
<pre>
use admin
db.logout()
</pre>
正如您已經知道的,角色是授予用戶對資源執行操做的特權。角色定義角色成員能夠執行的任務,以及能夠執行這些任務的資源。MongoDB爲最多見的情景提供內置角色。可是,也容許咱們根據本身的特定需求建立本身的角色。每一個角色的做用域都限定在建立它的數據庫中。角色只能包含應用於其數據庫的特權,而且只能從其數據庫中的其餘角色繼承特權。在管理數據庫中建立的角色能夠包含應用於管理數據庫、其餘數據庫或集羣資源的特權,還能夠繼承其餘數據庫和管理數據庫中的角色。所以,若是須要從另外一個數據庫中建立的角色繼承,則必須在管理數據庫中建立新角色。
以前已經解釋過,您能夠在管理數據庫或任何其餘數據庫中建立角色。所以,若是你想檢查它們,你必須在定義它們的數據庫中進行:
<pre>
use '<dbName>'
要獲取數據庫的全部角色,請使用
db.system.roles.find()
或者
db.getRoles()
若是你只想要一個特定的角色,你可使用這個命令:
use '<dbName>'
db.getRole('<roleName>')
</pre>
MongoDB將內置角色分類爲:
數據庫用戶角色
數據庫管理員角色
集羣管理員角色
備份和恢復角色
全部數據庫角色
超級用戶角色
下面將詳細介紹每個角色。
數據庫級別角色以下:
讀——讀取全部非系統集合上的數據
讀寫——包括全部「讀」角色特權和在全部非系統集合上寫數據的能力
可使用的數據庫管理員角色以下:
dbAdmin——授予執行管理任務的特權
userAdmin——容許您在當前數據庫上建立和修改用戶和角色
dbOwner——此角色結合瞭如下內容:
readWrite
dbAdmin
userAdmin
用於管理整個系統的管理數據庫中的角色。
clusterMonitor——提供對監視工具的只讀訪問
clusterManager——用於管理和監視集羣上的操做
hostManager——監視和管理服務器
clusterAdmin——結合了其餘三個角色和dropDatabase操做
這個角色屬於管理數據庫。
backup——提供備份數據所需的特權
restore——提供從備份中還原數據所需的特權
這些角色位於管理數據庫上,並提供適用於全部數據庫的特權。
readAnyDatabase——與「read」角色相同,但適用於全部數據庫
readWriteAnyDatabase——與「readWrite」角色相同,但適用於全部數據庫
userAdminAnyDatabase——與‘userAdmin’角色相同,但適用於全部數據庫
dbAdminAnyDatabase——與「dbAdmin」角色相同,但適用於全部數據庫
如下角色不是直接的超級用戶角色,可是可以爲任何用戶分配任何數據庫上的任何特權,也包括他們本身。
userAdmin
dbOwner
userAdminAnyDatabase
root角色提供對全部資源的徹底特權:
root
若是須要知道角色的特權(是否從其餘角色繼承),能夠經過 「showPrivileges」字段來進行激活:
<pre>
use '<dbName>'
db.getRole('<roleName>', { showPrivileges : true })
</pre>
管理MongoDB資產的人必須爲本身的用例找到最合適的角色。在我看來,如下角色一般是最有用的:
userAdminAnyDatabase
clusterManager
clusterMonitor
backup
restore
dbAdmin
readWrite
read
您能夠在建立用戶時授予角色,也能夠在過後授予角色。下一個命令對於在建立用戶的同時分配角色是有效的:
<pre>
use '<dbName>'
db.createUser(
{
user: "<userName>",
pwd: "<password>",
roles: [ { role: "<roleName>", db: "<dbName>" } ]
})
你也能夠用這個命令:
use '<dbName>'
db.grantRolesToUser(
'<userName>',
[ { role : '<roleName>', db : '<dbName>' }, '<roleName>', … ]
)
</pre>
註解:第三方MongoDB工具中的角色管理器之類的功能在這裏很是方便,特別是若是您還在學習MongoDB查詢語言的時候。
<pre>
use '<dbName>'
db.revokeRolesFromUser(
'<userName>',
[ { role : '<roleName>', db : '<dbname>' } | '<roleName>' ]
)
</pre>
<pre>
use '<dbName>'
db.createRole({
role: "<roleName>",
privileges: [
{ resource: { db : 「<dbName>」,
collection : 「<collectionName>」 },
actions: [ '<actionName>' ]
}
],
roles: [ { role : '<fatherRoleName>', db : '<dbName>'} | '<roleName>' ]
})
</pre>
<pre>
use '<dbName>'
db.dropRole('<roleName>')
</pre>
這些命令是給自定義用戶授予和撤銷角色:
方案一:
<pre>
use '<dbName>'
db.grantPrivilegesToRole(
'<roleName>',
[
{ resource : { db : '<dbName>', collection : '<collectionName'> },
actions : [ '<actionName>',... ]
},
...
]
)
</pre>
方案二:
<pre>
db.revokePrivilegesFromRole(
'<roleName>',
[
{ resource : { db : '<dbName>', collection : '<collectionName'> },
actions : [ '<actionName>',... ]
},
…
]
)
</pre>
方案一:
<pre>
use '<dbName>'
db.grantRolesToRole(
'<roleName>',
[ { role : '<roleName>', db : '<dbName>' } | <roles> ]
)
</pre>
方案二:
<pre>
db.revokeRolesFromRole(
'<roleName>',
[ { role : '<roleName>', db : '<dbName>' } | <roles> ]
)
</pre>
當心!正如文檔所述:「特權或角色數組的更新將徹底替換前一個數組的值」。
<pre>
use '<dbName>'
db.updateRole(
'<roleName>',
{
privileges : [
{
resource : { db : '<dbName>', collection : '<collectionName>' },
actions : [ '<actionName>' ]
},...
],
roles : [ { role : '<roleName>', db : '<dbName>' } | '<roleName>' ]
}
)
</pre>
註解:您剛剛完成了MongoDB用戶和角色解釋系列的前半部分,MongoDB用戶和角色解釋系列的後半部分將瞭解如何在一個包含三個數據的節點副本集中啓用訪問控制,建立第一個使用localhost異常的用戶,並授予所需的角色。敬請期待~~~
譯者:管祥青
湖南大學研究生畢業,畢業後在海康威視研究院從事大數據研發及機器學習相關工做,如今就任於一家大數據金融公司。
原文做者:Juan Roy Couto
Juan爲了讓本身成爲目前MongoDB大師之一(https://www.mongodb.com/commu...。他得到了MongoDB認證,DBA和DEV。目前,他的工做角色是MongoDB數據庫工程師。在此以前,在多家金融公司作了20年的開發。他喜歡與皇馬的馬克杯合做,也喜歡與技術社區交流。你能夠在twitter.com/juanroycouto上閱讀他的文章。