作者 陈松威,18年硕士毕业于华中科技大学,目前在CDB/CynosDB数据库内核团队担任TXSQL云数据库内核研发,开发过的功能包括企业级列加密函数、数据恢复工具、异步审计等。
引言
一、什么是数据库审计
对于一个仓库,如果要防盗,常见做法是出入口全装上监控,一旦有问题了,调监控查找异常情况。对数据库来说也类似,数据库也有出入口,对所有连接出入口监控,可以记录下所有的动作,一旦有问题了,通过查询历史动作并进行分析,可以找到关键信息。故数据库审计可以理解为是记录用户访问数据库行为,定位非法动作,事后追根溯源,提高数据库安全性的功能。
二、常见的审计方式
在应用系统中直接审计,语句还没往数据库后台发就先做了审计,不影响数据库性能,对底层用的是什么数据库也不关心,但对应用系统压力比较大,并且应用系统需要解析语句,有一定复杂度。
往往抓包解析实现,对上下层都没什么影响,但同样要解析语句,有一定复杂度,并且如果传输层是通过加密通讯,将无法解析。
直接在内核上实现,所有功能都能实现,也能将性能影响降到最低,但是对后台稳定性会有影响,对开发人员要求高,不管是开源还是非开源数据库,都会非常慎重考虑直接在内核上支持审计。
对于开源数据库,通常都有提供插件方式增加功能。审计可以以插件直接嵌在内核上,当然会对数据库性能有一定影响,但同样因为直接嵌在内核,很多一手信息能直接拿到,比方说上面没办法回避的语法解析就不用做,而且还能直接拿更多的运行态信息,能开发功能强大又灵活的审计功能。
其中插件式审计由于对内核侵入小,可以动态安装、卸载和升级等优点,是较受青睐的审计实现方式。MySQL上也有不少审计插件,例如Macfee插件,官方audit plugin,mariadb audit plugin,Percona audit plugin。
从功能上而言,审计插件大同小异,只是展示的审计内容和格式略有差异。从实现方式而言,审计插件的数据来源近乎相同,而在规则过滤和刷盘策略上有较大的差别。从性能上而言,除了macfee插件外,其它几个性能相差不多,宣称都是15%左右影响,macfee则可能达到50%或更多。
总体而言,审计的性能影响不能一概而论,其与使用场景强相关。审计以query为单位记录审计日志,性能开销与QPS成正比。在OLAP场景下,一条query运行几秒,甚至几十秒,此时审计对性能的影响几乎可以忽略不计。如果场景被设定为简单查询语句,QPS高达几十万的话,可想而知对性能会造成一定影响。
三、MySQL官方审计插件
MySQL支持了MYSQL_AUDIT_GENERAL_ALL、MYSQL_AUDIT_CONNECTION_ALL等十余种审计插件的类型,用于对客户端连接、query处理、error log日志落盘、general log落盘等场景进行审计,审计插件的接口实现在sql目录下的sql_audit.h和sql_audit.cc中。不同的插件类型对应不同的代码观察点。审计插件的定义中需要选择一种或多种注册类型,审计插件安装后,相应的代码观察点即可被激活。当程序运行到被激活的代码观察点处时,将携带这些审计信息跳转至审计插件定义的对应观察点处理函数中,进行审计日志的规则判断,落盘等处理。
Query在运行过程中,程序会记录诸如用户名、客户端ip、操作类型等审计信息。以MYSQL_AUDIT_GENERAL_ALL为例,其记录的审计信息如下所示:
TXSQL审计的实现
TXSQL是腾讯云数据库团队维护的 MySQL 内核分支,100%兼容原生 MySQL 版本,TXSQL 提供了类似于 MySQL 企业版的诸多功能,如企业级透明数据加密、审计、线程池、加密函数、备份恢复等功能。
一、数据库审计架构
腾讯云数据库MySQL提供了基于TXSQL内核插件的数据库审计服务,其沿用了官方审计插件接口,并支持同步审计、异步审计两种审计架构。
1.同步审计模式
同步审计模式的架构如下图所示,左侧灰色部分对应数据库服务器mysqld,它采用线程池中相对固定的工作线程来处理所有用户的连接。工作线程每执行一个query或处理一个新的连接会生成一个审计event。工作线程需要结合审计规则判断当前event是否需要记录,如果需要记录,则将审计event按一定格式转化为审计日志,并拷贝到公共的Audit buffer中。Flush thread负责异步将Audit buffer中的审计日志落盘到本地。Audit agent负责将本地的audit log推送到CTSDB(腾讯云推出的一款分布式、可扩展、支持近实时数据搜索与分析的时序数据库)上进行存储,并提供查询。
接下来,详细聊一下同步审计的实现。下图左侧是一条query的执行过程,包括连接,语句解析、分析、语句重写、语句优化、语句执行、语句返回和资源释放等几个步骤。为了能获取query执行的影响行数、执行时间、错误码等内容,TXSQL审计选择了在语句返回之后,资源释放之前的观察点处理审计逻辑。下图右侧是同步审计的具体流程,工作线程在语句返回之后、进入审计观察点,如果实例没有开启审计,则直接进入资源释放步骤。如果用户开启了审计,进一步判断当前审计event是否需要记录。如果需要则获取审计内容并计算审计内容的长度。计算完审计日志长度后,加锁在公共Audit buffer中进行内存占位,接下来立刻释放锁,在无锁的情况下将审计event转化为json格式的审计日志并拷贝到公共Audit buffer中已占领的位置处。Flush线程异步将Audit buffer中的审计日志落盘到本地,等待Audit agent进行消费。
- 异步审计模式
同步审计模式在绝大多数场景下性能优异,但是在配置了多个正则审计匹配规则并且QPS非常高的场景下将出现大幅的性能下降。性能下降的根因是正则匹配的过程中需要malloc内存,在高并发高压力下malloc系统调用在内核态出现锁瓶颈,影响了整体性能。为了解决同步审计在个别场景下的性能问题,TXSQL还支持了异步审计模式。
上图是异步审计的架构图,由图可见,工作线程只需要将audit event交付给审计event队列后即可返回。新增write thread负责消费审计event队列,并完成剩余的审计规则判断、内存拷贝等工作。由于每个时间点并发malloc的线程数大幅下降,因此malloc系统调用的锁瓶颈不复存在。下图是异步审计的具体实现。write thread负责观察审计event队列,如果有需要处理的audit event,则将其摘下进行审计规则判断,如果需要记录该审计event则进一步进行审计内容长度计算、加锁进行内存占位、无锁内容转换和内存拷贝等工作。
二、数据库审计规则
目前TXSQL的数据库审计支持以下类型设置:客户端IP,数据库帐户,数据库名。支持的匹配方式为:包含,不包含,等于,不等于,正则 方式匹配。每条规则为一个结构对象,多条规则为一个链表,规则保存在内存中,全局共享,审计启动时从规则配置文件加载,修改、增加、删除时重新加载。
Rule list: 规则链表,每个规则对应前台配置的一个或多个,不能合并的多个规则之间是或(||)关系。
Content list: 单个审计规则,规则内容包含username,host, database3项。在Content规则内部,不同内容项之间是与(&&)的关系。
结构简图如下:
三、数据库审计性能
TXSQL提供的数据库审计开启后,对用户的数据库实例会有少许性能损耗,但远低于业内的其他解决方案。(业务使用场景、QPS、规则设置等均会影响数据库审计的性能开销)
同步审计模式的最大的特点在于工作线程在生产审计日志的过程中,计算审计内容长度、内容json转换和Audit buffer拷贝都是在无锁的情况下进行的。整个过程只有内存占位需要持有锁,临界区足够小,使得Audit buffer的写锁没有成为系统瓶颈,从而在绝大多数场景下保持了极高的性能。平均的性能影响只有6%。
异步审计模式对数据库审计性能有了进一步的提升,对实例的性能损耗更低。不论在正则规则下,还是在普通规则下,性能损耗最高只有3%左右,其能力领先于业界其它的数据库审计插件。
四、数据库审计最佳实践
理论上可以不对规则条数和语法进行做限制,但必须说明数据库审计的规则对整体性能消耗会产生一定的影响,为了能够在相同的规则下降低对数据库数据库实例的性能影响,提升数据库审计能力,在这里提出以下几点审计规则的最佳实践:
-
规则合并:多个规则之间如果指定的类型相同,应该尝试合并规则。如A规则审计数据库db1的select操作,B规则审计数据库db1的update操作,应当合并成审计db1的select和update操作。
-
优先原则:对同个实例上不能合并的多个审计规则,优先使用命中率高的特征。只要有一个规则匹配上就会对该SQL进行审计,其它规则不需要再进行判断,因此需要把命中率最高的规则放前面优先用。
-
正则表达式最后匹配:在规则内部,容易否定的规则项优先匹配,精确范围值优先匹配,然后精确值,然后不包含和包含值,最后正则表达式值。
总结
TXSQL提供了同步和异步两种审计模式,内置丰富的审计规则,满足不同用户的个性化需求,同时在性能损耗方面把控得十分优秀,一般情况下的内存损耗只有3%,远低于业界其他插件。
有了TXSQL的审计功能,DBA就能够实时查看数据库活动,对于数据库的所有操作都会有迹可循,当数据库遇到疑似风险行为时,及时进行处理,对攻击行为进行阻断。同时,借助TXSQL审计不同的审计模式,丰富的规则和超低的性能损耗,可以让DBA专注于运维本身,通过对用户访问数据库行为的记录、分析和汇报,进行事后生成合规报告、事故追根溯源,最终加强内外部数据库网络行为记录,提高数据资产安全。
本文由博客一文多发平台 OpenWrite 发布!