MongoDB安全审计auditing
1. 前言
在数据库安全的生命周期中, 包括: 保护、检测、响应和补救。检测的核心就是审计(Audit)。有些情况下,审计不仅仅用于检测不好的行为,也作为对整个数据库的行为进行监控而存在。审计能够告诉我们谁访问了什么、在什么地方、什么时间、采用了何种方式。
有效的审计不仅仅意味着安全,也有助于数据库整体完善。
2. 背景
最近公司老板强烈要求保障线上数据的安全性,要求完善MongoDB的安全审计, 增加认证记录,就是要知道谁登陆了、干了些什么。
查看了一下MongoDB的企业版包括了审计mongod服务和mongos路由器的能力。允许管理员和用户跟踪系统活动,支持各种操作审计。一个完整的审计解决方案必须包括所有的mongod服务和mongos路由器进程。
MongoDB的审计机构能够审计事件日志以输出在控制台(console),syslog,JSON文件或一个BSON文件四种方式。
但是这是在企业版中具有的功能,后来在Stack Overflow上看帖子说percona server for mongodb具有企业版的一系列功能,所以就果断研究了一下,花了半天事件成功的研究出来了。percona牛b伟大。
本文主要就是来记录一下整个的配置过程,查缺补漏,做个记录,以便于后来使用。
3. replicaset集群搭建
本文主要针对mongo-3.4版本, 是基于percona-server-mongodb-3.4.20*
推荐使用RPM包安装, 可以把服务基于systemd进行管理, 稳定性更好
版本进行的搭建测试; 其他版本的下载地址可以到这里去[https://www.percona.com/downloads/] 选择你需要的版本;
3.1 配置文件
原来的时候配置文件主要以普通配置文件的方式, 这一次改了一下用yaml格式的配置文件重写了配置; yaml格式的看起来更加系统清晰一些, 推荐使用;
老式配置文件:
port=27017
dbpath=/data/mongodb/data
logpath=/data/mongodb/log/master.log
pidfilepath=/data/mongodb/data/master.pid
directoryperdb=true
logappend=true
fork=true
replSet=myrepl
bind_ip=0.0.0.0
oplogSize=1000
noprealloc=true
maxConns=20000
auth=true
keyFile=/usr/local/mongodb/mongo_replicaset_key
yaml格式的配置文件mongo.conf:
storage:
dbPath: /var/lib/mongo # 数据存储地址
journal: # 是否启用journal日志
enabled: true
engine: wiredTiger # 引擎类型, 如果设置为默认, 启动后无法切换引擎
directoryPerDB: true # 是否每个db保存为一个目录
 
processManagement:
fork: true # 是否fork子进程
pidFilePath: /var/run/mongod.pid # pid文件的存储路径
 
systemLog:
destination: file # 日志的输出格式
logAppend: true # 是否追加日志
path: /var/log/mongo/mongod.log # 日志的存储路径
 
replication: # 副本集相关配置
oplogSizeMB: 1000 # oplog文件的最大大小
replSetName: myrepl # 副本集的名称
secondaryIndexPrefetch: all #
 
security:
keyFile: /var/lib/mongo/mongo_replicaset_key # 集群通信用的key
clusterAuthMode: keyFile # 集群通信认证方式
authorization: enabled # 是否启用登录认证
 
net:
port: 27017
bindIp: 0.0.0.0
maxIncomingConnections: 20000
 
auditLog: # 启用审计
destination: file # 审计日志的存储方式
format: JSON # 输出文件的存储格式
path: /var/log/mongo/auditing.json # 日志存储地址
配置项的写法都差不多, yaml格式严格了配置的格式, 全部采用小驼峰式写法, 更加系统化; 新的配置文件中加入了auditLog配置段, 这一段的配置就是为了启用审计, destination是输出的日志类型, 可以选择[ syslog | file | console], format可以选择[JSON | BSON], 其他配置的意思都比较明晰, 就不再赘述;
注意: 由于集群启用了登录认证, 所以第一次启动时, 需要将
security相关的配置段先注释掉, 等待登录用户创建完成后, 停止mongod, 开启配置, 重启mongod;
3.2 replicaSet集群搭建
首先生成集群认证用的秘钥文件:
> openssl rand -base64 64 > /usr/local/mongodb/mongo_replicaset_key
> chmod 600 /usr/local/mongodb/mongo_replicaset_key
集群在初始搭建需要先关闭认证功能, 创建角色后, 再将集群认证功能打开
将security: authorization: disabled
这里是用了三个节点的集群; 分别启动三个集群后mongod -f mongod.conf, 连接其中一个节点进行配置;
集群配置如下:
> use admin
> cfg={
_id:"myrepl",
members:[{_id: 0, host: "192.168.1.154:27017", priority: 2},
{_id: 1, host: "192.168.1.155:27017", priority: 1},
{_id: 2, host: "192.168.1.156:27017", arbiterOnly: true}
]}
> rs.initiate(cfg); # 集群初始化
> rs.status() # 查看集群状态
3.3 添加权限
具体的权限介绍, 请查看这里MongoDB用户角色身份认证
3.3.1 生成秘钥文件
openssl rand -base64 64 > keyfile.dat
chmod 600 keyfile.dat
3.3.2 创建集群用户
连接mongod
# 创建admin库的超级管理员用户
> use admin
> db.createUser({
user: "yourUserName",
pwd: "yourPasswd",
roles: [{role: "root", db" admin"},{role: "clusterAdmin", db:"admin"}]
})
# 普通书库的管理用户
> use 新库
> db.createUser({
user: "yourUsername",
pwd: "yourPasswd",
roles:[{role: "dbOwner", db:"你的新库"},{role: "clusterAdmin", db:"admin"}]
})
3.3.3 启用集群的认证
将各个节点配置文件中的 security字段的配置取消注释, 重启mongod登录测试
# 登录方式一
$ mongo 127.0.0.1:27017/admin
> db.auth("Username", "Passwd")
# 登录方式二
$ mongo -u "username" -p "passwd" --authenticationDatabase admin 127.0.0.1:27017
4. 审计日志区域字段解析
文件内容示例:
{
"atype": "authenticate",
"ts": {
"$date": "2019-05-28T09:22:01.787+0800"
},
"local": {
"ip": "192.168.1.154",
"port": 27017
},
"remote": {
"ip": "127.0.0.1",
"port": 50398
},
"users": [{
"user": "firm",
"db": "admin"
}],
"roles": [{
"role": "clusterAdmin",
"db": "admin"
}, {
"role": "root",
"db": "admin"
}],
"param": {
"user": "firm",
"db": "admin",
"mechanism": "SCRAM-SHA-1"
},
"result": 0
}
4.1 审计内容领域主要包括以下:
| 字段 | 类型 | 记录描述 |
|---|---|---|
| atype | string | 记录审计事件的行动, 详细信息和结果 |
| ts | document | 文档包含"$date"日期键值对, 其中是以时间戳格式的值 |
| local | document | 文档包含ip键值对, 及port键值对 |
| remote | document | 文档包含与事件相关联的远程连接ip键值对和port键值对 |
| users | array | 用户识别文档数组; 由于MongoDB允许登录不同的用户数据库, 该数组可以有一个以上的用户; 每个文档包含用户名的user字段和该用户身份验证数据库的db字段 |
| roles | array | 指定给用户的角色的文档数组, 每个文档包含角色名称的role字段和该角色关联的数据库的db字段 |
| param | document | 定义审计事件的具体细节, 详细键下表 |
| result | integer | 错误代码 |
4.2 审计事件行为, 具体信息和结果
以下表列出了每一个atype的相关参数细节和结果值
| atype | param | result |
|---|---|---|
| authenticate | { user: <user name&, db: <database&, mechanism: <mechanism& } |
0 - 表示认证失败 1 - 表示认证成功 |
| authCheck | { command: <name&, ns: <database&.<collection&,(可选) args:<command object&(args可编辑) } |
0 - 表示成功 13 - 表示没有权限的操作 |
| createCollection | 0 - 表示成功 | |
| createDatabase | 0 - 表示成功 | |
| createIndex | { ns: <database&.<collection&, indexName: <index name&, indexSpec: <index specification& } |
0 - 表示成功 |
| renameCollection | { old: <database&.<collection& new: <database&.<collection& } |
0 - 表示成功 |
| dropCollection | 0 - 表示成功 | |
| dropDatabase | 0 - 表示成功 | |
| dropIndex | { ns:<database&.<collection&, indexName: <index name& } |
0 - 表示成功 |
| createUser | { user: <user name&, db: <database&, customData: <document&, roles: [ { role: <role name&, db: <database& }, ... ] } |
0 - 表示成功 |
| dropUser | { user: <user name&, db: <database& } |
0 - successful |
| dropAllUsersFromDatabase | 0 - successful | |
| updateUser | { user: <user name&, db: <database&, passwordChanged: <boolean&, customData: <document&,(可选) roles:[ { role: <role name&, db: <database& }, ... ] } |
0 - successful |
| enableSharding | 0 - successful | |
| removeShard | 0 - successful | |
| shutdown | {} | 0 - successful |
浙公网安备 33010602011771号