美文网首页程序员
MongoDB 4.x 的权限管理说明

MongoDB 4.x 的权限管理说明

作者: 暴走的初号机 | 来源:发表于2020-05-23 09:46 被阅读0次

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

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

    角色设计

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

    • 对于数据库数据的读、写操作
    • 对于数据库管理的各类操作,例如与schema相关、索引、收集统计信息,对数据库进行清理、修改、压缩、获取统计信息、执行检查等操作。
    • 对于数据库用户和角色的管理操作,可以分配scope范围内的角色给指定用户

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

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

    • read:可以读取指定数据库中任何数据。
    • readWrite:可以读写指定数据库中任何数据,包括创建、重命名、删除集合。

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

    • dbAdmin:包含执行某些管理任务(与schema相关、索引、收集统计信息)的权限,该角色不包含用户和角色管理的权限。
    • dbOwner:包含对指定数据库所有的管理操作权限。即角色readWrite、dbAdmin和userAdmin的集合。
    • userAdmin:包含对当前数据库创建和修改角色和用户的权限。该角色允许向其它任何用户(包括自身)授予任何权限,所以这个角色也提供间接对超级用户(root)的访问权限,如果限定在admin数据中,也包括集群管理的权限。

    集群管理角色(Cluster Administration Roles)

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

    • clusterManager:包含对集群监控和管理操作的权限。拥有此角色的用户能够访问集群中的config数据库和local数据库(集群模式为sharding或者replication)。
    • clusterMonitor:clusterMonitor角色包含针对监控工具具有只读操作的权限。如MongoDB Cloud Manager和Ops Manager。
    • hostManager:hostManager角色包含针对数据库服务器的监控和管理操作权限。
    • clusterAdmin:clusterAdmin角色包含MongoDB集群管理最高的操作权限。该角色包含clusterManager、clusterMonitor和hostManager三个角色的所有权限,并且还拥有dropDatabase操作命令的权限。

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

    • backup:包含备份MongoDB数据最小的权限。
    • restore:包含从备份文件中还原恢复MongoDB数据(除了system.profile集合)的权限。

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

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

    • readAnyDatabase:包含对所有数据库的只读权限。同时对于整个集群包含listDatabases命令操作。
    • readWriteAnyDatabase:包含对所有数据库的读写权限。同时对于整个集群包含listDatabases命令操作。
    • userAdminAnyDatabase:包含类似于userAdmin角色对于所有数据库的用户管理权限。
    • dbAdminAnyDatabase:包含类似于dbAdmin角色对于所有数据库管理权限。

    超级用户角色(Superuser Roles)

    • root:包含角色readWriteAnyDatabase、dbAdminAnyDatabase、userAdminAnyDatabase、clusterAdmin、restore和backup联合之后所有的权限。

    内部角色(Internal Role)

    • __system:MongoDB将此角色授予代表集群成员的用户对象,如副本集(replica set)成员或mongos实例。该角色允许用户对于需要的数据库操作都具有相应的权限,不要将该角色授予应用程序用户或其它管理员用户。

    创建自定义角色

    虽然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

    相关文章

      网友评论

        本文标题:MongoDB 4.x 的权限管理说明

        本文链接:https://www.haomeiwen.com/subject/ehckahtx.html