此文已由作者温正湖授权网易云社区发布。
欢迎访问,了解更多网易技术产品运营经验。
目前蜂巢()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两种角色,而每个角色拥有一定的权限,比如角色具有创建/删除集合、创建删除索引和集合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 mydbmongos> 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 wzhshardswitched to db wzhshardmongos> db.dropDatabase(){ "dropped" : "wzhshard", "ok" : 1 }
一切看起来那么美好!
MongoDB在权限管理中引入了角色这一中间层,一般情况下,直接基于内建角色来创建账号即可,有特殊需求的话,可以创建自定义角色来满足需求,这样一来就无需暴露繁多的具体权限。对于新司机,更容易上手。但不足之处在于MongoDB数据库并未像MySQL一样未提供IP过滤功能(未提供Host字段用来设置账号所适用的主机IP列表)。
最后,网易数据库团队正在热火朝天地调研和开发MongoDB分片集群功能,计划上半年在蜂巢(云计算基础服务)上提供MongoDB分片集群能力,届时将带给大家更加强大的文档数据库能力。
网易云数据库是一种稳定可靠、可弹性伸缩的在线关系型数据库服务,当前支持MySQL引擎,提供基础版,高可用版,金融版针对不同业务场景的高可用解决方案,同时提供多重安全防护措施,性能监控体系,专业的数据库备份、恢复及优化方案,使您能专注于应用开发和业务发展。
参考资料:
1、
2、
3、
4、
5、
6、
网易云,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请。
相关文章:
【推荐】 【推荐】