• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

MongoDB认证与授权详解

MongoDB 彭东稳 8年前 (2016-08-25) 32008次浏览 已收录 0个评论

一、MongoDB权限控制系统简介

对于数据库的管理,一般 DBA 都不会给开发过大的权限,避免如开发建立索引不加 [backgroud:true] 导致线上操作巨卡、误删除业务库或集合数据、对集合每个字段添加单列索引导致容量急剧膨胀,还有各种突破认知范围的误操作。由于 MongoDB 早期版本自身对权限控制极其简单粗暴,一般 DBA 都是授予开发最高权限。随着 MongoDB 3.X 版本的发布,在权限控制这块算是比较完善了,下面主要介绍 MongoDB 权限控制系统。

默认情况下,MongoDB 不启用访问控制。你可以使用--authsecurity.authorization设置启用用户身份验证,要求用户标识自己。启用了访问控制的 MongoDB,用户只能执行由其角色定义的操作,未定义的操作则无法执行。

要想理解清楚 MongoDB 的权限必须先了解如下一些关键字。

user

即用户,用于提供客户端连接 MongoDB 的认证账户。

role

即角色,对资源执行指定操作的权限集合,创建用户的时候必须要指定对应的角色,否则用户无法操作数据库。角色授予对资源执行指定操作的权限。每个权限要么在角色中显式指定,要么从另一个角色继承,要么两者兼而有之。

resource

即资源,包括 database 或 collection,也可以是 database 和 collection 的组合。例如:{ db: <database>, collection: <collection> },当然你也可能看到一种特殊的资源:{“cluster” : true},它其实表示的是全局资源。

actions即权限操作,actions 定义了 user 能够对 resource document 执行的操作。例如,增删改查包括如下操作:find、insert、remove、update。privilege

即权限,privilege 是一组 resource 和 actions 的组合。也就是权限由指定的资源和允许在资源上执行的操作组成。

authenticationDatabase

认证库,即创建角色或用户时所在的库。例如,在 admin 库下创建了 MongoDB 用户,那么登陆的时候需要指定认证库为 admin。

二、MongoDB基于角色的访问控制

MongoDB 使用基于角色的访问控制(RBAC)来管理对 MongoDB 系统的访问。为用户授予一个或多个角色,以确定用户对数据库资源和操作的访问权限。在角色分配之外,用户无法访问系统。

角色是什么?就是对某一资源的权限的“集合”。在 MongoDB 中有两种角色,一种是内置的已经定义好的角色,一种是自定义的角色。下面先说说内置的角色,可满足大部分用户的需求。

第一种:内置角色介绍

数据库用户角色

read

提供读取所有非系统集合和以下系统集合:system.indexes,system.js 和 system.namespaces 集合上的数据的功能。

该角色通过授予以下操作来提供读取权限:

readWrite

提供 read 角色的所有权限以及修改所有非系统集合和 system.js 集合上的数据的功能。

该角色对这些集合提供以下操作:

数据库管理角色

每个数据库都包含以下数据库管理角色:

dbAdmin

数据库的管理权限,提供执行管理任务(如与 schema 相关的任务,索引和收集统计信息)的功能。此角色不包含授予用户和角色的管理权限。

对数据库的 system.indexes,system.namespaces 和 system.profile 集合提供以下操作:

对所有非系统集合提供以下操作,此角色不包括非系统集合的完全读取访问权限:

dbOwner

数据库所有者可以对数据库执行任何管理操作。此角色组合了 readWrite,dbAdmin 和 userAdmin 角色授予的权限。

userAdmin

提供在当前数据库上创建用户和修改角色的功能。由于 userAdmin 角色允许用户向任何用户授予任何权限,包括自己。该角色还间接提供对数据库的超级用户访问权限,如果作用在 admin 数据库上。

userAdmin 角色显式提供以下操作:

Tips:了解授予 userAdmin 角色的安全隐患非常重要:具有此角色的用户可以为该数据库分配任何权限。在 admin 数据库上授予 userAdmin 角色具有进一步的安全隐患,因为这间接提供了对集群的超级用户访问权限。使用 admin 作用域,具有 userAdmin 角色的用户可以授予群集范围的角色或权限,包括 userAdminAnyDatabase。

集群管理角色

admin 数据库包括以下角色,用于管理整个系统而不仅仅是单个数据库。这些角色包括但不限于副本集和分片集群管理功能。

clusterAdmin

提供最佳的集群管理访问。此角色组合了 clusterManager,clusterMonitor 和 hostManager 角色授予的权限。此外,该角色还提供了 dropDatabase 操作。

clusterManager

提供群集上的管理和监控操作。具有此角色的用户可以分别访问分片和复制中使用的 config 和 local 数据库。

clusterMonitor

在版本 3.4 中更改。

提供对监控工具的只读访问权限,例如 MongoDB Cloud Manager 和 Ops Manager 监视代理程序。

hostManager

提供监控和管理服务器的功能。在整个群集上提供以下操作:

备份和恢复角色

backup

在版本3.4中更改。

提供备份数据所需的最小权限。此角色提供了使用 MongoDB Cloud Manager 备份代理的足够权限,Ops Manager 备份代理,或使用 mongodump 备份整个 mongod 实例。

在 admin 数据库中的 mms.backup 集合和 config 数据库中的 settings 集合上提供插入和更新操作。

restore

所有数据库角色

在版本 3.4 中更改。 admin 数据库上提供以下角色。

readAnyDatabase

在 admin 数据库上提供的角色,并提供适用于除 local 和 config 之外的所有数据库的 read 权限。该角色还在整个群集上提供 listDatabases 操作。

在 3.4 版本中更改:在 3.4 之前,readAnyDatabase 包括 local 和 config 数据库。要在 local 数据库上提供读取权限,请在 admin 数据库中创建具有 local 数据库中的读取角色的用户。

readWriteAnyDatabase

在 admin 数据库上提供的角色,并提供适用于除 local 和 config 之外的所有数据库的 readWrite 权限。

userAdminAnyDatabase

在 admin 数据库上提供的角色,并提供适用于除 local 和 config 之外的所有数据库的 userAdmin 权限。

dbAdminAnyDatabase

在 admin 数据库上提供的角色,并提供适用于除 local 和 config 之外的所有数据库的 dbAdmin 权限。

超级用户角色

root

超级用户权限,只能针对 admin 库。

提供对 readWriteAnyDatabase,dbAdminAnyDatabase,userAdminAnyDatabase,clusterAdmin,restore 和 backup 组合的操作和所有资源的访问。

版本 3.4 中已更改:root 角色包括 backup 角色的权限。

root 角色包括 restore 角色的权限。

第二种:自定义角色

MongoDB 内置角色一般来说都是够用的,但是当内置角色不满足需求时就可以自定义角色了。

要添加角色,MongoDB 提供 db.createRole() 方法。 MongoDB 还提供了更新现有用户定义角色的方法。有关角色管理方法的完整列表,请参阅角色管理。

添加角色时,你可以在特定数据库中创建角色。 MongoDB 使用数据库和角色名称的组合来唯一地定义角色。

除了在 admin 数据库中创建的角色之外,角色只能包含适用于其数据库的权限,并且只能从其数据库中的其他角色继承。在 admin 数据库中创建的角色可以包括适用于 admin 数据库,其他数据库或群集资源的权限,并且可以从其他数据库以及 admin 数据库中的角色继承。

在数据库中创建角色。您可以通过显式列出权限或让角色继承其他角色或两者的权限来指定角色的权限。该角色适用于运行该方法的数据库。

db.createRole() 方法接受以下参数:

Parameter Type Description
role document 包含角色名称和角色定义的文档。
writeConcern document 可选的。应用于此操作的 writeConcern 级别。

role 文档具有以下形式:


role 文档包含以下字段:
Field Type Description
role string 角色的名称。
privileges array

授予角色的权限。权限由资源和允许的操作组成。有关权限的语法,请参阅privileges数组。

你必须包含权限字段,使用空数组表示无权限。

roles array

指定继承角色数组。

你必须包含 roles 字段,使用空数组表示不继承角色。

authenticationRestrictions array

可选的

服务器对角色执行的身份验证限制。可以指定 IP 地址,或 CIDR 范围列表。

New in version 3.6.

roles

在 roles 字段中,你可以指定内置角色和用户自定义角色。要指定存在于运行 db.createRole() 的同一数据库中的角色,你可以使用角色名称指定角色:

或者你可以使用文档指定角色,如下所示:

要指定存在于其他数据库中的角色,请使用文档指定角色。

使用 db.createRole() 方法在 admin 数据库上创建 myClusterwideAdmin 角色:

角色创建完毕后 MongoDB 会在系统库 admin 下创建一个系统 collection 名叫 system.roles  里面存储的即是角色相关的信息。

可以使用如下语句进行查看:


操作角色(以下操作都基于 admin 库)

使用db.getRole(rolename, args)查看指定角色信息。

使用db.getRole()查看所有角色信息。

使用db.grantRolesToRole()授予权限到角色。

案例:

使用db.grantRolesToRole( "<rolename>", [ <roles> ], { <writeConcern> } )授予角色到角色。

使用db.revokeRolesFromRole( "<rolename>", [ <roles> ], { <writeConcern> } )从角色移除角色。

使用db.dropRole(rolename, writeConcern)删除指定角色。

使用db.dropAllRoles(writeConcern)删除所有角色。

使用db.grantPrivilegesToRole() 授予权限到角色。

还有如 db.updateRole() 更新角色,db.revokePrivilegesFromRole() 从角色中移除权限。

MongoDB 将所有角色信息存储在 admin 数据库的 system.roles 集合中。

三、MongoDB用户认证授权说明

身份验证是验证客户端身份的过程,启用访问控制(即授权)后,MongoDB 要求所有客户端对自己进行身份验证,以确定其访问权限。

尽管身份验证和授权密切相关,但身份验证不同于授权。身份验证是验证用户的身份,授权决定了经过验证的用户对资源和操作的访问。

  • MongoDB单实例认证

MongoDB 安装时不添加任何参数,默认是没有权限验证的,登录的用户可以对数据库任意操作而且可以远程访问数据库,如果需要开启 MongoDB 身份验证,那么需要在命令行启动 MongoDB 时加上--auth参数启动(或配置文件中使用 auth=True),这样当 MongoDB 启动后再次登录就需要用户和密码进行认证了。

在刚安装完毕的时候,MongoDB 都默认有一个 admin 数据库,此时 admin 数据库是空的,没有记录权限相关的信息。当 admin.system.users 一个用户都没有时,如果 mongod 启动时添加了--auth参数,那么就尴尬了。

MongoDB 的访问分为认证和授权,所以使用--auth参数开启认证后,虽然还是可以不进行认证直接进入数据库,但是不会有任何的权限进行任何操作,当执行命令时会报如下错误:

由此看出,一旦开启认证后授权就会生效了。如果登录时没进行用户认证,那么就没有任何权限执行任何命令。此时有两种办法,第一就是关掉 MongoDB,先添加完用户再开启用户认证;第二种就是 MongoDB 还提供了一个参数,就是在开启认证的情况下允许本地连接 MongoDB,就是使用 localhost 连接,其余一律不接受。此时就可以把这两个参数同时使用上,即开启认证时又没有添加任何用户的情况下允许本地无认证连接进行数据库操作。

注意:这个参数的使用有如下几条限制。

1)这个参数只能在开启认证的情况下,并且没有任何用户的情况下才生效,否则无效。

2)满足第一个条件时,只允许本地以 localhost 的方式进行连接 MongoDB,否则无效。

3)满足第一个条件时,当进入到 MongoDB 后如果创建了一个用户后,此参数将失效,就是本地无法登陆了。

4)以此方式创建的用户必须是 admin 库进行的,同时必须能够具备创建其他用户的权限。

在 MongoDB 授权部分,其中 admin 数据库中的用户名可以管理所有数据库,其他数据库中的用户只能管理其所在的数据库。在 2.4 之前版本中,用户的权限分为只读和拥有所有权限。2.4 版本的权限管理主要分为:数据库的操作权限、数据库用户的管理权限、集群的管理权限,建议由超级用户在 admin 数据库中管理这些用户。不过依然兼容 2.4 版本之前的用户管理方法。

  • MongoDB复制集认证

上面说的都是针对单实例 MongoDB,如果使用 MongoDB 复制集的话,那么情况与一点点变化了。如果在复制集机制下开启了--auth认证,那么此时 MongoDB 复制集状态就会变成不健康状态,这就需要另外一个认证方式了 “KeyFile”。简单来说 “KeyFile” 就是用在复制集群间开启认证的情况下需要的另外一种认证方式,用来验证集群间身份的。在复制集模式下,开启 KeyFile 之后就需要再开启你--auth了,因为开启 KeyFIle 后就会自动开启认证功能。

开启 KeyFile 也非常简单,需要在每个节点主机上创建一个文件,然后给一些字符串,但是复制集各个节点上的字符串必须相同,才能进行身份验证。如下所示,手动生成一个 KeyFile:

生成 KeyFile 时需要注意,不用在意空格、tab 以及换行符的,KeyFile 都会自动去掉的。

KeyFile 注意事项:

内容:base64编码,所以不能超出这个范围[a-zA-Z+/]

长度:1000bytes

权限:chmod 600 KeyFile

KeyFile 生成好之后,就可以同步到各个节点间了,然后在各个节点的配置文件中把 KeyFile 文件指定进来即可。

然后给权限为 600 即可。

前面已经说了,开启了 KeyFile 后就不需要添加 auth=true 参数了,默认会开启认证的。然后重启复制集各个节点就完成认证了。

另外在复制集模式下,在整个认证配置完成前不要创建任何用户,当整个认证好了之后,下面就可以创建用户了。

四、MongoDB用户管理

以下讲解都是基本 MongoDB 3.0+ 以上的版本。

1. 不开启认证,进行用户创建

首先,我们需要在不认证的情况下在 admin 库中创建一个管理用户,也就是需要在不认证情况下启动 MongoDB。

给出一个简单的配置文件,具体安装配置 MongoDB 可以看 MongoDB安装

启动 MongoDB

接着,打开 mongo shell 连接到 mongod。在命令窗口中输入:

看到只有一个 local 数据库,admin 是不存在的(这是 3.0 以上版本改变了的),我们需要自己给他创建个 admin 数据库。

添加用户时,可以在特定数据库中创建用户,该数据库是用户的身份验证数据库。使用 db.createUser() 接口创建用户,此接口提供了很多可选参数,具体看官网,这里只给常用的。

user:指定用户名。

pwd:指定用户密码。

roles:指定角色名称以及角色的认证库。

Note

启用访问控制后,请确保你拥有 admin 数据库中的用户,并且该用户有userAdminuserAdminAnyDatabase角色。该用户可以管理用户和角色,例如:创建用户,授予或撤消用户角色,以及创建或修改角色。

切换到 admin 下,查看刚才创建的用户。

怎么关闭 mongoDB?千万不要 kill -9 pid,可以 kill -2 piddb.shutdownServer()

Note

你创建用户的数据库(在此示例中为 admin)是用户的身份验证数据库。虽然用户将对此数据库进行身份验证,但用户可以在其他数据库中拥有角色,即用户的身份验证数据库不限制用户的权限。也就说,用户可以拥有跨不同数据库的权限,用户的权限不限于其身份验证数据库。

2. 开启认证,进行用户认证

使用--auth参数启动 MongoDB,当添加完一个高权限用户后就可以开启认证了。在配置文件中添加 auth 参数,然后再开启 mongod。

打开 mongo shell 进行认证。

要以用户身份进行身份验证,你必须提供用户名,密码以及与该用户关联的身份验证数据库。

对于认证,我们可以有多种方式。我们可以选择在连接期间进行用户身份验证:

也可以在连接后使用 db.auth 方法进行身份验证:

认证成功后,我们可以查看一下集合:

会出现如下报错信息:

因为,用户 admin 只有用户管理的权限。

一旦管理员用户通过身份验证,就可以使用 db.createUser() 创建其他用户,你可以将任何内置角色或用户定义的角色分配给用户。但需要注意的就是,MongoDB 模式就是根据数据库进行用户身份验证,所以创建用户都是在某个库下面进行。

单用户有多个库的权限示例:

查看刚刚创建的用户

查看整个 MongoDB 全部的用户

创建完毕,验证一下

显然没有权限,那我们就先进行认证。

用户的名称和身份验证数据库充当该用户的唯一标识符。也就是说,如果两个用户具有相同的名称但是在不同的数据库中创建,则它们是两个单独的用户。如果你打算让单个用户拥有多个数据库的权限,请在适用的数据库中创建具有角色的单个用户,而不是在不同的数据库中多次创建用户。

3. 查看用户信息

使用 db.getUser() 方法返回指定用户信息。

还有一种需求,就是查看某个库关联的用户信息,可以使用 db.getUsers() 方法。

4. 修改用户密码

使用 db.changeUserPassword() 就可以修改用户的密码。

5. 删除用户

使用 db.dropUser(<user_name>) 进行指定用户删除。

还可以使用 db.dropAllUsers() 删除当前库的所有用户。

这样就是把 admin 库的所有用户都删除了。

在 MongoDB 中删除库和集合并不会级联删除对应的角色和用户。因此如果想彻底删除对应的业务库因该先删除库及其对应的角色和用户。

6. 用户授权

使用db.grantRolesToUser( "<username>", [ <roles> ], { <writeConcern> } )方法为用户授权,一般必要参数是 username 和 roles。对于 writeConcern,如果在副本集上运行,则默认情况下使用多数写入机制。

7. 用户移权

使用db.revokeRolesFromUser( "<username>", [ <roles> ], { <writeConcern> } )为用户移除权限。

如果既想实现精细化权限控制又想简化用户管理,原则上建议只给开发创建一个账户,并且使用 admin 做认证库,这样可避免清理过期业务库而导致无法登陆的问题。

<相关连接>

MongoDB 安全配置:https://docs.mongodb.com/manual/security/

MongoDB 内建角色:https://docs.mongodb.org/manual/reference/built-in-roles/

MongoDB 权限操作列表:https://docs.mongodb.org/manual/reference/privilege-actions/#security-user-actions

MongoDB 角色管理方法:https://docs.mongodb.org/manual/reference/method/js-role-management/

MongoDB 用户管理方法:https://docs.mongodb.org/manual/reference/method/js-user-management/


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (6)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!