MongoDB的Replica Set以及Auth的配置


http://blog.0x01.site/2017/01/13/MongoDB%E7%9A%84Replica-Set%E4%BB%A5%E5%8F%8AAuth%E7%9A%84%E9%85%8D%E7%BD%AE/

MongoDB事件出現后,公司要給MongoDB加Auth,於是我就調研了一番。

現在MongoDB在生產中一般使用Replica Set的方式部署,如果一台宕機,另外一台Secondary會變成Master繼續服務,提高可用性。

使用docker搭個集群測試,首先建個network bridge

1
docker network new mongo-network

然后就是運行MongoDB的容器,集群名為test-rep

1
2
3
docker run --rm -it --name mongo1 --net=mongo-network mongo --replSet test-rep
docker run --rm -it --name mongo2 --net=mongo-network mongo --replSet test-rep
docker run --rm -it --name mongo3 --net=mongo-network mongo --replSet test-rep

然后再運行一個連接到上述三個MongoDB的容器

1
docker run --rm -it --name mongo-client --net=mongo-network mongo /bin/bash

然后在容器中執行

1
mongo --host mongo1

發現連接上了,說明MongoDB的配置沒有問題,然后是配置Replica Set。Replica Set要求配置的members中不能有localhost,而我配置為mongo2,mongo3這種一直都報類似的錯誤,我索性找出了幾個容器的IP,配置上去

1
docker network inspect mongo-network

可以看到幾個容器的IP

然后就可以使用IP地址配置了

1
2
config = {_id:"test-rep", version:1, members:[{_id:0, host:"172.19.0.5:27017", priority:5}, {_id:1, host:"172.19.0.3:27017", priority:2}, {_id:2, host:"172.19.0.4:27017", priority:3}]}
rs.initiate(config)

再去看mongod的log,發現集群同步成功

把mongo1停掉,mongo2會成為primary


然后按照MongoDB的文檔增加用戶

1
2
3
4
5
6
7
db.createUser(
{
user: "admin",
pwd: "admin",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)

重啟mongod的進程,增加–auth參數,表示啟用權限校驗

1
2
3
docker run --rm -it --name mongo1 --net=mongo-network mongo --replSet test-rep --auth
docker run --rm -it --name mongo2 --net=mongo-network mongo --replSet test-rep --auth
docker run --rm -it --name mongo3 --net=mongo-network mongo --replSet test-rep --auth

發現一直報Error in heartbeat request to 172.19.0.5:27017; Unauthorized: not authorized on admin to execute command的錯誤,查了很久,發現Replica Set要使用keyFile的校驗方式,讓集群的member之間同步,也就是說,通過keyFile獲得__system用戶在local上的權限。local存放着Replica Set的配置和同步信息。
MongoDB官方推薦的keyFile的生產方式

1
2
openssl rand -base64 756 > <path-to-keyfile>
chmod 400 <path-to-keyfile>

先結束掉mongod的進程,因為要放入keyFile,於是我啟動docker的時候,默認不啟動mongod

1
docker run --rm -it --name mongo1 --net=mongo-network mongo /bin/bash

容器里沒有裝openssl,我偷懶使用了以下命令

1
2
echo 'I8au1RERvEQkIiIB7vhTMhfceA8oH/L0mT6xxeVgaJg/mYnnZe89dGWjMrQSXI7A' > /data/key_file
chmod 400 /data/key_file

然后啟動mongod進程

1
mongod --replSet test-rep --auth --keyFile=/data/key_file

在mongo2,mongo3上按照上述命令,依次啟動。發現漂亮的同步成功的標志

收工


生產上的MongoDB,切換到需要Auth,是否可以在不停機的狀況下進行呢?

某同學猜想,mongod不采用Auth的時候,客戶端使用密碼,可不可以呢?Python連接MongoDB的代碼很簡單

pymongo.MongoClient('mongodb://user:user1@mongo1:27017,mongo2:27017,mongo3:27017/mydb?authMechanism=SCRAM-SHA-1') 

訪問mydb的時候,直接就拋Authentication failed錯誤了。如果我先添加了user呢?在mongo shell中執行

1
2
3
4
5
6
7
8
db.createUser(
{
user: "user",
pwd: "user1",
roles: [ { role: "readWrite", db: "mydb" },
{ role: "readWrite", db: "mydb2" } ]
}
)

剛剛的admin,只是訪問admin庫的用戶名和密碼,可以管理用戶信息,user用戶可以用來讀寫相應的庫。此時,mongod依然沒有使用--auth啟動,因此是沒有權限檢查的,再次連接,一切正常。

因此配置步驟如下

  • 創建MongoDB用戶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use admin
db.createUser(
{
user: "admin",
pwd: "admin",
roles: [ { role: "userAdminAnyDatabase", db: "admin" },
{ role: "clusterAdmin", db: "admin" },
]
}
)

use mydb
db.createUser(
{
user: "user",
pwd: "user1",
roles: [ { role: "dbOwner", db: "mydb" },
{ role: "dbOwner", db: "mydb2" } ]
}
)
  • 修改應用,更改MongoDB的URI
1
pymongo.MongoClient('mongodb://user:user1@mongo1:27017,mongo2:27017,mongo3:27017/mydb?authMechanism=SCRAM-SHA-1')
  • mongod增加keyFile
1
2
openssl rand -base64 756 > /data/key_file
chmod 400 /data/key_file
  • 把key_file上傳到其他mongod服務器上,修改mongod配置,一般是/etc/mongodb.conf
1
2
3
security:
authorization: enabled
keyFile: /data/key_file
  • 然后同時重啟三台mongod

這樣只有重啟的那一剎那不可用


免責聲明!

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



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