MongoDB 基础系列十九:安全

前言

此篇博文是 Mongdb 基础系列之一;

本章节只对 MongoDB 的基本概念和操作上的进行梳理,并不做深入分析;

本文为作者的原创作品,转载需注明出处;

如何开启验证

开启访问控制( Access Control )

MongoDB 默认情况下并不会开启访问控制( Access Control ),也就是说,用户可以随意访问 MongoDB 上的任何资源;有三种方式可以开启访问控制,

  1. 通过 configuration file 设置
    在我本地 mac 系统中,配置文件的路径在 /usr/local/etc/mongod.conf 中,linux 系统配置文件的路径一般在 /etc/mongod.conf 中;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    security:
    enableEncryption: <boolean>
    encryptionCipherMode: <string>
    encryptionKeyFile: <string>
    kmip:
    keyIdentifier: <string>
    rotateMasterKey: <boolean>
    serverName: <string>
    port: <string>
    clientCertificateFile: <string>
    clientCertificatePassword: <string>
    serverCAFile: <string>

    根据相关提示,在 mongod.conf 配置文件中配置好 security 节点便启动了 Access Control

  2. 通过--auth命令设置
    直接在启动 mongodb 的时候使用--auth选项,既开启了访问控制;比如,

    1
    $ mongod --auth --dbpath ~/data/mongodb
  3. 启用内部验证机制( Internal Authentication )
    该机制主要用在主从集群中或者是分片集群中,可以通过 keyfile 证书的方式在集群节点之间直接进行验证,省去了繁琐的账户的验证流程;更多详情参考 Internal Authentication

上述最常用的方式是 #2;

开启用户验证

MongoDB 是基于 RBAC ( role-based access control ) 既基于角色授权的访问控制模式的;所以,MongoDB 是基于用户的角色,通过角色判断用户有哪些权利( Previeges )来访问 MongoDB 的资源以及哪些用户可执行的操作;

创建用户管理员( User Administrator )

User Administrator:顾名思义,就是用来管理用户账户的管理员账户;

  1. 首先在不使用访问控制的情况下,开启一个 mongod 单机 MongoDB 实例,

    1
    mongod --port 27017 --dbpath /data/db1
  2. 连接该 MongoDB 实例

    1
    mongo --port 27017

    上述命令将会自动连接到本机 localhost 上;

  3. 创建用户管理员,
    admin 的数据库中,添加一个用户角色为 userAdminAnyDatabase 的用户;

    1
    2
    3
    4
    5
    6
    7
    8
    use admin   
    db.createUser(
    {
    user: "myUserAdmin",
    pwd: "abc123",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
    }
    )

    备注,userAdminuserAdminAnyDatabase 等内置的角色提供了 createUsergrantRole 等操作的权利;

  4. 查看已创建的用户
    上述被创建的用户保存在 system.users 的 collection 中,可以使用如下的命令查看;

    1
    2
    3
    > db.getCollectionNames()

    [ "system.indexes", "system.users", "system.version" ]
  5. 尝试登陆,验证设置是否成功

    1
    2
    > db.auth("myUserAdmin","abc123%H")
    1
  6. 断开当前 mongo shell 连接;

    1
    > exit

添加用户

假设,我们需要在 reporting 数据库上创建一个 reportUser 的用户,

  1. 使用上述 myUserAdmin 账户登录

    1
    mongo --port 27017 -u myUserAdmin -p 'abc123' --authenticationDatabase 'admin'
  2. 添加用户

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    use reporting
    db.createUser(
    {
    user: "reportsUser",
    pwd: "12345678",
    roles: [
    { role: "read", db: "reporting" },
    { role: "read", db: "products" },
    { role: "read", db: "sales" },
    { role: "readWrite", db: "accounts" }
    ]
    }
    )

上述命令中,创建了一个用户名为 reportUser 的用户,并且拥有一系列的 roles;

注意,上面的这种创建方式并不是说只为 reporting database 创建一个唯一的用户 reportUser,reportUser 其实是创建在 system.users collection 中的;而判断某个用户在其它的数据库中是否有相应的权限,是通过该用户的角色 roles 来进行判断的;

权限架构设计:基于角色权限定访问控制系统

User、Role and Privileges

MongoDB 的访问控制系统基于用户角色的权限来建立的;用户的身份信息和角色是完全分离的;构成 MongoDB 访问控制系统的总共有四个元素,User、Role、Privilege;怎么来理解这三个元素呢?User 故名思议,就是用户的认证信息,既是用户名和密码;那么 Role 和 Privilege 之间的关系呢?一言以蔽之,一个 Role 是由一些列的 Privileges 所构成的;那么 Privilege 又是什么呢?

Privileges

一个 privilege 由一个特定的 resource 以及一系列被允许在该 resource 上进行操作的 actions 所组成;这里的 resource 既是指 MongoDB 中的一系列资源,可以是一个 database,一个或者多个 collection,或者指 cluster;actions 顾名思义,也就是在该 resource 上所允许的一些力操作( Operators ),参考 Privilege Actions 来了解总共都有操作(既是 actions);

Roles

Roles 是由一系列的 privilege 所构成的;下面来看一下 MongoDB 内置用户权限来深入理解

内置角色 ( Built-In Roles )

内置权限总共分为 Database User Roles、Database Administrator Roles、Cluster Administrator Roles、Backup and Restoration Roles、All-Database Roles、Superuser Roles 以及 Internal Role 七种类型;笔者就前面两种类型来单独介绍,其余的可以参考 https://docs.mongodb.com/manual/core/security-built-in-roles/

Database User Roles

  • read

    可以看到,read role 是由一系列的 actions 组成,包含 collStats, dbHash, dbStats, find … 等操作所组成;

  • readWrite

    可以看到,readWrite 是由上述这些 privilege actions 所组成

Database Administration Roles

  • dbAdmin
    该角色针对不同的 collection 有不同的权限操作,

    针对 System Collection

    针对非 System Collection

  • dbOwner

    The database owner can perform any administrative action on the database. This role combines the privileges granted by the readWrite, dbAdmin and userAdmin roles.

  • userAdmin
    正如前面所演示的那样,该 role 主要是用来创建用户账户以及 roles 相关的角色;

访问连接 https://docs.mongodb.com/manual/reference/built-in-roles/ 访问所有的内置 Roles;

用户自定义角色

首先使用 userAdminAnyDatabase 角色登录

1
mongo --port 27017 -u myUserAdmin -p 'abc123' --authenticationDatabase 'admin'

然后,使用下面的方式创建了一个新的名为 myClusterwideAdmin 的权限,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use admin
db.createRole(
{
role: "myClusterwideAdmin",
privileges: [
{ resource: { cluster: true }, actions: [ "addShard" ] },
{ resource: { db: "config", collection: "" }, actions: [ "find", "update", "insert", "remove" ] },
{ resource: { db: "users", collection: "usersCollection" }, actions: [ "update", "insert", "remove" ] },
{ resource: { db: "", collection: "" }, actions: [ "find" ] }
],
roles: [
{ role: "read", db: "admin" }
]
},
{ w: "majority" , wtimeout: 5000 }
)

上述命令所使用的格式为,

1
2
3
4
5
6
7
8
9
10
11
{
role: "<name>",
privileges: [
{ resource: { <resource> }, actions: [ "<action>", ... ] },
...
],
roles: [
{ role: "<role>", db: "<database>" } | "<role>",
...
]
}

注意,roles 字段表示的是当前所新建的 role 所继承的 roles;

https://docs.mongodb.com/manual/reference/method/db.createRole/#db.createRole

在某个 collection 上设置访问控制

在 collection 级别上设置访问控制是通过用户自定义角色的方式来设置的,通过自定义角色的时候,针对某个 collection 设置 privileges,既是将该访问控制限定在该 collection 上即可;比如我们在创建一个用户自定义的角色的时候,通过如下的方式将 actions 指定到某些特定的 collection 上即可;

1
2
3
4
privileges: [
{ resource: { db: "products", collection: "inventory" }, actions: [ "find", "update", "insert" ] },
{ resource: { db: "products", collection: "orders" }, actions: [ "find" ] }
]

加密

MongoDB 针对数据传输和数据加密提供了针对两个不同方面的加密方式,分别是传输加密(Transport Encryption)以及数据加密(Encryption at Rest)

https://docs.mongodb.com/manual/core/security-encryption/

传输加密

提供了 TLS / SSL 的加密方式

数据加密(Encryption at Rest)

针对数据加密的不同粒度,包含两种对数据加密的不同方式,应用层的数据加密( Application Level Encryption )以及存储引擎上的加密( Storage Encryption );

应用层数据加密

主要指的是对某个文档后者某个字段进行加密操作;

存储引擎加密

AES256

这里讲的是如何对整个存储引擎进行加密,里面提到的算法就是 AES256 相关的算法;

Key Management

Key Management Interoperability Protocol (KMIP)

审计 Auditing

https://docs.mongodb.com/manual/core/auditing/

MongoDB 的日志系统;

例子

TODO…

References

https://docs.mongodb.com/manual/core/authorization/
http://www.mzwu.com/article.asp?id=3324

整理思路

  1. 默认情况下,MongoDB 是不启用安全访问机制的既( Access Control ),需要手动启动..
  2. Authentication 系统
    通过 db.auth() 方法来验证用户
  3. Enable Auth
    • 综述
      如何创建 Admin 超级管理员
      如何创建部分授权的管理员用户
    • Manage Users and Roles
    • Change Your Password and Custom Data
  4. Role-Based Access Control
    创建 User,设置 Role,Role 是由 Privileges 构成的.. Privileges 既是设置对 resources 执行特定的权限操作;
  5. 加密
    • Transport Encryption
      TLS / SSL 链路层加密
    • Encryption at Rest
      提供了应用层的加密( Application Level Encryption )以及存储加密( Storage Encryption )
      • Encrypted Storage Engine
        AES256
        这里讲的是如何对整个存储引擎进行加密,里面提到的算法就是 AES256 相关的算法;
        Key Management
        Key Management Interoperability Protocol (KMIP)
      • Application Level Encryption
        主要指的是对某个文档后者某个字段进行加密操作;
  6. Auditing 审计
    日志系统

  7. Security Hardening

    To reduce the risk exposure of the entire MongoDB system, ensure that only trusted hosts have access to MongoDB.

    通过限制 IP 访问,限制给公网暴露的 REST 或者 HTTP 接口,来降低风险性;通过 iptables 建立 VPN 隧道的方式降低风险;

Mongodb 角色和用户

概念

Mongodb 目前拥有的主要角色有,前面四个都是只能在指定数据库中进行配置(其实就是指,不能在 admin 库中进行设置的角色),其余的都只能在 admin 库中进行设置,显然,这些角色都是管理员的角色;

角色 作用 如何设置
Read 允许用户读取指定数据库 在指定数据库中创建
readWrite 允许用户读写指定数据库 在指定数据库中创建
dbAdmin 允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile 在指定数据库中创建
userAdmin 允许用户向 system.users 集合写入,可以在指定数据库里创建、删除和管理用户 在指定数据库中创建
clusterAdmin 只在 admin 数据库中可用,赋予用户所有分片和复制集相关函数的管理权限 只能在 admin 数据库中创建
readAnyDatabase 赋予用户所有数据库的读权限 只能在 admin 数据库中创建
readWriteAnyDatabase 只在 admin 数据库中可用,赋予用户所有数据库的读写权限 只能在 admin 数据库中创建
userAdminAnyDatabase 赋予用户所有数据库的userAdmin权限 只能在 admin 数据库中创建
dbAdminAnyDatabase 赋予用户所有数据库的dbAdmin权限 只能在 admin 数据库中创建
root 超级账号,超级权限 只能在 admin 数据库中创建

查看

如何查看角色?使用 show users 命令,

1
2
use admin
show users

要注意的是,Mongodb 3.0 以后,角色必须创建在某个库中,因此要查看用户角色的话,必须先定位到该库中;

更新

  1. 更新 admin 角色的权限
    如果我想把某个 admin 用户的 userAdminAnyDatabase 的权限改成 root 权限,怎么操作呢?首先,要关闭认证,启动 mongodb

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    > use admin
    switched to db admin
    > show users
    {
    "_id" : "admin.fishsir",
    "user" : "fishsir",
    "db" : "admin",
    "roles" : [
    {
    "role" : "userAdminAnyDatabase",
    "db" : "admin"
    }
    ]
    }

    那么我如何将它改变成 root 权限呢?

    1
    > db.updateUser('fishsir', { roles: [{role: 'root', db: 'admin'}]})

    https://docs.mongodb.com/manual/reference/method/db.updateUser/

  2. 更新普通用户的权限,这种情况,不建议使用上述的方式,应该是在启动了安全认证的 Mongodb 上使用 userAdminAnyDatabase 或者 root 角色来对用户进行更新;

References

https://docs.mongodb.com/v3.4/security/
https://www.cnblogs.com/nixi8/p/4849314.html
http://www.cnblogs.com/zhoujinyi/p/4610050.html
https://docs.mongodb.com/v3.4/tutorial/enable-authentication/