MongoDB笔记

用户与权限

2020-12-27  本文已影响0人  逃跑的肉丸

权限有关的问题

前言:

与其他数据库系统一样,MongoDB的安全机制同样重要,在去年发生的一次又一次数据库被黑的案例当中,有很大一部分是因为没有开启最起码的安全认证机制,从而为黑客提供了可乘之机。

认证机制

目前MongoDB支持如下安全机制

认证与授权

其实说的严肃点,authentication(认证)与Authorization(授权)还是不一样的,在MongoDB里,认证是当用户需要访问数据库实例时,需要提供用户名,密码,认证库来作为验证凭证;而Authorization则是在验证通过后,验证用户是否有访问或操作某个数据库对象的权限。也就是说如果只创建了用户但是没有赋予其任何权限,则该用户可能只能登陆进数据库实例,但是执行不了任何命令。

如何开启认证

对于单实例来说,直接在启动的时候指定--auth参数,或者在配置文件中指定security.authorization:enabled即可,如果是对于replica set复制集架构,则可以使用--keyfile参数或security.keyfile参数,此参数默认包含--auth的作用因为MongoDB没有默认的初始化用户可以使用,故在第一次部署完mongod实例后,可以有两种方法来创建你的第一个用户账号:

语法

其实创建语法百度搜索一下有一堆,不过我还是稍微啰嗦几句参数问题吧

语法结构:

db.createUser(
{ user: "<name>",   //用户名称
  pwd: "<cleartext password>",  //密码
  customData: { <any information> },    //用户的描述信息,想写啥写啥
  roles: [          //想要赋予的权限角色,可以赋予不同库下的不同角色
    { role: "<role>", db: "<database>" } | "<role>",
    ...
  ],
  authenticationRestrictions:[      //3.6之后功能,客户端白名单(默认允许所有客户端IP访问),类似于MySQL创建用户指定的IP
    {
        clientSource:[<IP>|<CDR range>],    //允许哪个客户端IP访问
        serverAddress:[<IP>|<CDR range>]    //连接到的服务器的IP地址,一般不用写
        }
    ],
    mechanisms: [ "<SCRAM-SHA-1|SCRAM-SHA-256>", ... ],  //SCRAM认证算法,一般使用默认值即可
    passwordDigestor: "<server|client>"     //密码分析位置,一般使用默认值即可(4.0以后默认server,以前版本默认client)
}
)

举例说明

>use admin
>db.createUser(
{
user:'user1',
pwd:'123456',
customData:{"desc":"This is the first user"},
roles:[{role:'userAdminAnyDatabase', db:'admin'}],
authenticationRestrictions: [ {
    clientSource: ["10.25.14.68"],        //客户端IP
    serverAddress: ["10.25.14.67"]        //其实就是服务器的可监听IP地址
} ]
})

注:上述例子表示只能允许客户端从10.25.14.68使用user1来访问数据库

内置角色

创建用户时需要使用到角色来达到权限分配的目的,而其实mongod本身内置的role已经基本可以满足使用了,当然如果你有特殊权限分配的需求,那可以使用用户自定义角色,这个后续文章会讲解。也可以参考官方文档:Built-in Roles
内置角色大致分组:

认证库问题

如果是从其他数据库管理系统过来的同学,可能对MongoDB的认证模式会有所模糊,所以我在这里提醒大家,在创建用户时,你在哪个库下建的账号就一定要使用这个库作为认证库去登录数据库系统,若使用其他库来鉴权则会报错,可能你还是不太理解,没关系,我们做个测试估计就明白了
我们切到testdb库创建一个用户

shardrs1:PRIMARY> use testdb
switched to db testdb
shardrs1:PRIMARY> db.createUser({
    user:"user3",pwd:"123456",
    roles:[
        {role:"read",db:"admin"},
        {role:"readWrite",db:"testdb"}
        ]})

之后我们尝试用新用户登录,此时如果你使用的不是用户所在的库作为认证库,那么就会报错; --authenticationDatabase参数就是用来指定此账号的认证库因为我们刚才是在testdb下创建的用户,所以必须使用testdb作为认证库进行登录连接,不同开发语言的驱动方法可能不太一样,但是认证逻辑是一样,请大家注意。

[mongo@mongotest01 ~]$ /apps/mongodb4/bin/mongo 127.0.0.1:27001 -u user3 -p123456 --authenticationDatabase admin
MongoDB shell version v4.0.0
connecting to: mongodb://127.0.0.1:27001/test
MongoDB server version: 4.0.0
2019-07-10T23:43:40.703+0800 E QUERY    [js] Error: Authentication failed. :
DB.prototype._authOrThrow@src/mongo/shell/db.js:1679:20
@(auth):6:1
@(auth):1:2
exception: login failed
[mongo@mongotest01 ~]$ /apps/mongodb4/bin/mongo 127.0.0.1:27001 -u user3 -p123456 --authenticationDatabase testdb
MongoDB shell version v4.0.0
connecting to: mongodb://127.0.0.1:27001/test
MongoDB server version: 4.0.0
shardrs1:PRIMARY> 

总结: 用户在哪个库下建的,就要使用哪个库作为其登录连接时的认证库,无论你roles里赋予的是什么库的权限,这些都不重要;

权限问题汇总

1.创建用户问题

问题1: 无法创建用户
报错如下:

[mongo@mongotest01 ~]$ mongo 127.0.0.1:27001/admin
MongoDB shell version: 3.2.10
connecting to: 127.0.0.1:27001/admin
shardrs1:PRIMARY> db.createUser({user:"user1",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
2019-07-10T15:05:51.135+0800 E QUERY    [thread1] Error: couldn't add user: Use of SCRAM-SHA-256 requires undigested passwords :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1267:15
@(shell):1:1

原因:为什么会发生这种报错呢,其实主要原因是因为我们使用了3.2的client端(注意看上述的MongoDB shell version)去连接到4.0的server端,而mongo在4.0版本上对createUser的参数默认值做了些修改,从而导致参数不匹配而报错。主要是参数选项passwordDigestor,其在4.0版本默认值为server,而4.0以前版本默认值是client, 可以参考官网文档db.createUser
解决办法:
方法1:使用4.0版本的client端连接数据库,当然这也是强烈推荐的,以免产生些其他未知问题;
方法2:在createUser时显示指定参数选项值passwordDigestor=server,如下:

shardrs1:PRIMARY> db.createUser({user:"user1",pwd:"123456",
    roles:[{role:"userAdminAnyDatabase",db:"admin"}],
    passwordDigestor:"server"}
    )
Successfully added user: {
    "user" : "user1",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ],
    "passwordDigestor" : "server"
}

问题2: 创建用户时提示timeout
报错如下:
提示不能创建用户,等待同步超时;

shardrs1:PRIMARY> db.createUser({user:"user2",pwd:"123456",roles:[{role:"readAnyDatabases",db:"admin"}]})
2019-07-10T15:58:00.711+0800 E QUERY    [js] Error: couldn't add user: waiting for replication timed out :
_getErrorWithCode@src/mongo/shell/utils.js:25:13

原因:主要是因为我们这个复制集架构是Primary+Secondary+Arbiter,而create user时secondary节点由于某些原因正处于unreachable状态(或者处于Recovering也会发生类似状况),db.createUser()方法有个默认参数选项w: "majority",即write concern特性(写关注),表示createUser命令必须同步到复制集架构的大部分数据节点才能返回ok,而此时secondary节点宕机,arbiter节点又不保存数据,从而未能达到其majority(大多数)节点的要求,当持续时间超过wtimeout参数选项指定时间后就会报错。从官方文档我们也能看到这样的解释
If run on a replica set, db.createUser() is executed using majority write concern by default.
解决办法:
方法1:如果不着急创建用户的话,那就先等secondary节点恢复正常以后再进行创建动作;
方法2:如果确实不能等,那就显示的指定w参数选项为1,如下命令格式;

shardrs1:PRIMARY> db.createUser({
    user:"user2",
    pwd:"123456",
    roles:[{role:"readAnyDatabases",db:"admin"}]
    },
    {w:1})

2.登录问题

刚才上面其实也已经讲过,登录连接数据库时一定要用对认证库,用户在哪个库下创建,就使用哪个库,使用错就无法登录成功,而有时候不是这些原因,而是因为开发语言版本问题导致的登录失败,这是我遇到过的一个问题
报错如下:
当时开发人员想要使用Java连接mongodb3.2版本,但总是报Failed to authenticate to database

org.springframework.data.mongodb.CannotGetMongoDbConnectionException:
Failed to authenticate to database [local], username = [appuser], password = [a*****r]`

原因:刚开始以为是防火墙问题,关闭之后也不行,关闭权限认证机制之后,开发就可以连接,所以认为是权限的问题,随后给了开发管理员权限,可是依然没有解决问题;后来查询到可能是java使用的驱动版本问题;开发使用版本:2.10.1,而MongoDB版本是3.2.10,由于3.x之后默认的认证机制从原先的MONGO-R变更为SCRAM,需要升级到最低要求的驱动版本

解决办法:升级JAVA的驱动版本到2.13, 当然你也可以通过官网来查看驱动版本的最低要求:SCRAM官网解释

最后

上述只是我平时较为遇到常见的权限相关的问题,记录于此,当然后续我也会持续更新本文章,如果其他问题也可以留言给我,也可以加入QQ群进行问题讨论:521548981

上一篇 下一篇

猜你喜欢

热点阅读