MongoDB用戶驗證和權限管理


官方參考頁面:

https://docs.mongodb.com/v3.6/tutorial/enable-authentication/

https://docs.mongodb.com/v3.6/tutorial/enforce-keyfile-access-control-in-existing-replica-set/

前言:

前些年很多用戶對mongodb的安全意識是很淡漠的,也因此在前幾年出現了一些很嚴重的針對mongodb的攻擊。

本文以mongodb3.6為例,介紹mongodb目前的用戶驗證機制,當然用戶驗證只是mongodb安全體系的一部分,更加全面的安全內容參考:https://docs.mongodb.com/v3.6/security/

雖然mongodb提供了一系列的加強安全的措施,但實際上經常會用到的也就是用戶驗證(本文稱為client auth)集群成員間的驗證(本文稱為internal auth)了,internal auth多使用keyfile,關於keyfile驗證參考上述的第二個官方鏈接即可,這種keyfile是集群節點間的一種權限驗證機制,是mongo實例級別的,會在最后介紹下。

關於加密算法:

1.集群成員間的internal authentication加密方式有keyfiles和x.509兩種,前者較多見,后者涉及TLS/SSL封裝,我沒用過。

2.用戶驗證的加密算法在4.0之前默認為SCRAM,4.0之后MONGODB-CR(3.0前的默認加密方式)已被廢棄,而x.509不但支持internal auth也支持client auth,但是很少使用。

本文主要介紹最核心的用戶驗證,這種用戶驗證的粒度是庫級別的。

一、如何創建用戶?

安裝MongoDB后auth認證默認是關閉的,此時admin庫是不可見的(舊版本不可見,新版本里只是admin下的用戶相關的system.users不可見),現創建一個超級帳號:

use admin
//查看當前庫內已有用戶
show users
//查看當前庫內可用的roles,默認只有built-in roles
show roles
//創建用戶,roles可以使用當前庫內的角色,或者其他庫內的角色
db.createUser({user: "root",pwd: "root",roles: [ { role: "root", db: "admin" } ]})
//如何修改密碼
db.changeUserPassword('root','rootNew'); 
//已有用戶新增和解除built-in roles
db.grantRolesToUser('<username>', [{ role: '<built-in role>', db: 'admin' }])
db.revokeRolesFromUser( "<username>", [{ role: '<built-in role>', db: 'admin' }])
//刪除用戶命令如下,雖然所有庫的用戶信息全存在admin的system.users中,刪用戶時還是要use <庫名>才能刪除
use db_name
db.dropUser("<username>")

創建用戶時需要牢記的幾點:

  • 創建用戶必須指定庫名,即用戶是和庫綁定的。即便是超級用戶的創建也是如此,如果你創建root用戶時是在業務庫里,那你以后登錄root也只能指定業務庫的庫名了(超級賬戶一般建於admin庫下)。
  • 創建用戶時指定的built-in roles也是與庫綁定的,指定的哪個庫的角色,就擁有哪個庫的操作權限,即在test庫內創建db.createUser({user: "test",pwd: "test",roles: [ { role: "read", db: "test1" } ]})只能讀test1下的collection不能讀test下的。
  • 不同的庫下可以存在相同的用戶名,即admin.root用戶和test.root用戶是可以同時存在的。
  • 登陸mongo shell時如果不指定庫名,默認登入的test庫(只在3.6驗證過,其他版本自行驗證),你需要use db_name后才能進行db.auth(),當然你可以選擇直接mongo db_name -u username -p password登陸。
  • 一般來說創建一個root角色的超級用戶root即可(或一個__system權限的system用戶),創建一些普通權限的用戶做日常操作。
示例,創建包含多個角色的用戶:
use test
db.createUser(
  {
    user: "myTester",
    pwd: "xyz123",
    roles: [ { role: "readWrite", db: "test" },
             { role: "read", db: "reporting" } ]
  }
)
//這里第二個role是reporting.read,說明此用戶擁有reporting下的讀權限。
use admin
db.createUser(
  {
    user: "myUserAdmin",
    pwd: "abc123",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
  }
)
//未指定db的role默認是使用當前庫下的角色的,這里其實readWriteAnyDatabase相當於{ role: "readWriteAnyDatabase", db: "admin" }

 二、什么是角色(roles)?

https://docs.mongodb.com/manual/reference/built-in-roles/index.html

roles即一系列權限的集合,系統內置了一系列的built-in roles以便可以方便的為用戶授權,一般來說使用這些built-in roles創建用戶就可以了,除非你需要更細粒度的指定權限(那你可能需要下點功夫看官網文檔)。

Built-In Roles簡略介紹(詳細介紹參考以上官方鏈接):
Database User Roles:
    read
        提供本庫下所有非系統collection的讀權限,以及少數幾個系統collection的讀權限,例如system.indexes, system.js, and system.namespaces
    readWrite
        提供本庫下所有非系統collection的讀寫權限,以及系統collection system.js的讀寫權限。
Database Administration Roles:
    dbAdmin
        提供一些庫管理的權限,諸如索引創建,增刪集合,刪庫等等,並沒有對所有集合的讀權限,因此其實很少會用到。
    userAdmin
        提供在本庫下創建用戶、角色,刪除用戶、角色,修改密碼等一系列用戶相關的權限。
    dbOwner
        庫擁有者權限,即readWrite、dbAdmin、userAdmin角色的合體。
Cluster Administration Roles:
    clusterAdmin
        集群管理權限,clusterManager、clusterMonitor、hostManager角色的合體,此外再加上dropDatabase權限。
    clusterManager
        集群管理者權限,提供諸如添加shard,刪除shard,修改副本集配置等權限。
    clusterMonitor
        集群監控權限,顧名思義擁有查看一系列集群狀態的權限。
    hostManager
        參考官網鏈接的解釋,很少使用。
Backup and Restoration Roles:
    backup
        即進行數據備份的權限,實例級別的角色。
    restore
        即進行數據還原的權限,實例級別的角色,還包含很多與dbOwner重合的權限,參見官網中的相關解釋。
All-Database Roles:
    readAnyDatabase
        提供針對除了local和config庫外所有其他庫的讀權限。
    readWriteAnyDatabase
        提供針對除了local和config庫外所有其他庫的讀寫權限。
    userAdminAnyDatabase
        同userAdmin角色,只不過范圍擴大到了所有庫。
    dbAdminAnyDatabase
        同dbAdmin角色,只不過范圍擴大到了所有庫。
Superuser Roles:
    root
        即超級用戶的權限,擁有此權限你可以管理任意數據庫,可以將此角色理解為dbOwner of All Database。
Internal Role:
    __system
        系統內置角色,擁有很高的權限(高於root),在做一些集群操作時可以使用此包含此角色的用戶
        一般不推薦設置此角色的用戶,使用keyfile進行internal auth的副本集之間的交互就是使用此角色的。    

一般來說應用使用的用戶只需要readWrite角色即可,DBA可使用root賬戶和__system賬戶進行諸如集群配置,備份恢復等操作。

如何查看用戶的權限:

use admin
db.system.users.find()  //所有庫的用戶全部存在admin的system.users中
或者
use db_name
show users

三、如何開啟驗證登陸:

之前說了如何創建用戶和指定權限,那么如何使用戶登錄驗證生效呢?

在配置文件添加auth=true參數重啟之后即可生效(如果是集群環境只配置keyfile也可以),然后登陸:

use db_name  //用戶必須切換到其相應的庫登陸。3.6版本中默認登陸的一般是test庫,所以要注意使用use dbname切換到用戶對應的庫
db.auth('xxx','xxx')  //登陸相應的庫之后就可以操作數據啦
--或者直接在命令行中登陸:
mongo db_name -u username -p password

四、關於Localhost Exception

https://docs.mongodb.com/manual/core/security-users/#localhost-exception

mongodb配置文件中有個配置項enableLocalhostAuthBypass,其默認值為1(true)。

這個參數=1的含義是:

    如果你設置了auth=true,但是還未創建user或者不知道原來的用戶密碼想新建一個,那么此參數允許你在本地登陸時創建用戶,然后使用此新建的用戶驗證登錄。

    相應的如果此參數為0,那么如果你未創建用戶或者忘記了賬號密碼,那么即便在本地登陸mongo shell,也不允許你新建用戶。

因此官網建議將此參數設置為0或false,從而防止有人可以在服務器本地新建超級權限的用戶。

這個參數在初始安裝時有點用,例如你開啟了auth認證但是還沒建超級賬戶的場景,不過剛安裝完成時一般連auth都不會開,這個參數雞肋。

保險起見這里還是貼下enableLocalhostAuthBypass參數的設置方法:

在配置文件里添加setParameter=enableLocalhostAuthBypass=1,然后重啟(這是非YAML的設置方式,YAML的設置方式官網示例很完善了動手去查下就知道)。

五、關於集群用戶和集群驗證

https://docs.mongodb.com/v3.6/core/security-users/#sharded-cluster-users

mongodb還針對sharding集群提供了shard cluster user,普通的副本集內用戶稱作shard local user,集群用戶可以通過mongos登陸並操作整個集群的數據,但是shard local user只能操作特定的shard副本集,例如 cleanupOrphaned, compact, rs.reconfig()等操作可以使用本地用戶執行。

在mongos上創建的用戶屬於shard cluster user,在shard副本集本地節點創建的用戶就是shard local user了。在mongo2.6之后集群用戶是存儲在config server上的。

一般來說沒必要糾結集群用戶和普通應用用戶,對分片的集合使用集群用戶,不分片的使用本地用戶查詢某個shard副本集也可以。

mongodb官網是建議對於shard集群使用集群用戶連接mongos來操作集群,而本地用戶只用於進行單個shard的管理和配置。這應該是出於維護數據一致性的需求,對於那些未分片的集合操作本地shard應該是可以的,但是因為我生產上也沒部署過shard集群,所以實際生產中的最優實踐大家根據自己的實際情況抉擇。

更多的關於集群用戶的相關知識參見上述官網鏈接,這里不再詳述。

關於集群驗證:

在之前介紹了如何為mongo開啟用戶驗證,但是如果是replica或shard環境怎么辦?副本集節點間也是需要交流溝通的,這樣才能進行數據同步,那么直接把賬密寫入配置文件嗎?不,mongodb選擇創建一個keyfile實現集群間的權限驗證以便進行信息交互。

keyfile的內容可以是字符,但是保險起見一般使用工具生成:

openssl rand -base64 756 > /etc/mongo-keyfile
chown mongod.mongod /etc/mongo-keyfile
chmod 400 /etc/mongo-keyfile

--keyfile的權限只能是400,過高會導致節點無法啟動

然后將keyfile拷貝至副本集各個節點,並在配置文件中開啟keyFile選項即可。

需要特別提醒的是集群環境下如果開啟賬戶密碼驗證,那么只配置keyfile也是可以的,因為keyFile配置項默認會開啟authorization。官網原話是:keyFile implies security.authorization. 即keyfile項意味着auth同時開啟。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM