zoukankan      html  css  js  c++  java
  • MongoDB账号管理及实践

    此文已由作者温正湖授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    目前蜂巢(云计算基础服务)MongoDB上已经有数十个实例,其中不少是企业用户或公司内部产品用户的。用户多了,那就会反馈一些问题。其中一个就是MongoDB实例访问账号,虽能够提供创建和删除集合、索引,创建数据库等用户所需的权限,但无法删除数据库,这个问题虽然不严重,但多少会影响用户体验。那么这是为什么呢?本文以此作为入口来谈谈MongoDB的账号管理。


    MongoDB作为一个成熟的数据库,像MySQL一样,也提供账号管理,但又跟MySQL不大一样,MongoDB使用基于角色的访问权限控制(Role-Based Access Control,RBAC),包括账号(Users,直译为用户,但似乎账号更好理解)、角色(Roles)和权限(Privileges)三层关系。权限指的是允许对某种资源进行的某些操作。这里所说的资源,包括数据库、集合和集群等。在进行MongoDB权限管理操作时,资源使用一个文档来表示,比如数据库mydb下的集合mycoll作为一种资源表示为{db: "mydb", collection: "mycoll"}。{db: "mydb", collection: ""}表示数据库mydb下的所有集合。对应地,{db: "", collection: "mycoll"}就是所有数据库下的mycoll集合,集群资源表示为{cluster: true},如果要将所有数据库和集群作为一种资源那么可以表示为{anyResource: true}。所说的操作包括对集合的CRUD,查看数据库下的集合列表,查看复制集或分片集群当前状态等。根据操作类型,又可以分为:读写操作,数据库管理操作,集群部署操作,复制集操作,分片集群操作,系统管理操作,诊断操作,内部操作等8大类。


    MongoDB对外提供的是账号,作为访问MongoDB认证单位。内部,一个账号可以由0到多个角色组成,角色分为内建角色(Built-In Roles)和自定义角色(User-Defined Roles)。为了方便使用,MongoDB提供了多种内建角色,分为数据库用户,数据库管理员,集群管理员,备份和恢复角色,跨数据库角色,超级用户,内部用户等7大类,每个大类下面有可以分为不同权限的角色,比如数据库用户大类可细分为读read和读写readWrite两种角色,而每个角色拥有一定的权限,比如readWrite角色具有创建/删除集合、创建删除索引和集合CRUD等16种权限,跨数据库角色表示该角色不仅对某个数据库有指定的操作权限,还对实例中其他所有(用户创建的)的数据库都具备同样的权限,比如readWriteAnyDatabase,具备对所有数据库有readWrite权限。这里有个特例,就是给用户授权角色时,如果授权时指定的数据库是admin,则即使仅指定readWrite,也同样具备readWriteAnyDatabase角色,也就是说对admin具有readWrite角色,那么对其他数据库也具有,天然具有AnyDatabase光辉。


    蜂巢(云计算基础服务)MongoDB提供了MongoDB复制集实例,用户可以创建readWriteAnyDatabase权限的账号来访问MongoDB,为什么要AnyDatabase呢?因为我们还未提供MongoDB的数据库和账号管理功能(接管用户所有的数据库/集合、用户创建和权限管理操作),无法限制用户创建数据库,所以也就无法为特定某个数据库授予readWrite权限。readWriteAnyDatabase权限具备了复制集场景下用户所需的绝大部分权限,包括集合、索引的创建和删除,数据库/集合等统计信息。就像文章刚开始的描述一样,其不具备删除数据库(dropDatabase)这个权限,虽然有点坑,但还不是大问题,只需在后续提供MongoDB的数据库和账号管理功能中,将dropDatabase权限纳入管理即可。但在分片集群场景下,readWriteAnyDatabase所具有的的权限已经根本无法满足用户的正常操作,比如对数据库启用分片功能(enableSharding),人工进行分片的chunk拆分(splitChunk),在我们没有数据库和账号管理功能前,这些操作都需要用户端来执行,而readWriteAnyDatabase无法满足。那么是不是有其他内建角色满足需求呢,查阅官方文档发现集群管理员下的clusterManager角色提供了我们所需的权限,但其还提供了诸如在分片集群中添加和删除分片服务器,在复制集中进行复制集重配置等重型权限,如果给用户这些权限将是非常危险的。所以,在蜂巢分片集群实例中,无法通过为用户提供拥有多个内建角色(如readWriteAnyDatabase、clusterManager两个)的账号来满足用户正常使用的需求。这个时候,自定义角色就派送用场了,在创建自定义角色时,既可以指定对资源的操作权限,还可以选择继承另一个角色所拥有的权限,比如,提供给用户的新账号继承了readWriteAnyDatabase角色的所有权限,还额外添加了dropDatabase、enableSharding和splitChunk等权限,这样一来就顺利解决了面临的问题。


    关说不练假把式,结合以上的描述,演示如何为MongoDB进行账号管理操作。


    1、首先在mongod配置文件中增加权限相关设置 security: {authorization: enabled, keyFile: /home/mongo/keyfile}。其中authorization表示是否启用访问权限认证,keyFile指定了MongoDB复制集或分片集群内部各组件相互间通信的认证文件;MongoDB提供了本地例外机制,避免用户在启用认证前未设置账号导致无法访问MongoDB实例的尴尬;


    2、创建用户所需的数据库账号,如下:

    mongos> use admin

    mongos> db.createUser(  {    user: "myuser",    pwd: "xxxxx",    roles: [ { role: "readWrite", db: "admin" } ]  } )

    指定了认证数据库为admin,角色采用内建的readWrite,由于指定的数据库是admin,那么等同于创建了readWriteAnyDatabase角色的账号。用该账号登陆:

    use admin

    db.auth("myuser","wzh123")


    3、但该账号无法执行如下这些操作:

    mongos> use mydb
    mongos> db.dropDatabase()
    {
    	"ok" : 0,
    	"errmsg" : "not authorized on shardtest to execute command { dropDatabase: 1.0 }",
    	"code" : 13,
    	"codeName" : "Unauthorized"
    }
    mongos> sh.enableSharding("wzhshard")
    {
    	"ok" : 0,
    	"errmsg" : "not authorized on admin to execute command { enableSharding: "wzhshard" }",
    	"code" : 13,
    	"codeName" : "Unauthorized"
    }


    4、所以,只能通过创建自定义角色来满足需求,先切换到root账号:

    use admin

    db.auth("root","wzh123") // root为已创建的具备超级用户角色的管理账号。

    创建自定义角色: db.createRole({ role: "wzhRole", privileges: [{ resource: { db: "", collection: "" }, actions: ["enableSharding","dropDatabase" ] }], roles: ["readWriteAnyDatabase"] })

    privileges字段指定了该角色具有的对resource字段所述资源具有actions字段所述的操作权限enableSharding和dropDatabase,同时通过roles字段继承了readWriteAnyDatabase的所有权限。


    5、进一步操作myuser账号,先去掉其readWrite角色,操作如下:

    db.revokeRolesFromUser(
        "myuser",
        [
          { role: "readWrite", db: "admin" }
        ]
    )

    确认权限已收回:

    mongos> db.getUser("myuser")
    {
    	"_id" : "admin.myuser",
    	"user" : "myuser",
    	"db" : "admin",
    	"roles" : [ ]
    }


    6、为myuser增加wzhRole角色:

    db.grantRolesToUser(
        "myuser",
        [
          { role: "wzhRole", db: "admin" }
        ]
    )

    确认权限已经赋予:

    db.getUser("myuser")
    {
    	"_id" : "admin.myuser",
    	"user" : "myuser",
    	"db" : "admin",
    	"roles" : [
    		{
    			"role" : "wzhRole",
    			"db" : "admin"
    		}
    	]
    }


    7、再使用myuser登陆

    use admin

    db.auth("myuser","wzh123")


    8、执行操作:

    mongos> sh.enableSharding("wzhshard")
    { "ok" : 1 }
    mongos> sh.shardCollection("wzhshard.table1",{mykey:1})
    { "collectionsharded" : "wzhshard.table1", "ok" : 1 }
    mongos> use wzhshard
    switched to db wzhshard
    mongos> db.dropDatabase()
    { "dropped" : "wzhshard", "ok" : 1 }


    一切看起来那么美好!

    MongoDB在权限管理中引入了角色这一中间层,一般情况下,直接基于内建角色来创建账号即可,有特殊需求的话,可以创建自定义角色来满足需求,这样一来就无需暴露繁多的具体权限。对于新司机,更容易上手。但不足之处在于MongoDB数据库并未像MySQL一样未提供IP过滤功能(未提供Host字段用来设置账号所适用的主机IP列表)。

    最后,网易数据库团队正在热火朝天地调研和开发MongoDB分片集群功能,计划上半年在蜂巢(云计算基础服务)上提供MongoDB分片集群能力,届时将带给大家更加强大的文档数据库能力。


    网易云数据库RDS是一种稳定可靠、可弹性伸缩的在线关系型数据库服务,当前支持MySQL引擎,提供基础版,高可用版,金融版针对不同业务场景的高可用解决方案,同时提供多重安全防护措施,性能监控体系,专业的数据库备份、恢复及优化方案,使您能专注于应用开发和业务发展。


    参考资料:

    1、https://docs.mongodb.com/manual/reference/built-in-roles

    2、https://docs.mongodb.com/manual/reference/privilege-actions/

    3、https://docs.mongodb.com/manual/reference/resource-document/

    4、https://docs.mongodb.com/manual/core/authorization/

    5、https://docs.mongodb.com/manual/core/security-user-defined-roles/

    6、https://docs.mongodb.com/manual/tutorial/manage-users-and-roles/


    网易云免费体验馆,0成本体验20+款云产品! 

    更多网易技术、产品、运营经验分享请点击




    相关文章:
    【推荐】 感觉要火!妹子实地采访网易猪厂程序员七夕怎么过

  • 相关阅读:
    发送邮箱验证信息的工具类
    Tensor的组合与分块-02
    09-ImageJ的安装与使用
    01 织布缺陷——断针缺陷检测
    Map 与结构体的混合使用
    c++ 读取TXT文件,中文乱码处理
    Code128 混合编码--译码方式及校验准则
    08-局部阈值分割算法总结
    code128码国标
    vector使用的相关博客
  • 原文地址:https://www.cnblogs.com/163yun/p/9814784.html
Copyright © 2011-2022 走看看