程序员

MongoDB 4.x 的权限管理说明

2020-05-23  本文已影响0人  暴走的初号机

MongoDB是一款高性能的nosql数据库,因为在数据结构的定义上有着极大的灵活性,所以在获取个人信息、社交网络、地理位置、行为日志等互联网场景中有着广泛的应用。默认情况下,MongoDB实例启动运行时是没有启用用户访问权限控制的,也就是说MongoDB不会对连接客户端进行用户验证,用户可以以root权限执行任何操作,这显然在生产环境下是不行的,本篇文章讨论MongoDB的认证及权限控制功能的配置。

之前的一篇文章深入理解Kubernetes的认证与授权机制其实已经提到,任何系统的权限管理的核心是认证和授权,mongodb自然也不例外。认证方面,我们考虑最简单的用户名密码方式实现(其实mongo还支持x509证书、kerberos、LDAP等方式)。权限管理方面,mongo使用的也是rbac模型,通过将用户和一组角色进行绑定,来进行数据库各类操作的权限控制。

角色设计

mongo对于数据库的各项操作我总结抽象为以下几类:

所谓的权限管理就是对上述操作进行各种排列组合,定义出一组角色,并且赋予给对应的用户。为了方便用户使用,mongodb已经内置了一组角色,在绝大部分场景下已经足够用了。需要注意的是,MongoDB在每个数据库上都提供内置的数据库用户角色数据库管理角色,但只在admin数据库中提供其它的内置角色。同时,角色有scope(作用域)的概念,一般有指定数据库和所有数据库两种。官方内置的角色列表如下:

数据库用户角色(Database User Roles)

数据库管理角色(Database Administration Roles)

集群管理角色(Cluster Administration Roles)

此类角色仅在mongo运行在集群模式(包含但不限于replica set或者sharded cluster)时使用,只有admin数据库中含有这些角色:

备份和恢复角色(Backup and Restoration Roles)

全数据库级角色(All-Database Roles)

以下角色只存在于admin数据库,全局级别,并且适用于除了configlocal之外所有的数据库。

超级用户角色(Superuser Roles)

内部角色(Internal Role)

创建自定义角色

虽然MongoDB提供了一系列内置角色,但有时内置角色所包含的权限并不满足所有需求,所以MongoDB也提供了创建自定义角色的方法。当创建一个自定义角色时需要进入指定数据库进行操作,因为MongoDB通过数据库和角色名称对角色进行唯一标识。

除了在admin数据库中创建的角色之外,在其它数据库中创建的自定义角色包含的权限只适用于角色所在的数据库,并且只能继承同数据库其它角色的权限。在admin数据库中创建的自定义角色则不受此限制。

MongoDB将所有的角色信息存储在admin数据库的system.roles集合中,不建议直接访问此集合内容,而是通过角色管理命令来查看和编辑自定义角色。

使用下面的命令可创建自定义角色:

db.createRole({
    "role" : "role1",
    "db" : "test",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ],
    "privileges" : [
        {
            "resource" : {
                "db" : "bocsh",
                "collection" : ""
            },
            "actions" : [
                "changeStream",
                "collStats",
                "convertToCapped",
                "createCollection",
                "createIndex",
                "dbHash",
                "dbStats",
                "dropCollection",
                "dropIndex",
                "emptycapped",
                "find",
                "insert",
                "killCursors",
                "listCollections",
                "listIndexes",
                "planCacheRead",
                "remove",
                "renameCollectionSameDB",
                "update"
            ]
        }
    ]
})

上述命令在test这个db中创建了一个名为role1的角色,这个角色能进行的操作在action中进行了定义(可以创建集合,新增、修改文档等),可以根据自身的实际需要灵活定义。

实际操作

添加用户

mongo默认是没有用户的,首先我们先来添加一些用户用于测试权限:

1、添加一个root用户用于全局管理:

db.createUser(
   {
     user: "root",
     pwd: "password",     
     roles: [{"role":"root","db":"admin"}]
   }
)

2、添加一个writer用户用于操作bocsh数据库(也可以在认证开启后使用root用户创建),这里我们创建readWrite类型的角色:

db.createUser(
   {
     user: "writer",
     pwd: "password",
     roles: [{"role":"readWrite","db":"bocsh"}]
   }
)

启用认证

首先要开启mongo的用户认证功能,可以通过如下方式启用:

1、在mongod启动命令中添加--auth,例如:

./mongod --dbpath /data/db/ --auth

2、在配置文件中启用安全认证:

security:
  authorization: enabled

3、docker中启用认证:

docker run --name=mongo mongo:4.0.18 --auth

k8s中也是类似,在args字段中加入启动参数即可
关于docker的cmd和kubernetes的args参数说明,请参考k8s中的command和docker的entrypoint区别

启动数据库以后,可以验证一下,执行mongo命令连接数据库:

$ mongo
MongoDB shell version v4.2.3
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("9e273833-874e-48fa-a0e6-417ac78d041f") }
MongoDB server version: 4.2.3
> use bocsh
switched to db bocsh
> db.user.find({})
Error: error: {
    "ok" : 0,
    "errmsg" : "command find requires authentication",
    "code" : 13,
    "codeName" : "Unauthorized"
}
> 

可以看到,因为没有权限(匿名用户),所以mongo直接返回了Unauthorized

权限验证

使用我们刚才创建的writer用户登陆数据库

$ mongo -u "writer" --authenticationDatabase "bocsh"
MongoDB shell version v4.2.3
Enter password: 
connecting to: mongodb://127.0.0.1:27017/?authSource=bocsh&compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("b4c6e5b0-6062-4d81-a621-a8340cb9d004") }
MongoDB server version: 4.2.3
> show dbs
bocsh  0.002GB
> use bocsh
switched to db bocsh
> db.user.find({})
{ "_id" : ObjectId("5e4965d207d7692d8f29bfca"), "name" : "张三", "age" : 30, "sexy" : "male" }
{ "_id" : ObjectId("5e496600a3ae9e2e0c4f3331"), "name" : "李四", "age" : 32, "sexy" : "male" }

可以看到能够正常查询到bocsh数据库中的数据,执行show dbs也只能看到bocsh这一个数据库,让我们来实验一下使用这个用户来创建一个包含read角色的用户:

> db.createUser(
...    {
...      user: "reader",
...      pwd: "password",
...      roles: [{"role":"read","db":"bocsh"}],
...     
...    }
... )
2020-05-23T13:21:22.917+0800 E  QUERY    [js] uncaught exception: Error: couldn't add user: not authorized on bocsh to execute command { createUser: "reader", pwd: "xxx", roles: [ { role: "read", db: "bocsh" } ], digestPassword: true, writeConcern: { w: "majority", wtimeout: 600000.0 }, lsid: { id: UUID("b2c99a8f-0abf-4a3b-8336-ac09cef977c3") }, $db: "bocsh" } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1370:11
@(shell):1:1

可以看到报错权限不足,因为执行这个操作需要userAdmin角色中包含的权限,而writer用户并没有这个角色,这是符合预期的。

接下来我们给writer用户赋予userAdmin角色(使用之前创建的root用户):

db.getSiblingDB("bocsh").updateUser(
    "writer",
    {
        customData: {},
        roles: [{ "role": "readWrite", "db": "bocsh" },
               { "role": "userAdmin", "db": "bocsh" }],
    }
)

writer用户再次执行添加用户操作:

> db.createUser(
... ...    {
... ...      user: "reader",
... ...      pwd: "password",
... ...      roles: [{"role":"read","db":"bocsh"}],
... ...     
... ...    }
... ... )
Successfully added user: {
    "user" : "reader",
    "roles" : [
        {
            "role" : "read",
            "db" : "bocsh"
        }
    ]
}

试验成功!

参考资料

https://www.cnblogs.com/dbabd/p/10811523.html
https://docs.mongodb.com/manual/reference/built-in-roles/#database-user-roles

上一篇下一篇

猜你喜欢

热点阅读