MySQL审核工具Inception

时间:2022-06-20 17:51:28

http://www.ywnds.com/?p=9423

https://github.com/mysql-inception/inception

一、Inception简介

Inception是集审核、执行、回滚于一体的一个自动化运维系统,它是根据MySQL代码修改过来的,用它可以很明确的,详细的,准确的审核MySQL的SQL语句,它的工作模式和MySQL完全相同,可以直接使用MySQL客户端来连接,但不需要验证权限,它相对应用程序(上层审核流程系统等)而言,是一个服务器,在连接时需要指定服务器地址及Inception服务器的端口即可,而它相对要审核或执行的语句所对应的线上MySQL服务器来说,是一个客户端,它在内部需要实时的连接数据库服务器来获取所需要的信息,或者直接在在线上执行相应的语句及获取binlog等,Inception就是一个中间性质的服务。图1.1所示为Inception的架构。

MySQL审核工具Inception

Inception提供的功能很丰富,首先,它可以对提交的所有语句的语法分析,如果语法有问题,都会将相应的错误信息返回给审核者。 还提供语义分析,当一个表,库,列等信息不正确或者不符合规范的时候报错,或者使用了一个不存在的对象时报错等等。 还提供了很多针对SQL规范性约束的功能,这些DBA都是可以通过系统参数来配置的。 更高级的功能是,可以辅助DBA分析一条查询语句的性能,如果没有使用索引或者某些原因导致查询很慢,都可以检查。

还提供SQL语句的执行功能,可执行的语句类型包括常用的DML及DDL语句及truncate table等操作。 Inception 在执行 DML 时还提供生成回滚语句的功能,对应的操作记录及回滚语句会被存储在备份机器上面,备份机器通过配置Inception参数来指定。

项目地址:https://github.com/mysql-inception/inception

文档地址:http://mysql-inception.github.io/inception-document/inception

二、Inception安装

以下安装是CentOS系统,如果是Ubuntu/Debian请看官方文档。

2.1 Git下载源码包

$ git clone https://github.com/mysql-inception/inception.git
1
$ git clone https://github.com/mysql-inception/inception.git

2.2 安装依赖包

$ yum install gcc gcc-c++ cmake bison openssl-devel ncurses-devel MySQL-python –y
1
$ yum install gcc gcc-c++ cmake bison openssl-devel ncurses-devel MySQL-python –y

使用yum安装的bison版本会3.0以上,官方建议使用低于2.6版本的,不然会编译有问题。参考:Inception服务的安装以及使用Python 3实现MySQL的审计

2.3 开始编译安装

首先就是编译,在源码根目录下面有一个文件inception_build.sh,执行命令sh inception_build.sh,会输出使用方法。 实际上只需要执行inception_build.sh debug [Xcode]即可,后面的平台是可选的,如果不指定就是linux平台,而如果要指定是Xcode,就后面指定Xcode,而debug是编译的目录,编译之后,所有的生成文件都在这个目录下面,包括可执行文件Inception。可执行文件在debug/sql/目录下面(不同平台有可能不相同)。

$ cd inception
$ bash inception_build.sh debug [Xcode]
1
2
$ cd inception
$ bash inception_build.sh debug [Xcode]

顺便强调说一下,实际上编译Inception,和编译MySQL源码是一样的,如果有不太了解的同学,可以先在网上看看关于MySQL源码的编译,我想遇到的问题都可以解决。

编译完成之后,就是使用了,那么需要一个配置文件(inc.cnf):

$ cat /etc/inc.cnf
[inception]
general_log=1
general_log_file=inception.log
port=6669
socket=/tmp/inc.socket
character-set-client-handshake=0
character-set-server=utf8
inception_remote_system_password=root
inception_remote_system_user=wzf1
inception_remote_backup_port=3306
inception_remote_backup_host=127.0.0.1
inception_support_charset=utf8mb4
inception_enable_nullable=0
inception_check_primary_key=1
inception_check_column_comment=1
inception_check_table_comment=1
inception_osc_min_table_size=1
inception_osc_bin_dir=/data/temp
inception_osc_chunk_time=0.1
inception_enable_blob_type=1
inception_check_column_default_value=1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ cat /etc/inc.cnf
[inception]
general_log=1
general_log_file=inception.log
port=6669
socket=/tmp/inc.socket
character-set-client-handshake=0
character-set-server=utf8
inception_remote_system_password=root
inception_remote_system_user=wzf1
inception_remote_backup_port=3306
inception_remote_backup_host=127.0.0.1
inception_support_charset=utf8mb4
inception_enable_nullable=0
inception_check_primary_key=1
inception_check_column_comment=1
inception_check_table_comment=1
inception_osc_min_table_size=1
inception_osc_bin_dir=/data/temp
inception_osc_chunk_time=0.1
inception_enable_blob_type=1
inception_check_column_default_value=1

2.4 启动Inception程序

启动方式和MySQL是一样的。

$ nohup /data/inception/debug/mysql/bin/Inception --defaults-file=/etc/inc.cnf &
1
$ nohup /data/inception/debug/mysql/bin/Inception --defaults-file=/etc/inc.cnf &

注意:因为Inception支持OSC执行的功能,是通过调用pt-online-schema-change工具来做的,但如果Inception后台启动(&)的话,可能会导致pt-online-schema-change在执行完成之后,长时间不返回,进而导致Inception卡死的问题,这个问题官方后面会解决,但现阶段请尽量不要使用后台启动的方式,或者可以使用nohup Inception &的方式来启动。

启动如果不报错的话,说明已经启动成功了,实际上很难让它报错,因为非常轻量级。

启动成功之后,可以简单试一下看,通过MySQL客户端

$ mysql -uroot -h127.0.0.1 -P6669
1
$ mysql -uroot -h127.0.0.1 -P6669

登录上去之后,再执行一个命令:

mysql> inception get variables;
1
mysql> inception get variables;

输出了所有的变量,恭喜你,已经启动成功了,都说了非常简单。

三、Inception使用

Inception实际上是一个服务程序,那么它应该有自己的一套友好的使用方式,必须要具备简单、高效、易用等特性。那么为了让Inception具有这些特点,在设计之初,就规定了它的使用方式,如下所述。

通过Inception对语句进行审核时,必须要告诉Inception这些语句对应的数据库地址、数据库端口以及Inception连接数据库时使用的用户名、密码等信息,而不能简单的只是执行一条sql语句,所以必须要通过某种方式将这些信息传达给Inception。而我们选择的方式是,为了不影响语句的意义,将这些必要信息都以注释的方式放在语句最前面,也就是说所有这些信息都是被 /**/括起来的,每一个参数都是通过分号来分隔,类似的方式为:

/*--user=username;--password=xxxx;--host=127.0.0.1;--port=3306;*/
1
/*--user=username;--password=xxxx;--host=127.0.0.1;--port=3306;*/

当然支持的参数不止是这几个,后面还会介绍一些其它的参数。 Inception要做的是一个语句块的审核,需要引入一个规则,将要执行的语句包围起来,Inception规定,在语句的最开始位置,要加上inception_magic_start;语句,在执行语句块的最后加上inception_magic_commit;语句,这2个语句在 Inception 中都是合法的、具有标记性质的可被正确解析的 SQL 语句。被包围起来的所有需要审核或者执行的语句都必须要在每条之后加上分号,其实就是批量执行SQL语句。(包括 use database语句之后也要加分号,这点与 MySQL 客户端不同),不然存在语法错误。

在具体执行时,在没有解析到inception_magic_start之前如果发现要执行其它的语句,则直接报错,因为规则中inception_magic_start是强制的。而如果在执行的语句块最后没有出现inception_magic_commit,则直接报错,不会做任何操作。 在前面注释部分,需要指定一些操作的选项,包括线上用户名、密码、数据库地址、检查/执行等。下面是一个简单的例子:

/*--user=zhufeng;--password=xxxxxxxxxxx;--host=xxxxxxxxxx;
--enable-check;--port=3456;*/
inception_magic_start;
use mysql;
CREATE TABLE adaptive_office(id int);
inception_magic_commit;
1
2
3
4
5
6
/*--user=zhufeng;--password=xxxxxxxxxxx;--host=xxxxxxxxxx;
--enable-check;--port=3456;*/  
inception_magic_start;  
use mysql;  
CREATE TABLE adaptive_office(id int);  
inception_magic_commit;

那么上面这一段就是一批正常可以执行的SQL语句,目前执行只支持通过C/C++接口、Python接口来对Inception访问,这一段必须是一次性的通过执行接口提交给Inception,那么在处理完成之后,Inception会返回一个结果集,来告诉我们这些语句中存在什么错误,或者是完全正常等等。

请不要将下面的SQL语句块,放到MySQL客户端中执行,因为这是一个自动化运维工具,如果使用交互式的命令行来使用的话没有意义,只能是通过写程序来访问Inception服务器。

而可以通过MySQL客户端来执行的,只有是Inception命令,请参考<<inception命令集语句>>一节。

下面是一段执行上面语句的Python程序的例子:

#!/usr/bin/python
#-\*-coding: utf-8-\*-
import MySQLdb
sql='/*--user=root;--password=123456;--host=172.17.0.2;--execute=1;--port=3306;*/\
inception_magic_start;\
create database if not exists test charset utf8mb4;\
use test;\
CREATE TABLE adaptive_office(id int);\
inception_magic_commit;'
try:
conn=MySQLdb.connect(host='127.0.0.1',user='',passwd='',db='',port=6669)
cur=conn.cursor()
ret=cur.execute(sql)
result=cur.fetchall()
num_fields = len(cur.description)
field_names = [i[0] for i in cur.description]
print("-------------------------")
for row in result:
for i in range(11):
print("%-14s : %s") % (field_names[i], row[i])
print("-------------------------")
cur.close()
conn.close()
except MySQLdb.Error,e:
print("Mysql Error %d: %s" % (e.args[0], e.args[1])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/python
#-\*-coding: utf-8-\*-
import MySQLdb
sql='/*--user=root;--password=123456;--host=172.17.0.2;--execute=1;--port=3306;*/\
inception_magic_start;\
create database if not exists test charset utf8mb4;\
use test;\
CREATE TABLE adaptive_office(id int);\
inception_magic_commit;'
try:
    conn=MySQLdb.connect(host='127.0.0.1',user='',passwd='',db='',port=6669)
    cur=conn.cursor()
    ret=cur.execute(sql)
    result=cur.fetchall()
    num_fields = len(cur.description)
    field_names = [i[0] for i in cur.description]
    print("-------------------------")
    for row in result:
        for i in range(11):
            print("%-14s : %s") % (field_names[i], row[i])
        print("-------------------------")
    cur.close()
    conn.close()
except MySQLdb.Error,e:
     print("Mysql Error %d: %s" % (e.args[0], e.args[1])

执行这段程序之后,返回的结果如下:

-------------------------
ID : 1
stage : EXECUTED
errlevel : 0
stagestatus : Execute Successfully
Backup successfully
errormessage : None
SQL : update sbtest.dd set c="test" where a>607
Affected_rows : 2
sequence : '1520577544_481_0'
backup_dbname : 10_10_0_109_3306_sbtest
execute_time : 0.000
sqlsha1 :
-------------------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-------------------------
ID             : 1
stage          : EXECUTED
errlevel       : 0
stagestatus    : Execute Successfully
Backup successfully
errormessage   : None
SQL            : update sbtest.dd set c="test" where a>607
Affected_rows  : 2
sequence       : '1520577544_481_0'
backup_dbname  : 10_10_0_109_3306_sbtest
execute_time   : 0.000
sqlsha1        :
-------------------------

从返回结果可以看到,每一行语句的审核及执行信息,最前面打印的是field_names,表示Inception的返回结果集的列名信息,总共包括十个列,下面是每个列对应的结果,因为只有两个语句,则只有两行,从结果集第一个列看到只有序号为1和2的两行,而对于每一个列的具体含义,这会在<<Inception结果集>>这一章中讲到,这里只看清楚是什么内容即可。

另外,Inception支持审核以及执行语句,可以自行开启或关闭,具体要看<<Inception选项>>。

更详细内容请看官网,最后说一句,在这里感谢inception作者。

另外在生产环境,Inception需要MySQL的用户权限最少如下,其中还需要复制权限回滚依赖:

mysql> GRANT SUPER, CREATE, INDEX, ALTER, INSERT, UPDATE, DELETE, SELECT, REPLICATION SLAVE ON *.* TO 'platformuser'@'172.%' IDENTIFIED BY '123456';
1
mysql> GRANT SUPER, CREATE, INDEX, ALTER, INSERT, UPDATE, DELETE, SELECT, REPLICATION SLAVE ON *.* TO 'platformuser'@'172.%' IDENTIFIED BY '123456';

四、Web平台

基于Inception的可视化web端sql审核平台,Yearning SQL审计平台基于Vue.js与Django的整套sql审核平台解决方案,提供基于Inception的SQL检测及执行。

源码地址:https://github.com/cookieY/Yearning

MySQL审核工具Inception

这个项目在2018年1月份一出来就很快进入大家的视线,目前有QQ官方群,并且作者会持续更新,更多内容看官网。

五、使用中遇到的问题

inception不支持MariaDB回滚,注释inception/sql/sql_parse.cc文件中如下几行就可以支持。

9596 /* if (query_log->thread_id != thread_id)
9597 {
9598 *skip_trx = TRUE;
9599 DBUG_RETURN(true);
9600 } */
1
2
3
4
5
9596         /* if (query_log->thread_id != thread_id)
9597         {
9598             *skip_trx = TRUE;
9599             DBUG_RETURN(true);
9600         } */

Python 3连接inception报错解决:Inception服务的安装以及使用Python 3 实现MySQL的审计

还有比如TEXT/BLOB类型的列不支持NOT NULL,备份语句长度超过限制等问题,这里有个网友补充了这些问题的解决方案。