1、介绍
本文讨论保护MongoDB数据库所需的访问控制。具体来说,我们可以使用这些特性来确保只有经过授权的用户才能访问数据库。每个MongoDB用户应该只能访问他们在组织中所扮演的角色所需要的数据,这由组织中负责管理数据安全的人员来决定。这是管理数据和遵守国际要求所必需的良好特质。
1.1 访问控制
访问控制确保访问数据库的人员得到明确的标识,并且能够访问、更新或删除他们有权访问的数据。这是我们将在本文中讨论的主题。在数据库中,我们可以处理客户机的身份验证和它们希望执行的操作的授权。
1.2 认证
当客户机或用户访问数据库时,第一个任务是检查该用户是否是已知用户,并提供凭证以确保能够令人信服地识别他们,这就是所谓的身份验证。使用MongoDB,我们可以使用以下工具之一来处理认证问题。
1.2.1 内部工具
SCRAM:MongoDB默认身份验证机制。它根据用户名、密码来进行数据库身份验证。
x.509证书:该机制使用x.509证书代替用户名和密码。基于副本集或分片集群中的服务器或成员对客户机进行身份验证。维基百科上说:“x.509证书包含公钥和标识,由证书颁发机构或自签名,持有证书的人可以依赖证书所包含的公钥来建立安全通信”。
1.2.2 外部工具
LDAP:这个协议最常见的用途是提供一个中心服务器来存储用户名和密码,允许不同的应用程序连接到LDAP服务器来验证用户。
Kerberos:这是一个基于票据的行业标准认证协议。
注解:外部工具只在MongoDB企业版中提供。
作为一种最佳实践,我们将为需要访问数据库的每个实体创建登录凭据,但只针对这些实体。这样做,我们将能够审计所有用户所做的所有活动,并完成GDPR要求。除了用户身份验证之外,还需要对服务器和网络进程进行身份验证。在一套副本或分片集群的所有节点检查彼此不断为了确保都是已知的访问用户(换句话说,确认他们的会员),以及其他任务,比如检查每个成员的健康为了确定副本必须完成一次新的选举。那么什么是选举呢?在MongoDB中,只有一个节点能够执行写操作。当此节点关闭或网络部分开始工作时,其余节点开始进行一次选择,以便选择新的主节点并使服务在不停止的情况下运行。
1.3 授权
数据库管理员负责向用户授予或拒绝对数据库资源进行操作的权限。通过使用角色,我们可以指定对资源执行什么操作。因此,角色是授予用户使用特定资源执行特定任务的权限。
资源←动作←角色(权限)→用户
MongoDB提供内置角色,还允许您根据数据库的特定需求定义新的角色。这些角色是根据对资源的操作来定义的。动作是我们可以对数据库进行所有类型的操作,例如查找、删除、插入、更新或创建索引。资源可以是集合、文档、索引、数据库等等。使用只读视图,管理员通过限制对只公开其子集的敏感数据的访问来获得字段级安全性。对视图授予的权限与授予底层集合的权限是分开指定的。每个角色只应该为该角色授予必要的权限,并且只应该为用户分配适合其需求的角色。
1.4 数据库的身份验证
MongoDB用户必须使用最初创建它们的数据库来标识自己。这通常是管理数据库,但也可以是其他数据库。无论在哪个数据库上创建了用户,如果将适当的角色授予了用户,他们将能够对其他数据库采取操作。
2、MongoDB用户
在启用访问控制之前,应该创建一个用户,该用户可以在启用访问控制后创建用户并为用户分配角色。然后,这个用户管理员将用于创建和维护其他用户和角色,因此需要分配一个合适的角色来支持。如果你不创建此管理用户,则在启用访问控制时将无法登录或创建新用户和角色。
2.1 本地主机异常
如果在没有创建至少一个管理用户的情况下启用访问控制,则无法登录。localhost异常允许您在启用访问控制之后创建第一个用户,从而避免了这个问题。要做到这一点,你需要:
这个localhost异常只适用于仍然没有创建用户的情况。您必须在两个选项中进行选择,在启用访问控制之前创建第一个用户,或者在启用访问控制之后使用localhost异常创建第一个用户。
2.2 如何启用访问控制
在启动mongod服务时,可以使用参数指定数据库的特性,或者更好的方法是使用配置文件。无论哪种方式,你都必须使用安全选项:
security
authorization:enabled
此设置启用或禁用基于角色的访问控制(译者注:上面的配置是激活状态)。
2.3 如何创建用户
在创建MongoDB用户之前,有必要考虑一下用户将要执行的任务。可能会有几个具有相同权限级别的用户,所以最明智的选择是创建一个角色并将其分配给每个用户。通过只更改一个角色,您将更新所有使用它的用户的权限。否则,需要为每个用户对一组或一类用户的访问需求进行更改。操作步骤如下:
第一步:将上下文更改为要创建角色的数据库:
use admin
第二步:执行这个命令:
> db.createUser({
user : '<userName>',
pwd : '<password>',
roles : [ { role : '<roleName>', db : '<dbName>' } | '<roleName>', …]
})
如果您想创建一个用户而不为该用户分配任何角色,您只需指定一个空的roles字段。
注解:如果您还在掌握MongoDB查询语言,像MongoDB IDE Studio 3T这样的工具有一个直观的用户管理器特性,这使得用户管理更加直观和直观。
MongoDB IDE Studio 3T地址:https://studio3t.com/
用户管理器地址:https://studio3t.com/knowledge-base/articles/user-manager/
2.4 如何删除一个用户
假设您有合适的登陆角色并允许删除用户,您将需要将上下文更改到创建数据库的时候,
use admin
之后执行如下命令:
db.dropUser('<userName>')
2.5 用户存储在哪里?
要检查用户,必须将上下文更改为创建用户的数据库的情景,例如管理员数据库。
> use '<dbName>'
然后您可以使用其中之一
> db.system.users.find()
或者
> db.getUsers()
但是,如果您只想询问特定的用户,请使用以下命令:
> db.getUser('<userName>')
2.6 如何登陆?
有三种可能的情况,显然它们都有相同的哲学。让我们来看看:
2.6.1 在数据库内部
$ mongo
> use '<dbName>'
> db.auth('<userName>','<password>')
我不建议您使用此方法,因为在您键入密码时密码是可见的。
2.6.2 通过Shell脚本
$ mongo --authenticationDatabase <dbName> -u <userName> -p
MongoDB shell version v3.6.4-rc0
Enter password:
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.4-rc0
MongoDB Enterprise >
这是我的首选。在本例中,如果不指定authenticationDatabase参数,数据库将始终尝试根据将要连接到的数据库对用户进行身份验证。如果我们不指定要连接的数据库名称,就像我在上面的示例中所做的那样,服务器将对“test”数据库执行此操作。
2.6.3 通过MongoDB客户端
从MongoDB客户端,我们必须使用这样的连接字符串:
mongo://<userName>:<password>@<hostName>:27017/<dbName>?options
2.7 怎样注销
注销结束当前身份验证会话。您必须在经过身份验证的同一数据库中执行此操作。
> use admin
> db.logout()
3、MongoDB角色
正如您已经知道的,角色是授予用户对资源执行操作的特权。角色定义角色成员可以执行的任务,以及可以执行这些任务的资源。MongoDB为最常见的情景提供内置角色。但是,也允许我们根据自己的特定需求创建自己的角色。每个角色的作用域都限定在创建它的数据库中。角色只能包含应用于其数据库的特权,并且只能从其数据库中的其他角色继承特权。在管理数据库中创建的角色可以包含应用于管理数据库、其他数据库或集群资源的特权,还可以继承其他数据库和管理数据库中的角色。因此,如果需要从另一个数据库中创建的角色继承,则必须在管理数据库中创建新角色。
3.1 角色存储在哪里?
之前已经解释过,您可以在管理数据库或任何其他数据库中创建角色。因此,如果你想检查它们,你必须在定义它们的数据库中进行:
> use '<dbName>'
要获取数据库的所有角色,请使用
> db.system.roles.find()
或者
> db.getRoles()
如果你只想要一个特定的角色,你可以使用这个命令:
> use '<dbName>'
> db.getRole('<roleName>')
3.2 内置的角色
MongoDB将内置角色分类为:
下面将详细介绍每一个角色。
3.2.1 数据库用户角色
数据库级别角色如下:
3.2.2 数据库管理员角色
可以使用的数据库管理员角色如下:
dbAdmin——授予执行管理任务的特权
userAdmin——允许您在当前数据库上创建和修改用户和角色
dbOwner——此角色结合了以下内容:
readWrite
dbAdmin
userAdmin
3.2.3 集群管理员角色
用于管理整个系统的管理数据库中的角色。
clusterMonitor——提供对监视工具的只读访问
clusterManager——用于管理和监视集群上的操作
hostManager——监视和管理服务器
clusterAdmin——结合了其他三个角色和dropDatabase操作
3.2.4 备份和恢复角色
这个角色属于管理数据库。
backup——提供备份数据所需的特权
restore——提供从备份中还原数据所需的特权
3.2.5 所有数据库角色
这些角色位于管理数据库上,并提供适用于所有数据库的特权。
readAnyDatabase——与“read”角色相同,但适用于所有数据库
readWriteAnyDatabase——与“readWrite”角色相同,但适用于所有数据库
userAdminAnyDatabase——与‘userAdmin’角色相同,但适用于所有数据库
dbAdminAnyDatabase——与“dbAdmin”角色相同,但适用于所有数据库
3.2.6 超级用户角色
以下角色不是直接的超级用户角色,但是能够为任何用户分配任何数据库上的任何特权,也包括他们自己。
userAdmin
dbOwner
userAdminAnyDatabase
root角色提供对所有资源的完全特权:
root
3.3 如何检查角色的特权
如果需要知道角色的特权(是否从其他角色继承),可以通过 “showPrivileges”字段来进行激活:
> use '<dbName>'
> db.getRole('<roleName>', { showPrivileges : true })
3.4 角色汇总
管理MongoDB资产的人必须为自己的用例找到最合适的角色。在我看来,以下角色通常是最有用的:
3.5 如何授予用户角色
您可以在创建用户时授予角色,也可以在事后授予角色。下一个命令对于在创建用户的同时分配角色是有效的:
> use '<dbName>'
> db.createUser(
{
user: "<userName>",
pwd: "<password>",
roles: [ { role: "<roleName>", db: "<dbName>" } ]
})
你也可以用这个命令:
> use '<dbName>'
> db.grantRolesToUser(
'<userName>',
[ { role : '<roleName>', db : '<dbName>' }, '<roleName>', … ]
)
注解:第三方MongoDB工具中的角色管理器之类的功能在这里非常方便,特别是如果您还在学习MongoDB查询语言的时候。
3.6 如何从用户撤消角色
> use '<dbName>'
> db.revokeRolesFromUser(
'<userName>',
[ { role : '<roleName>', db : '<dbname>' } | '<roleName>' ]
)
3.7 自定义用户角色
3.7.1 怎样创建一个自定义角色
> use '<dbName>'
> db.createRole({
role: "<roleName>",
privileges: [
{ resource: { db : “<dbName>”,
collection : “<collectionName>” },
actions: [ '<actionName>' ]
}
],
roles: [ { role : '<fatherRoleName>', db : '<dbName>'} | '<roleName>' ]
})
3.7.2 怎样删除一个自定义角色
> use '<dbName>'
> db.dropRole('<roleName>')
3.7.3 如何授予或撤消自定义角色
这些命令是给自定义用户授予和撤销角色:
方案一:
> use '<dbName>'
> db.grantPrivilegesToRole(
'<roleName>',
[
{ resource : { db : '<dbName>', collection : '<collectionName'> },
actions : [ '<actionName>',... ]
},
...
]
)
方案二:
> db.revokePrivilegesFromRole(
'<roleName>',
[
{ resource : { db : '<dbName>', collection : '<collectionName'> },
actions : [ '<actionName>',... ]
},
…
]
)
3.7.4 对自定义用户角色怎样授予和撤销
方案一:
> use '<dbName>'
> db.grantRolesToRole(
'<roleName>',
[ { role : '<roleName>', db : '<dbName>' } | <roles> ]
)
方案二:
> db.revokeRolesFromRole(
'<roleName>',
[ { role : '<roleName>', db : '<dbName>' } | <roles> ]
)
3.8 怎样更新一个角色
小心!正如文档所述:“特权或角色数组的更新将完全替换前一个数组的值”。
> use '<dbName>'
> db.updateRole(
'<roleName>',
{
privileges : [
{
resource : { db : '<dbName>', collection : '<collectionName>' },
actions : [ '<actionName>' ]
},...
],
roles : [ { role : '<roleName>', db : '<dbName>' } | '<roleName>' ]
}
)
注解:您刚刚完成了MongoDB用户和角色解释系列的前半部分,MongoDB用户和角色解释系列的后半部分将了解如何在一个包含三个数据的节点副本集中启用访问控制,创建第一个使用localhost异常的用户,并授予所需的角色。敬请期待~~~
原文作者:Juan Roy Couto
Juan为了让自己成为目前MongoDB大师之一(https://www.mongodb.com/community/masters)。他获得了MongoDB认证,DBA和DEV。目前,他的工作角色是MongoDB数据库工程师。在此之前,在多家金融公司做了20年的开发。他喜欢与皇马的马克杯合作,也喜欢与技术社区交流。你可以在twitter.com/juanroycouto上阅读他的文章。
译者
管祥青
湖南大学研究生毕业,毕业后在海康威视研究院从事大数据研发及机器学习相关工作,现在就职于一家大数据金融公司。
本文分享自 Mongoing中文社区 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!