2021 iThome 鐵人賽 - DAY25 MongoDB 自訂角色與使用者

2021 iThome 鐵人賽 MongoDB披荊斬棘之路


DAY25 MongoDB 自訂角色與使用者

前言

MongoDB 內的登入需要輸入 使用者(user) 帳號密碼,而每個 使用者 都有其對應的角色(身份),我們稱為 Role。在建立使用者的當下,必須指定他的角色,因此會先介紹如何建立 Role。

事前準備

可以使用其他方法,但我習慣用 docker-compose 啟動,可以使用乾淨的環境且我有設定快捷鍵XD

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
version: "3.7"
services:
database:
image: mongo
container_name: mongodb-test
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=pass.123
command: mongod --auth
ports:
- "27117:27017"

我們設定 root 帳密為 root / pass.123,以及啟動認證 mongod --auth

MongoDB 內建的角色

最完整的當然還是參閱官方文章 Built-In Roles,要注意的是內建的角色都會在每一個資料庫中存在。

以下為常用的角色:

  • read: 僅有閱讀權限
  • readWrite: 擁有修改權限(包含上述權限)
  • dbAdmin: 擁有 DB 的所有修改權限(包含上述權限),除了 role 的調整
  • dbOwner: 擁有允許(grant) role 的權限(包含上述權限)
  • userAdmin: 擁有修改 role 的權限(包含上述權限)

所有 DB 操作的角色:

  • readAnyDatabase
  • readWriteAnyDatabase
  • dbAdminAnyDatabase
  • userAdminAnyDatabase

最高等級角色:

  • root

一般來說 dbAdmin 以上的權限就應該不常使用到了,理論上不會時常新增這麼大權限的角色給 user,通常 DBA 也會用更高的權限。


那除了上述的內建角色,我們也能夠自己定義角色的權限,最小可以到 Collection 的粒度。

建立角色

  1. 切換至 admin DB。use admin
  2. 建立角色
1
2
3
4
5
6
7
8
9
db.adminCommand(
{
createRole: "test_role",
privileges: [
{ resource: { db: "testdb", collection: "" }, actions: [ "find", "update", "insert" ] },
{ resource: { db: "testdb", collection: "testCollection" }, actions: [ "remove" ] } ],
roles: [ { role: "read", db: "admin" } ],
writeConcern: { w: "majority" , wtimeout: 5000 }
})

上面的語法是

  • admin 資料庫中,建立一個名為 test_role,的角色
  • 該角色可以在全部 Collection 進行 find, update, insert
  • 該角色僅可在 testCollection 進行 remove
  • roles 的意思是,繼承 admin 資料庫中的 read 權限

實際演練

Step0

1
2
use admin
db.auth("root", "pass.123")

Step1 建立 Role

1
2
3
4
5
6
7
8
9
db.adminCommand(
{
createRole: "test_role",
privileges: [
{ resource: { db: "testdb", collection: "" }, actions: [ "find", "update", "insert" ] },
{ resource: { db: "testdb", collection: "testCollection" }, actions: [ "remove" ] } ],
roles: [ { role: "read", db: "admin" } ],
writeConcern: { w: "majority" , wtimeout: 5000 }
})

Step2 建立 User

1
2
3
4
5
6
7
8
db.createUser(
{
user:"test1",
pwd:"pass.123",
roles:["test_role"]
});

Successfully added user: { "user" : "test1", "roles" : [ "test_role" ] }

Step3 以 test1 登入測試

mongo --host localhost --port 27117 -u test1 -p pass.123

分別在

  • testCollection 建立一筆資料,值為 a
  • noRemoveCollection 建立一筆資料,值為 b
1
2
3
4
5
6
7
8
9
> use testdb
switched to db testdb

> db.testCollection.insert({"field":"a"})
WriteResult({ "nInserted" : 1 })

> db.noRemoveCollection.insert({"field":"b"})
WriteResult({ "nInserted" : 1 })
>

先進行查詢測試

1
2
3
4
5
6
> db.testCollection.find()
{ "_id" : ObjectId("60e82a0a810f8c0cd303cf61"), "field" : "a" }

> db.noRemoveCollection.find()
{ "_id" : ObjectId("60e82a35810f8c0cd303cf62"), "field" : "b" }
>

都符合我們預期結果,接著試試看刪除,僅有 testCollection 能夠被刪除。

1
2
3
4
5
6
7
8
9
10
11
> db.testCollection.remove({"field":"a"})
WriteResult({ "nRemoved" : 1 })

> db.noRemoveCollection.remove({"field":"b"})
WriteCommandError({
"ok" : 0,
"errmsg" : "not authorized on testdb to execute command { delete: \"noRemoveCollection\", ordered: true, lsid: { id: UUID(\"d095b383-e647-4429-88a0-0d03335ccab2\") }, $db: \"testdb\" }",
"code" : 13,
"codeName" : "Unauthorized"
})
>

可以看到 noRemoveCollection 會因為沒有權限無法進行刪除,符合我們 test_role 的權限設定。


小插曲

之前遇過一個事件,即便設定了 auth,有人還是堅持能夠不輸入帳號密碼也能連線,於是當時我試了一下,先不使用帳號密碼連線看看

1
2
3
4
5
6
# mongo --host localhost --port 27117
MongoDB shell version v4.2.7
connecting to: mongodb://localhost:27117/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("3ab7644a-66eb-452a-8b4e-6f569664cb81") }
MongoDB server version: 4.4.4
WARNING: shell and server versions do not match

確實是可以連線,我們看看有哪些 database

1
2
> show dbs
>

得到一片空白,那我們再看看有哪些 user

1
2
3
4
5
6
7
8
> show users
2021-07-08T00:45:42.807+0800 E QUERY [js] uncaught exception: Error: command usersInfo requires authentication :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.getUsers@src/mongo/shell/db.js:1638:15
shellHelper.show@src/mongo/shell/utils.js:883:9
shellHelper@src/mongo/shell/utils.js:790:15
@(shellhelp2):1:1
>

這裡就很明顯告訴你沒有認證。
原來是他老兄以為第一個步驟就能夠連上線使用了XD

  • 作者: MingYi Chou
  • 版權聲明: 轉載不用問,但請註明出處!本網誌均採用 BY-NC-SA 許可協議。