MySQL Audit&Firewall Introduction

基本原理:

    传统的方式下,如果我们在对一条SQL语句进行审计或者根据该SQL语句的类型进行相应操作的时候,我们需要对所执行的SQL进行分析,将该语句中的各个语法部分抽取出来,而需要完成对应语句的解析操作我们有两种选择

(1)使用MySQL自身source code中完成词法&语法解析的功能,但这会带来一个问题:我们需要修改MySQL的源码;

(2)已插件的方式不修改MySQL而是在SQL语句执行之前,将该语句发送到插件中,由我们自己完成对应SQL语句的解析工作; 同时,我们采用Trampoline机制将MySQL实例中的特定函数进行“脱壳”,替换为我们自己的函数,因为我们需要在插件中不紧紧是分析SQL语句,而且同时提供SQL语句的执行功能;

在我们获得了对应SQL语句的审计信息后,我们需要将相应的日志信息发送外部系统,在我们系统中我们将该日志消息通过upd方式外发到kafka消息队列中,由外部系统消费日志进行处理;

插件功能配置

  • (1)标准功能

在标准模式下,该项功能移植自Percona,因此对于该模式下的插件功能配置方法,请参考Percona,这里不再赘述。如果想了解更多关于Percona关于审计和防火墙插件的功能,请参考其官方介绍。

  • (2)New Plugin Feature

在我们安装AUDIT/FIREWALL插件后,缺省状态下,该插件所具有的功能是:Audit(审计)功能。于此同时,在该项功能下,我们会主动的记录下用户的操作信息到日志文件中。DBA可以明确的设置操作日志记录选项(audit_json_file)用来表明在该Audit模式下是否进行操作信息的日志记录。同时,考虑到日志信息的磁盘写入涉及到大量的磁盘IO操作,为了能够提高系统的性能(主要是QPS和TPS等),我们提供将操作日志不进行落盘操作的行为:通过网络外发到kafka服务器上,其中:audit_json_socket参数描述了是否将该操作日志进行外发kafka,缺省状态是不进行外发kafka操作。

当我们在将操作日志进行外发kafka服务器的时,我们通过该插件以UDP的方式,将这些操作消息(json格式)通过UPD 网关发送到kafka服务器上。这样的设计考虑是:我们可以通过dns来做到消息外发的分布式行为,从而提高查询的消息外发的吞吐量。故而,在消息外发模式下,我们还需要关注:audit_socket_type,audit_dns_svr_addr这几个参数(具体这些参数的含义详解见下面说明)。

在查询工作在AUDIT模式下,我们提供两种处理原始查询SQL语句的方式:(1)解析并获取该查询SQL语句的模式;(2)不解析。audit_parsing_sql,该参数描述了是否进行查询SQL语句的解析的行为,默认情况下未来获得更高的系统体验,我们关闭该项功能。

当插件工作于FIREWALL模式下(audit_function_type),我们并不会记录相应的操作信息,而是根据我们预先设定的SQL语句模式所对应的行为进行相应的操作。例如:忽略,不做任何操作(ignore);亦或者进行阻断连接操作(killsession);

当插件工作于BOTH模式下,插件同时具有AUDIT和FIREWALL所具有的功能:操作日志的记录以及操作行为管理。可以说当插件工作在BOTH模式下,其会按照如下处理流程对查询SQL语句进行处理:

(1)首先根据预先设定的模式进行匹配,并按所匹配的模式所对应的行为进行后续操作(主要是:ignore,killsession等);当该语句通过相应的模式检测后,该操作会行为会以为审计日志的行为记录下并根据相应的设置进行日志记录或外发kafka。当插件工作在FIREWALL模式下,为了能够保持预先设置的模式信息,再数据库初始化时候,插件会在mysql数据库上创建一个名为sql_pattern的元数据表。该元数据表的定义如下:

CREATE TABLE IF NOT EXISTS

sql_pattern (

sql_text varchar(1024) DEFAULT ” NOT NULL,

sql_pattern varchar(1024) DEFAULT ” NOT NULL,

sql_md5 varchar(512) DEFAULT ” NOT NULL,

sql_action varchar(16) DEFAULT ” NOT NULL, PRIMARY KEY(sql_text)

) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_general_ci comment=’MySQL sql patterns’;

为了使得DBA可以通过相应的SQL语句来维护该元数据表,插件提供了:(1) create rule; (2) update rule;(3)drop rule命令来创建一个SQL规则;更新一个SQL规则;删除一个SQL规则;具体的如下描述:

(1)CREATE RULE ‘rule_name’ AS sql_statement WITH Action_Opt;

CREATE RULE ‘rule1’ as select * from table1 WITH killsession;

(2)UPDATE RULE ‘rule_name’ AS sql_statement WITH Action_Opt;

UPDATE RULE ‘rule1′ as select * from table2 where table2.col=’value’ WITH ignore;

(3)DROP RULE ‘rule_name’

DROP RULE ‘rule1’;

注意:当我们需要在一个已经完成初始化操作的数据库上使用该插件功能时候,我们可以由DBA在mysql数据库上运行上述的SQL语句来创建相应的sql_pattern元数据表。

下面就详细介绍下插件中的各个参数:

  • audit_json_log_file: 日志文件的名称;当audit_json_file参数有效时候,数据库的操作将会被记录到json格式的日志文件中,而audit_json_log_file则描述了该日志文件的名称。默认值:audit.log;
  • audit_json_file: 是否以json格式文件记录操作行为,其值范围为:ON|OFF.默认值:ON;
  • audit_json_file_sync: json 日志文件的同步周期;当该值为一大于0的值时,其表明在audit_json_file_sync次写入后(首先会写入到log buffer中),将日志缓存中的数据同步到磁盘上;默认值为:0.
  • audit_json_file_flush:是否强制将缓存中的数据写入到磁盘;当该参数被设置为ON是,会强制的进行log写入操作(系统会关闭已打开的日志文件并重新打开该日志文件);
  • audit_json_socket_name: unix socket名称。当插件工作于非日志文件模式下,插件提供了两种外发模式:(1)通过unix socket方式;(2)udp方式; 依据audit_socket_type参数值来进行决定是通过unix socket方式亦或是upd方式进行日志消息的外发操作;
  • audit_json_socket 当我们将日志消息设置为外发模式时候,其工作在unix socket外发模式下时,该参数描述是否通过unix socket进行外发操作日志。取值范围:ON|OFF,默认值为:OFF;
  • audit_json_socket_write_timeout:插件工作在unix socket外发模式下,该参数描述了socket写入时候的超时时间,单位毫秒;当前默认值:1000ms。
  • audit_uninstall_plugin: 描述是否可以通过uninstall plugin命令来卸载插件。取值范围:ON|OFF,默认值:ON。DBA可以通过执行uninstall plugin AUDIT;来卸载所安装的AUDIT/FIREWALL插件。
  • audit_validate_checksum:描述了mysqld的二进制的校验码(无需关注)。取值范围:ON|OFF,默认值:ON.
  • audit_record_cmds: 描述了插件所记录的命令,以逗号隔开;例如:insert,update,delete.
  • audit_record_objs: 描述了查询所记录的对象信息;以逗号隔开;例如:.mytable ,mydb..
  • audit_header_msg: 描述了日志信息中是否包含头信息;头信息中描述:用户名,对方ip和端口等信息。
  • audit_json_file_bufsize: 描述了日志文件的缓存大小,为了提高日志文件写入效率,日志文件并非每次都是进行磁盘写入操作,而是会首先保存到大小为audit_json_file_bufsize的日志缓存中。当该缓存被填满后,一并写入,从而提高插件的日志写入效率。
  • audit_before_after:描述了操作日志所记录的位置,是在命令执行前或是在命令执行后执行记录操作。取值范围:’before’, ‘after’, or ‘both’. 默认值:’after’。
  • audit_remote_port: 描述了当日志信息以udp方式外发时候,udp服务器的监听端口。默认值:5000,该值需要依据udp server的监听具体端口而定。
  • audit_dns_svr_addr: 当插件以udp消息外发时,为了能够提供分布式行为,插件通过dns来获取udp server的地址并将日志消息外发到该udp server。该种模式下,使插件屏蔽了后端具体udp server的地址。
  • audit_socket_type: 描述了插件消息外发的模式;取值范围:(1)unix;(2)udp;默认值udp。当该参数设置为unix时候,日志消息将通过audit_json_socket_name所描述的unix socket进行外发;否则,通过有audit_dns_svr_addr所描述的dns svr所给出的udp地址进行消息外发。
  • audit_function_type: 描述了插件所完成的功能角色,例如:以audit角色运行,亦或者以firewall角色运行;取值范围:audit,firewall,both;默认值:audit。
  • audit_parsing_sql: 描述了插件是否进行查询SQL语句的解析操作;取值范围:ON|OFF,默认值:OFF。
  • audit_max_seg_log_file_size: 描述了日志文件的最大大小。由于插件需要长期运行,当以日志文件行为运行时候,其会产生非常庞大的日志文件。因此,该参数规定了每个日志文件所能达到的最大大小。当日志文件的大小大于该参数所设定的值时候,日志文件将会被分割为每个最大大小为 audit_max_seg_log_file_size的多个日志文件;

*audit_offsets:描述插件中各个域在系统中的偏移量。
其中具体的各个mysql版本下的offset值可以通过offset-extract脚本来获得。
./offset-extract.sh mysqld_dir [mysqld_symbol_table].

注意:该脚本在获得offset值得时候,需要gdb和mysqld的符号表支持,否则我们无法获取到有效的offset值。mysqld得符号表,通常release版本中并不带有,但是mysql官网通常会提供该版本的符号表信息,我们可以从官网上下载该版本的符号表。

注意
该插件运行在每个mysql实例下;

audit_max_seg_log_file_size: To indicate size of each log file slice. When the log file size exceeds over this value, the log file will be split into small pieces.
When configuring boolean variables (enable/disable) in MySQL 5.1 via a configuration file (my.cnf) use 0/1 as values. For example: audit_json_file=1. There seems to be an issue with MySQL 5.1 where boolean configurations with ON/OFF values in my.cnf don’t work.
The Audit Plugin will log all activity performed by the SQL thread of a slave server. To turn it off, whitelist the empty user by setting: audit_whitelist_users='{}’.
The above list may be incomplete. To view all available AUDIT system variables run: mysqld –help –verbose
If a SQL statement can not be parsed when it means that this rule does not be added into grammatical file, grammar.y. Pls, adding the grammatical rules manually.

如何安装SQL Audit&Firewall插件

1: 综述:

本插件主要完成对应数据库基本操作行为的日志记录以及SQL语句的防火墙功能,在完成该插件的安装后,根据所配置的的参数,相应的对应数据库的操作行为将会被记录在data目录下的名为audit_xxx.log的
json形式的文件中。该文件中包括:操作的类型,操作者的账号,地址,端口,语句等等。下面就对该插件的安装,卸载,及相关配置进行描述。

2:相关文件:

该插件公有如下几个.so文件,由于该插件是以动态库的方式运行,因此该插件以.so文件格式提供。下面是文件列表。

1:libaudit_plugin.a

2:libaudit_plugin.la

3:libaudit_plugin.so

4:libaudit_plugin.so.0 (link file)

5: libaudit_plugin.so.0.0.0(link file)

3:安装:

对应该插件的安装,有如下的两种方式: (1)自动安装&运行; (2)手动安装。

(0)准备工作

在该方式下,首先将该插件的.so文件拷贝到mysql plugin的文件夹中。用户可以通过运行 “show variables like ‘%plugin%’;” 命令来查询当前数据库实例所所指定的plugin安装路径。

例如:

性能测试:

下面就给出相应的测试对比如下,第一幅是相应的QPS对比信息; 第二幅图是相应的延迟对比图,下面就对各附图进行简单的说明。

下图是关于qps的各种情况的介绍;

(0)base 是未安装audit&firewall功能的状态下的qps情况。

(1)audit_no_parse是处于审计模式下,对相应的我们的sql不进行解析的情况,此时我们只是记录了用户的操作行为,但并不对用户所允许的sql语句进行解析;因此,我们不能在该中状态下,并不能够依据sql语句进行行为判定;此时,由于并不会进行额外的且耗时的sql语句分析工作,此时相应的qps损坏最小,但此时所提供的功能最小;

(2)audit_parse为处于审计模式下,并对用户所执行的sql进行解析的情况;运行在该种情况下,mysql会将用户所运行的sql进行解析并提取出该sql的 pattern;然后记录该pattern;

(3)firewall_no_parse,运行于firewall模式下,该中模式下如果开启sql解析时,mysql会首先已经之前由create rules语句所创建的sql语句进行pattern匹配并依据所匹配的情况执行对应的action; 但由于firewall_no_parse是运行在firewall模式下不解析SQL情况;因此,该模式下并未与之前创建的规则进行比对;

(4)firewall_parse, 运行在firewall模式下,并对相应用户所执行的sql语句进行解析;当完成解析并获取该sql语句所对应的Pattern,并将该所得的pattern与数据库中所给出的pattern进行比对并根据该模式所对应的操作,执行相应的操作(例如:关闭session连接,忽视该操作等等)

(5)both_no_parse,运作在两钟模式下,但是在这两种情形下,都不进行sql语句的解析操作;此时,虽然运行具有firewall模式特性,因为没有对用户sql语句进行解析,故而不会执行相应的操作;

(6)both_parse,与both_parse刚好相反,其会执行相应的audit及firewall模式,并依据相应的sql模式进行对应的操作;

结论:

从上面的讨论可知,运行在audit&firewall并带有解析sql模式下,其qps损坏最大,但是其提供的功能最为完整。运行在audit_no_parse模式下,QPS损耗最新,但是所提供的功能最为单一;

同样的结论也适用于latency。

The latency(95 percentile):

MyRocks&Aurora等

下面为之前对应MyRocks,AWS Aurora,PolarDB相关调研的总结,并给出了相应的对比,希望能够对大家有所帮助。

1: MyRocks

2:Aurora&Polar&Taurus

对应MyRocks更加详细的分析在后续给出。关于Aurora等由于只有Paper相关厂商并未给出相应的source code,因此我们只能从Paper及网上相关信息给出自己的理解;