DAY25 MongoDB 自订角色与使用者

DAY25 MongoDB 自订角色与使用者

前言

MongoDB 内的登入需要输入 使用者(user) 帐号密码,而每个 使用者 都有其对应的角色(身份),我们称为 Role。在建立使用者的当下,必须指定他的角色,因此会先介绍如何建立 Role。

事前准备

可以使用其他方法,但我习惯用 docker-compose 启动,环境乾净的且..我有设定快捷键XD

docker-compose.yml

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. 建立角色
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

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

Step1 建立 Role

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

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
> use testdb
switched to db testdb

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

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

先进行查询测试

> db.testCollection.find()
{ "_id" : ObjectId("60e82a0a810f8c0cd303cf61"), "field" : "a" }

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

都符合我们预期结果,接着试试看删除,仅有 testCollection 能够被删除。

> 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,有人还是坚持能够不输入帐号密码也能连线,於是当时我试了一下,先不使用帐号密码连线看看

# 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

> show dbs
>

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

> 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


本系列文章会同步发表於我个人的部落格 Pie Note


<<:  【Day12】数据展示元件 - Tooltip

>>:  html5 语意化标签-基础语法

计算机概论 - 软件工程 Software engineering

软件工程是计算机科学的一门分支,目的是寻找能引导大型且复杂软件系统开发的原则,开发这样的系统所要面的...

【Day 26】S3 on AWS Outpost 限制与建置流程

tags: 铁人赛 AWS S3 Outposts S3 Bucket 前言 昨天我们成功把 K8S...

Day 13 Mailhog - 模拟 SMTP 邮件服务的开发利器

由於 Mautic 是一个自动化行销利器,那麽寄发电子邮件便是一个必须的功能。不过在开发时一再的利用...

Rust-30天的心得

分享一下这30天从无到有的学习下来的一点点心得 先说一下为什麽要学习Rust是因为最近比较红之外还有...

Day 3 情报收集 - Information Gathering

在开始正式进入主题前,觉得可能有必要宣导一下国内刑法规范,根据全国法规资料库所查到的相关资料 刑法第...