//
readAnyDatabase可以读取所有的database吗?
//
01
问题背景
今天在线上环境中,发现了一个有意思的小问题。这个问题是权限相关的。
我们首先使用root权限登录,并在admin的这个数据库下面创建了test账号,给了它readAnydatabase的角色,创建这个账号的语句如下:
use admin db.createUser({ "user" : "test", "pwd" : "test_password", "roles" : [ { "role" : "readAnyDatabase", "db" : "admin" } ] })
创建账号完毕后,然后我们创建一个新的集合aaa.bbb,并向bbb这个集合插入数据,
testInit:PRIMARY> use aaa switched to db aaa testInit:PRIMARY> db.bbb.insert({id:1}) WriteResult({ "nInserted" : 1 })
然后我们重新使用test这个用户和test_password这个密码登录相关的mongod实例,并查询bbb的这个集合,结果如下:
[root@ ~]# /data1/yazhou5/mongodb/mongodb-linux-4.0.4/bin/mongo --port=45011 -u "test" -p "test_password" --authenticationDatabase "admin" --host=10.xx.xx.80 MongoDB shell version v4.0.4 connecting to: mongodb://10.13.88.80:45011/ Implicit session: session { "id" : UUID("daf6970a-aa4b-4984-9aa6-769e92f27c55") } MongoDB server version: 4.0.4 testInit:PRIMARY> testInit:PRIMARY> use aaa switched to db aaa testInit:PRIMARY> db.bbb.find() { "_id" : ObjectId("607da365a9028d75b2dc970c"), "id" : 1 }
到这里,似乎没有什么问题,我们创建的账号在admin数据库下面,有readAnydatabase的权限,所以即使不在aaa数据库下面,也可以直接读取aaa数据库下面的bbb集合。
如果我们使用这个账号去读取local数据库中的oplog.rs这个集合的时候,会发现下面的问题:
testInit:PRIMARY> db.oplog.rs.find() Error: error: { "operationTime" : Timestamp(1618847798, 1), "ok" : 0, "errmsg" : "not authorized on local to execute command { find: "oplog.rs", filter: {}, lsid: { id: UUID("a84e7282-ad63-4a53-8f14-1e8681ee2f06") }, $clusterTime: { clusterTime: Timestamp(1618847788, 1), signature: { hash: BinData(0, 81ABC979D562DC82476920680BB0B7B1940EDF46), keyId: 6912418480415309825 } }, $db: "local" }", "code" : 13, "codeName" : "Unauthorized", "$clusterTime" : { "clusterTime" : Timestamp(1618847798, 1), "signature" : { "hash" : BinData(0,"FmxZI9KxpqsjBgtPuVX/I7mlSvo="), "keyId" : NumberLong("6912418480415309825") } } }
看来,readAnyDatabase的角色只是一个"顾名思义"上的错觉,它也不能访问所有的数据库,那么这个角色能访问哪些数据库呢?
02
官方文档说明
readAnyDatabase
从官方文档描述不难看出,在3.4版本之前,这个用户可以访问local库和config库,而在3.4版本的MongoDB中进行了改造,后续版本不再能够访问local库和config库中的表,只能访问除这两个库之外的其他业务库和系统库。
如果想要访问local库和config库,需要单独创建这两个数据库的read或者readwrite角色账号。
那么我们可以将test用户设置成下面这样:
{ "user" : "test", "pwd" : "test_password", "roles" : [ { "role" : "readAnyDatabase", "db": "admin" }, { "role" : "readWrite", "db" : "config" }, { "role" : "readWrite", "db" : "local" } ] }