Audit简介
MySQL 企业版包括 MySQL Enterprise Audit,MySQL Enterprise Audit 使用开放的 MySQL Audit API 来启用标准的、基于策略的监控、日志记录和阻止在特定 MySQL 服务器上执行的连接和查询活动。
安装后,审计插件使 MySQL 服务器能够生成包含服务器活动审计记录的日志文件。日志内容包括客户端何时连接和断开连接,以及它们在连接时执行的操作,例如它们访问的数据库和表。安装审计插件后,默认它会写入audit.log审计日志文件。
MySQL 企业审计的要素
- Audit插件审计事件过滤规则并确定是否将它们写入审计日志audit_log
审计日志文件的命名约定
有效的审计日志文件名是在配置的文件名中添加适用的压缩和加密后缀后产生的名称。
例如,如果配置的 audit_log_file值为 audit.log,则有效文件名是下表中的值之一。
|
启用的功能 |
有效文件名 |
|
无压缩或加密 |
audit.log |
|
压缩 |
audit.log.gz |
|
加密 |
audit.log.pwd_id.enc |
|
压缩、加密 |
audit.log.gz.pwd_id.enc |
- 一组函数支持对控制日志行为、加密密码和日志文件读取的过滤定义进行操作
- audit_log_filter_set_filter(): 定义过滤器。
- audit_log_filter_remove_filter(): 删除过滤器。
- audit_log_filter_set_user():开始过滤用户帐户。
- audit_log_filter_remove_user():停止过滤用户帐户。
- audit_log_filter_flush():刷新对过滤器表的手动更改以影响正在进行的过滤。
- mysql系统数据库 中的表提供过滤器和用户帐户数据的持久存储。
- 系统变量启用审计日志配置,状态变量提供运行时操作信息。
- 一个AUDIT_ADMIN特权使用户能够管理审计日志。
要使用任何过滤功能,用户必须拥有 权限,否则会发生错误。要将这些权限之一授予 用户帐户,请使用以下语句: AUDIT_ADMIN SUPER
GRANT privilege ON *.* TO user;
Audit 安装单机安装
1. 执行audit安装插件
执行安装 audit_log_filter_linux_install.sql
[root@mac4 data]# find / -type f -name "*audit_log_filter_linux_install*"
/usr/share/mysql/audit_log_filter_linux_install.sql
[root@mac4 ~]# mysql -u root -p < /usr/share/mysql/audit_log_filter_linux_install.sql
Enter password:
Result
OK
安装后默认激活 Show plugins或
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'audit%';
2. 插件激活方式
A、启动mysql服务加参数 --audit-log
B、添加到cnf文件 正常启动
[mysqld]
audit-log=FORCE_PLUS_PERMANENT
3. audit.log三种格式
[audit.log可压缩可加密可解压解密读取 这里不做深入展开]
l 新式 XML 格式 ( audit_log_format=NEW):与旧式 XML 格式相比,与 Oracle Audit Vault 的兼容性更好的 XML 格式。MySQL 8.0 默认使用新式 XML 格式。
l 旧式 XML 格式 ( audit_log_format=OLD):旧版 MySQL 系列中默认使用的原始审计日志格式。
l JSON 格式 ( audit_log_format=JSON)
- 可以在my.cnf参数种修改 audit_log_format = NEW / OLD / JSON
审计日志过滤
审计日志使用说明
默认情况下,基于规则的审计日志过滤不会记录任何用户的可审计事件。要记录所有用户的所有可审计事件,请使用以下语句,这些语句创建一个简单的过滤器以启用日志记录并将其分配给默认帐户:
SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }');
SELECT audit_log_filter_set_user('%', 'log_all');
如果为用户分配了过滤器,审核日志将使用该过滤器。否则,如果不存在特定于用户的过滤器分配,但有分配给默认帐户 ( %)的过滤器,则审核日志使用默认过滤器。否则,审计日志不会从会话中选择任何审计事件进行处理。
审计日志过滤的属性
审计日志插件能够通过过滤来控制审计事件的日志记录
l 可以使用以下特征过滤审计事件
- 用户帐号
- 审计事件类
- 审计事件子类
- 审计事件字段,例如指示操作状态或执行的 SQL 语句的字段
l 审计过滤基于规则
- 过滤器定义创建一组审计规则。定义可以配置为包含或排除基于刚刚描述的特征的日志记录事件。
- 除了用于事件记录的现有功能之外,过滤器规则还具有阻止(中止)执行合格事件的功能。
- 可以定义多个过滤器,并且可以将任何给定的过滤器分配给任意数量的用户帐户。
- 可以定义一个默认过滤器以用于任何没有明确分配过滤器的用户帐户。
l 可以使用基于函数调用的 SQL 接口来定义、显示和修改审计过滤器。
l 审计过滤器定义存储在mysql系统数据库的表中 。
l 在给定的会话中,只读 audit_log_filter_id 系统变量的值指示是否为会话分配了过滤器。
编写审计日志过滤器定义
1. 记录所有事件
要显式启用或禁用所有事件的日志记录,请使用log过滤器中的 一项:
{
"filter": { "log": true }
}
该log值可以是 true或false。
前面的过滤器启用所有事件的日志记录。它相当于:
{
"filter": { }
}
记录行为取决于log值以及是否指定了class或 event项:
随着log指定,则使用其给定值。
如果没有log指定,则日志记录是 true如果没有指定class或 event项目, false否则(在这种情况下, class或event可以包括自己的log项目)。
2. 记录特定的事件类
要记录特定类的事件,请使用class过滤器中的 一项,其 name字段表示要记录的类的名称:
{
"filter": {
"class": { "name": "connection" }
}
}
该name值可以是 connection、general或 table_access,分别用于记录连接、一般或表访问事件。
前面的过滤器可以记录connection类中的事件 。它等效于以下过滤器,其中log明确显示了项目:
{
"filter": {
"log": false,
"class": { "log": true,
"name": "connection" }
}
}
要启用多个类的日志记录,请将class值定义 为JSON命名类的 数组元素:
{
"filter": {
"class": [
{ "name": "connection" },
{ "name": "general" },
{ "name": "table_access" }
]
}
}
笔记
当给定项目的多个实例出现在过滤器定义中的同一级别时,项目值可以组合为数组值中该项目的单个实例。前面的定义可以这样写:
{
"filter": {
"class": [
{ "name": [ "connection", "general", "table_access" ] }
]
}
}
3. 记录特定的事件子类
要选择特定事件子类,请使用event包含name命名子类的 项目的 项目。项目选择的事件的默认操作 event是记录它们。例如,此过滤器为指定的事件子类启用日志记录:
{
"filter": {
"class": [
{
"name": "connection",
"event": [
{ "name": "connect" },
{ "name": "disconnect" }
]
},
{ "name": "general" },
{
"name": "table_access",
"event": [
{ "name": "insert" },
{ "name": "delete" },
{ "name": "update" }
]
}
]
}
}
该event项目还可以包含显式 log项目以指示是否记录符合条件的事件。此项event选择多个事件并明确指示它们的日志记录行为:
"event": [
{ "name": "read", "log": false },
{ "name": "insert", "log": true },
{ "name": "delete", "log": true },
{ "name": "update", "log": true }
]
该event项目还可以指示是否阻止符合条件的事件(如果它包含一个 abort项目)。有关详细信息,请参阅 阻止特定事件的执行。
表“事件类和子类组合” 描述了每个事件类允许的子类值。
|
事件类 |
事件子类 |
描述 |
|
connection |
connect |
连接启动(成功或不成功) |
|
connection |
change_user |
在会话期间使用不同的用户/密码重新验证用户 |
|
connection |
disconnect |
连接终止 |
|
general |
status |
一般操作信息 |
|
message |
internal |
内部生成的消息 |
|
message |
user |
|
|
table_access |
read |
表读取语句,例如SELECT或 INSERT INTO ... SELECT |
|
table_access |
delete |
表删除语句,例如DELETE 或TRUNCATE TABLE |
|
table_access |
insert |
|
|
table_access |
update |
表更新语句,例如 UPDATE |
每个事件类和子类组合的日志和中止特征
|
事件类 |
事件子类 |
可以记录 |
可以中止 |
|
connection |
connect |
是的 |
不 |
|
connection |
change_user |
是的 |
不 |
|
connection |
disconnect |
是的 |
不 |
|
general |
status |
是的 |
不 |
|
message |
internal |
是的 |
是的 |
|
message |
user |
是的 |
是的 |
|
table_access |
read |
是的 |
是的 |
|
table_access |
delete |
是的 |
是的 |
|
table_access |
insert |
是的 |
是的 |
|
table_access |
update |
是的 |
是的 |
4. 包含和独占日志记录
过滤器可以定义为包含或排除模式:
包含模式仅记录明确指定的项目。
独占模式记录所有但明确指定的项目。
要执行包含日志记录,请全局禁用日志记录并为特定类启用日志记录。此过滤器类中的日志 connect和disconnect 事件,以及connection类中的事件general:
{
"filter": {
"log": false,
"class": [
{
"name": "connection",
"event": [
{ "name": "connect", "log": true },
{ "name": "disconnect", "log": true }
]
},
{ "name": "general", "log": true }
]
}
}
要执行独占日志记录,请全局启用日志记录并禁用特定类的日志记录。此过滤器记录除general 类中的事件之外的所有内容:
{
"filter": {
"log": true,
"class":
{ "name": "general", "log": false }
}
}
该过滤器记录change_user的事件 connection类, message事件和 table_access活动,凭借的 不是记录一切:
{
"filter": {
"log": true,
"class": [
{
"name": "connection",
"event": [
{ "name": "connect", "log": false },
{ "name": "disconnect", "log": false }
]
},
{ "name": "general", "log": false }
]
}
}
5. 测试事件字段值
要启用基于特定事件字段值的日志记录,请在field项目中 指定一个log项目来指示字段名称及其预期值:
{
"filter": {
"class": {
"name": "general",
"event": {
"name": "status",
"log": {
"field": { "name": "general_command.str", "value": "Query" }
}
}
}
}
}
每个事件都包含特定于事件类的字段,可以从过滤器中访问这些字段以执行自定义过滤。
类中的事件connection指示在会话期间何时发生与连接相关的活动,例如用户连接到服务器或从服务器断开连接。 表 “连接事件字段”指示事件的允许字段connection。
表连接事件字段
|
字段名称 |
字段类型 |
描述 |
|
status |
整数 |
事件状态: 0:好的 否则:失败 |
|
connection_id |
无符号整数 |
连接 ID |
|
user.str |
细绳 |
认证时指定的用户名 |
|
user.length |
无符号整数 |
用户名长度 |
|
priv_user.str |
细绳 |
认证用户名(账户用户名) |
|
priv_user.length |
无符号整数 |
认证用户名长度 |
|
external_user.str |
细绳 |
外部用户名(由第三方认证插件提供) |
|
external_user.length |
无符号整数 |
外部用户名长度 |
|
proxy_user.str |
细绳 |
代理用户名 |
|
proxy_user.length |
无符号整数 |
代理用户名长度 |
|
host.str |
细绳 |
连接的用户主机 |
|
host.length |
无符号整数 |
连接用户主机长度 |
|
ip.str |
细绳 |
连接的用户IP地址 |
|
ip.length |
无符号整数 |
连接用户IP地址长度 |
|
database.str |
细绳 |
连接时指定的数据库名称 |
|
database.length |
无符号整数 |
数据库名称长度 |
|
connection_type |
整数 |
连接类型: 0 或"::undefined": 未定义 1 或"::tcp/ip": TCP/IP 2 或"::socket": 插座 3 或"::named_pipe": 命名管道 4 或"::ssl": TCP/IP 加密 5 或"::shared_memory": 共享内存 |
这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"
类中的事件general指示操作的状态代码及其详细信息。 表 “一般事件字段”指示事件的允许字段general。
表 一般事件字段
|
字段名称 |
字段类型 |
描述 |
|
general_error_code |
整数 |
事件状态: 0:好的 否则:失败 |
|
general_thread_id |
无符号整数 |
连接/线程 ID |
|
general_user.str |
细绳 |
认证时指定的用户名 |
|
general_user.length |
无符号整数 |
用户名长度 |
|
general_command.str |
细绳 |
命令名称 |
|
general_command.length |
无符号整数 |
命令名长度 |
|
general_query.str |
细绳 |
SQL语句文本 |
|
general_query.length |
无符号整数 |
SQL语句文本长度 |
|
general_host.str |
细绳 |
主机名 |
|
general_host.length |
无符号整数 |
主机名长度 |
|
general_sql_command.str |
细绳 |
SQL 命令类型名称 |
|
general_sql_command.length |
无符号整数 |
SQL 命令类型名称长度 |
|
general_external_user.str |
细绳 |
外部用户名(由第三方认证插件提供) |
|
general_external_user.length |
无符号整数 |
外部用户名长度 |
|
general_ip.str |
细绳 |
连接的用户IP地址 |
|
general_ip.length |
无符号整数 |
连接用户IP地址长度 |
general_command.str表示命令名:Query,Execute, Quit,或Change user。
字段设置为 或 包含设置为指定 SQL 命令类型的值 的general事件 : 、 、 等。可用 值可以看作是此语句显示的 Performance Schema 工具的最后一个组件: general_command.strQueryExecutegeneral_sql_command.stralter_dbalter_db_upgradeadmin_commandsgeneral_sql_command.str
mysql> SELECT NAME FROM performance_schema.setup_instruments
WHERE NAME LIKE 'statement/sql/%' ORDER BY NAME;+---------------------------------------+| NAME |+---------------------------------------+| statement/sql/alter_db || statement/sql/alter_db_upgrade || statement/sql/alter_event || statement/sql/alter_function || statement/sql/alter_instance || statement/sql/alter_procedure || statement/sql/alter_server |...
类中的事件table_access提供有关对表的特定类型访问的信息。
表 “表访问事件字段” 指示事件的允许字段 table_access。
表访问事件字段
|
字段名称 |
字段类型 |
描述 |
|
connection_id |
无符号整数 |
事件连接 ID |
|
sql_command_id |
整数 |
SQL 命令 ID |
|
query.str |
细绳 |
SQL语句文本 |
|
query.length |
无符号整数 |
SQL语句文本长度 |
|
table_database.str |
细绳 |
与事件关联的数据库名称 |
|
table_database.length |
无符号整数 |
数据库名称长度 |
|
table_name.str |
细绳 |
与事件关联的表名 |
|
table_name.length |
无符号整数 |
表名长度 |
以下列表显示了哪些语句会产生哪些表访问事件:
- read 事件:
SELECT
INSERT ... SELECT(对于SELECT子句中引用的表)
REPLACE ... SELECT(对于SELECT子句中引用的表)
UPDATE ... WHERE(对于WHERE子句中引用的表)
HANDLER ... READ
- delete 事件:
DELETE
TRUNCATE TABLE
- insert 事件:
INSERT
INSERT ... SELECT(对于INSERT子句中引用的表)
REPLACE
REPLACE ... SELECT(对于REPLACE子句 中引用的表
LOAD DATA
LOAD XML
- update 事件:
UPDATE
UPDATE ... WHERE(对于UPDATE子句中引用的表)
6. 阻止特定事件的执行
event项目可以包括 abort指示是否阻止执行合格事件的项目。 abort允许编写阻止执行特定 SQL 语句的规则。
该abort项目必须出现在一个 event项目中。例如:
"event": {
"name": qualifying event subclass names
"abort": condition
}
对于name 项目选择的事件子类,abort动作为真或假,取决于condition评估。如果条件评估为真,则事件被阻止。否则,事件继续执行。
所述condition规范可以是一样简单true或 false,或者它可以是更复杂的,使得评价取决于事件特性。
该过滤块INSERT, UPDATE和 DELETE语句:
{
"filter": {
"class": {
"name": "table_access",
"event": {
"name": [ "insert", "update", "delete" ],
"abort": true
}
}
}
}
这个更复杂的过滤器会阻止相同的语句,但仅针对特定表 ( finances.bank_account):
{
"filter": {
"class": {
"name": "table_access",
"event": {
"name": [ "insert", "update", "delete" ],
"abort": {
"and": [
{ "field": { "name": "table_database.str", "value": "finances" } },
{ "field": { "name": "table_name.str", "value": "bank_account" } }
]
}
}
}
}
}
过滤器匹配并阻止的语句向客户端返回错误:
ERROR 1045 (28000): Statement was aborted by an audit log filter
并非所有事件都可以被阻止( 参见表 6.35,“每个事件类和子类组合的日志和中止特征”)。对于无法阻止的事件,审计日志会向错误日志写入警告而不是阻止它。
如果尝试定义abort项目出现在event项目以外的其他地方 的过滤器, 则会发生错误。
7. 逻辑运算符
逻辑运算符 ( and, or, not) 允许构建复杂条件,从而能够编写更高级的过滤配置。以下 log项目仅记录 具有特定值和长度的字段的general事件 general_command:
{
"filter": {
"class": {
"name": "general",
"event": {
"name": "status",
"log": {
"or": [
{
"and": [
{ "field": { "name": "general_command.str", "value": "Query" } },
{ "field": { "name": "general_command.length", "value": 5 } }
]
},
{
"and": [
{ "field": { "name": "general_command.str", "value": "Execute" } },
{ "field": { "name": "general_command.length", "value": 7 } }
]
}
]
}
}
}
}
}
8. 引用预定义变量
要引用条件中的预定义变量log ,请使用variableitem,它采用 name和valueitems 并根据给定值测试命名变量的相等性:
"variable": {
"name": "variable_name",
"value": comparison_value
}
如果variable_name值为则为真comparison_value,否则为假。
例子:
{
"filter": {
"class": {
"name": "general",
"event": {
"name": "status",
"log": {
"variable": {
"name": "audit_log_connection_policy_value",
"value": "::none"
}
}
}
}
}
}
每个预定义变量对应一个系统变量。通过编写测试预定义变量的过滤器,您可以通过设置相应的系统变量来修改过滤器操作,而无需重新定义过滤器。例如,通过编写测试audit_log_connection_policy_value 预定义变量值的 过滤器,您可以通过更改audit_log_connection_policy 系统变量的值来修改过滤器操作 。
该 系统变量用于遗留模式审计日志(见 第6.4.5.9,“传统模式下的审计日志过滤”)。使用基于规则的审计日志过滤,这些变量仍然可见(例如,使用),但除非您编写包含引用它们的构造的过滤器,否则对它们的更改不会产生任何影响。 audit_log_xxx_policySHOW VARIABLES
以下列表描述了variable项目允许的预定义变量:
audit_log_connection_policy_value
该变量对应于audit_log_connection_policy 系统变量的值 。该值是一个无符号整数。 表 6.39,“audit_log_connection_policy_value 值” 显示了允许的值和相应的 audit_log_connection_policy 值。
表 6.39 audit_log_connection_policy_value 值
价值 对应的 audit_log_connection_policy 值
0 或者 "::none" NONE
1 或者 "::errors" ERRORS
2 或者 "::all" ALL
这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"
audit_log_policy_value
该变量对应于audit_log_policy系统变量的值 。该值是一个无符号整数。 表 6.40,“audit_log_policy_value 值”显示了允许的值和相应的 audit_log_policy值。
表 6.40 audit_log_policy_value 值
价值 对应的 audit_log_policy 值
0 或者 "::none" NONE
1 或者 "::logins" LOGINS
2 或者 "::all" ALL
3 或者 "::queries" QUERIES
这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"
audit_log_statement_policy_value
该变量对应于audit_log_statement_policy 系统变量的值 。该值是一个无符号整数。 表 6.41,“audit_log_statement_policy_value 值” 显示了允许的值和相应的 audit_log_statement_policy 值。
表 6.41 audit_log_statement_policy_value 值
价值 对应的 audit_log_statement_policy 值
0 或者 "::none" NONE
1 或者 "::errors" ERRORS
2 或者 "::all" ALL
这些 值是可以给出的符号伪常量,而不是文字数值。它们必须作为字符串引用并且区分大小写。 "::xxx"
9. 引用预定义函数
要在log 条件中引用预定义的函数,请使用functionitem,它需要 name和argsitems 分别指定函数名称及其参数:
"function": {
"name": "function_name",
"args": arguments
}
该name项目应仅指定函数名称,不带括号或参数列表。
该args项目必须满足以下条件:
如果函数不接受任何参数,则args不应给出任何 项。
如果函数确实接受参数,args则需要一个 项目,并且必须按照函数描述中列出的顺序给出参数。参数可以指预定义的变量、事件字段或字符串或数字常量。
如果参数数量不正确或参数不是函数所需的正确数据类型,则会发生错误。
例子:
{
"filter": {
"class": {
"name": "general",
"event": {
"name": "status",
"log": {
"function": {
"name": "find_in_include_list",
"args": [ { "string": [ { "field": "user.str" },
{ "string": "@"},
{ "field": "host.str" } ] } ]
}
}
}
}
}
}
前面的过滤器根据是否 在 系统变量中找到当前用户来确定是否记录 general类status事件 audit_log_include_accounts。该用户是使用事件中的字段构建的。
以下列表描述了function项目允许的预定义功能:
audit_log_exclude_accounts_is_null()
检查audit_log_exclude_accounts 系统变量是否 为NULL。在定义与旧审计日志实现相对应的过滤器时,此功能会很有帮助。
参数:
没有任何。
audit_log_include_accounts_is_null()
检查audit_log_include_accounts 系统变量是否 为NULL。在定义与旧审计日志实现相对应的过滤器时,此功能会很有帮助。
参数:
没有任何。
debug_sleep(millisec)
休眠给定的毫秒数。此功能用于性能测量。
debug_sleep() 仅可用于调试版本。
参数:
millisec:一个无符号整数,指定休眠的毫秒数。
find_in_exclude_list(account)
检查审计日志排除列表中是否存在帐户字符串(audit_log_exclude_accounts 系统变量的值 )。
参数:
account:指定用户帐户名称的字符串。
find_in_include_list(account)
检查审计日志包含列表中是否存在帐户字符串(audit_log_include_accounts 系统变量的值 )。
参数:
account:指定用户帐户名称的字符串。
query_digest([str])
根据是否给出参数,此函数具有不同的行为:
不带参数,query_digest 返回与当前事件中的语句文字文本相对应的语句摘要值。
带参数,query_digest 返回一个布尔值,指示参数是否等于当前语句摘要。
参数:
str: 这个参数是可选的。如果给定,则它指定要与当前事件中的语句的摘要进行比较的语句摘要。
例子:
此项function不包含任何参数,因此query_digest将当前语句摘要作为字符串返回:
"function": {
"name": "query_digest"
}
此项function包含一个参数,因此query_digest返回一个布尔值,指示该参数是否等于当前语句摘要:
"function": {
"name": "query_digest",
"args": "SELECT ?"
}
这个函数是在 MySQL 8.0.26 中添加的。
string_find(text, substr)
检查substr值是否包含在text值中。此搜索区分大小写。
参数:
text: 要搜索的文本字符串。
substr: 要在 中搜索的子字符串text。
事件字段值的替换
10. 事件字段值的替换
从 MySQL 8.0.26 开始,审计过滤器定义支持替换某些审计事件字段,以便记录的事件包含替换值而不是原始值。此功能使记录的审计记录能够包含语句摘要而不是文字语句,这对于语句可能会暴露敏感值的 MySQL 部署非常有用。
审计事件中的字段替换工作如下:
字段替换在审计过滤器定义中指定,因此必须启用审计日志过滤,如第 6.4.5.7 节“审计日志过滤”中所述。
并非所有字段都可以替换。 表 6.42,“可替换的事件字段”显示了哪些字段在哪些事件类中是可替换的。
表 6.42 可替换的事件字段
事件类 字段名称
general general_query.str
table_access query.str
更换是有条件的。过滤器定义中的每个替换规范都包含一个条件,根据条件结果,可以更改或保持可替换字段不变。
如果发生替换,则替换规范使用为此目的允许的函数指示替换值。
如表 6.42,“可替换的事件字段”所示,目前唯一可替换的字段是那些包含语句文本的字段(发生在general和table_access 类的事件中 )。此外,唯一允许指定替换值的函数是 query_digest。这意味着唯一允许的替换操作是用其相应的摘要替换语句文字文本。
因为字段替换发生在早期审计阶段(过滤期间),所以无论稍后写入的日志格式如何(即审计日志插件生成 XML 还是 JSON 输出),都适用选择是否写入语句文字文本或摘要值。
字段替换可以在不同级别的事件粒度上进行:
要对类中的所有事件执行字段替换,请在类级别过滤事件。
要在更细粒度的基础上执行替换,请包括其他事件选择项。例如,您可以仅对给定事件类的特定子类执行字段替换,或者仅在字段具有某些特征的事件中执行字段替换。
在过滤器定义中,通过包含一个print项目来指定字段替换,其语法如下:
"print": {
"field": {
"name": "field_name",
"print": condition,
"replace": replacement_value
}
}
在printitem 内,它的 fielditem 用这三个 item 来表示是否发生替换以及如何发生替换:
name:替换(可能)发生的字段。 field_name必须是表 6.42 “要替换的事件字段”中显示的那些之一 。
print: 决定是保留原字段值还是替换的条件:
如果condition计算为 true,则该字段保持不变。
如果condition计算为 false,则使用项目的值进行替换replace。
要无条件替换字段,请指定如下条件:
"print": false
replace:当print条件计算为 时使用的替换值false。指定 replacement_value使用 function项目。
例如,此过滤器定义适用于general类中的所有事件,用其摘要替换语句文字文本:
{
"filter": {
"class": {
"name": "general",
"print": {
"field": {
"name": "general_query.str",
"print": false,
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
}
}
}
前面的过滤器使用此项print无条件地替换包含在general_query.str其摘要值中的语句文字文本:
"print": {
"field": {
"name": "general_query.str",
"print": false,
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
print可以用不同的方式编写项目以实现不同的替换策略。replace刚刚显示的 项目使用此function 构造指定替换文本以返回表示当前语句摘要的字符串:
"function": {
"name": "query_digest"
}
该query_digest函数还可以以另一种方式使用,作为返回布尔值的比较器,从而使其能够在print条件中使用。为此,请提供一个指定比较语句摘要的参数:
"function": {
"name": "query_digest",
"args": "digest"
}
在这种情况下,query_digest返回 true或false取决于当前语句摘要是否与比较摘要相同。使用query_digest这种方式使过滤器定义能够检测与特定摘要匹配的语句。以下结构中的条件仅对摘要等于 的语句成立 SELECT ?,因此仅对与摘要不匹配的语句进行替换:
"print": {
"field": {
"name": "general_query.str",
"print": {
"function": {
"name": "query_digest",
"args": "SELECT ?"
}
},
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
要仅对与摘要匹配的语句执行替换,请使用not反转条件:
"print": {
"field": {
"name": "general_query.str",
"print": {
"not": {
"function": {
"name": "query_digest",
"args": "SELECT ?"
}
}
},
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
假设您希望审计日志仅包含语句摘要而不包含文字语句。为此,您必须对所有包含语句文本的事件执行替换;即general和 table_access类中的事件。较早的过滤器定义展示了如何无条件地替换general事件的语句文本。要对table_access事件执行相同的操作 ,请使用类似的过滤器,但将类从 更改general 为table_access,将字段名称从 general_query.str更改为 query.str:
{
"filter": {
"class": {
"name": "table_access",
"print": {
"field": {
"name": "query.str",
"print": false,
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
}
}
}
组合general和 table_access过滤器会生成一个过滤器,该过滤器对所有包含语句文本的事件执行替换:
{
"filter": {
"class": [
{
"name": "general",
"print": {
"field": {
"name": "general_query.str",
"print": false,
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
},
{
"name": "table_access",
"print": {
"field": {
"name": "query.str",
"print": false,
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
}
]
}
}
要仅对类中的某些事件执行替换,请向过滤器添加更具体地指示何时发生替换的项目。以下过滤器适用于table_access类中的事件,但仅对insert和 update事件执行替换(保持 read和delete事件不变):
{
"filter": {
"class": {
"name": "table_access",
"event": {
"name": [
"insert",
"update"
],
"print": {
"field": {
"name": "query.str",
"print": false,
"replace": {
"function": {
"name": "query_digest"
}
}
}
}
}
}
}
}
此过滤器执行general与列出的帐户管理语句相对应的类事件的替换 (效果是隐藏语句中的凭据和数据值):
{
"filter": {
"class": {
"name": "general",
"event": {
"name": "status",
"print": {
"field": {
"name": "general_query.str",
"print": false,
"replace": {
"function": {
"name": "query_digest"
}
}
}
},
"log": {
"or": [
{
"field": {
"name": "general_sql_command.str",
"value": "alter_user"
}
},
{
"field": {
"name": "general_sql_command.str",
"value": "alter_user_default_role"
}
},
{
"field": {
"name": "general_sql_command.str",
"value": "create_role"
}
},
{
"field": {
"name": "general_sql_command.str",
"value": "create_user"
}
}
]
}
}
}
}
}
有关可能 general_sql_command.str值的信息,请参阅 测试事件字段值。
11. 更换用户过滤器
在某些情况下,过滤器定义可以动态更改。为此,请filter 在现有filter. 例如:
{
"filter": {
"id": "main",
"class": {
"name": "table_access",
"event": {
"name": [ "update", "delete" ],
"log": false,
"filter": {
"class": {
"name": "general",
"event" : { "name": "status",
"filter": { "ref": "main" } }
},
"activate": {
"or": [
{ "field": { "name": "table_name.str", "value": "temp_1" } },
{ "field": { "name": "table_name.str", "value": "temp_2" } }
]
}
}
}
}
}
}
当子过滤器中的activate 项目评估为时,将激活新过滤器true。不允许activate在顶层 使用filter。
通过使用子ref过滤器内的项目来引用原始过滤器,可以将新过滤器替换 为原始过滤器id。
显示的过滤器操作如下:
该main过滤器等待 table_access的事件,无论是 update或delete。
如果updateor delete table_access 事件发生在temp_1or temp_2表上,则过滤器将替换为内部过滤器(没有id,因为不需要显式引用它)。
如果发出命令结束信号(general/status 事件),则会将一个条目写入审计日志文件,并将过滤器替换为main 过滤器。
过滤器对于记录更新或删除temp_1或 temp_2表中任何内容的语句非常有用,例如:
UPDATE temp_1, temp_3 SET temp_1.a=21, temp_3.a=23;
该语句生成多个 table_access事件,但审计日志文件仅包含general/ status条目。
Audit 对MySQL Enterprise性能影响
开启audit审计由于额外的日志记录磁盘开销等对MySQL数据库性能有一定的影响,下面对性能影响的程度做了一个详细的测试
测试准备
测试环境:linux系统, 8核CPU ,16G内存,128G SSD硬盘
测试配置:MySQL8.0.27企业版的docker容器。该容器运行独占宿主主机资源。仅存在单个Audit.log审计插件。无其他企业级插件占用主机资源
【my.cnf】配置对比
启用记录所有事件
为充分体现启用 Audit Log 对数据库性能的影响,采用记录所有事件(即不过滤掉任何事件)的审计策略配置:
执行测试脚本
测试脚本:
/--*!
sysbench /usr/share/sysbench/oltp_read_write.lua --db-driver=mysql --mysql-host=10.1.0.4 --mysql-port=3306 --mysql-user=root --mysql-password=**** --mysql-db=user1_db --range_size=100 --table_size=500000 --tables=10 --num-threads=${thread} --events=0 --time=900 --rand-type=uniform --report-interval=10 run
!*--/
说明:
sysbench采用读写综合的 oltp_read_write.lua
thread进程数由脚本循环迭代更新。(“有/无Audit”由{1,8,16,32,64,128,256,512})(“有Audit多线程测试”,由{64,128})
生成的测试用例表是10个,每个表500000条记录
每个线程测试用时 900秒.
随机类型为固定模式
测试结果报告
- "无Audit"/"有Audit"数据库OLTP业务负载运行性能对比测试:
|
Threads值 |
TPS(无Audit)(N) |
TPS(有Audit)(Y) |
TPS差异(N-Y) |
TPS差异率(((N-Y)/N)*100%) |
|
1 |
453.26 |
417.533 |
35.727 |
7.88% |
|
8 |
2472.97 |
1505.88 |
967.09 |
39.11% |
|
16 |
2569.11 |
1759.66 |
809.45 |
31.51% |
|
32 |
2637.03 |
1892.11 |
744.92 |
28.25% |
|
64 |
2657.02 |
2013.32 |
643.7 |
24.23% |
|
128 |
2853.80 |
2128.11 |
725.69 |
25.43% |
|
256 |
2798.46 |
2041.77 |
756.69 |
27.04% |
|
512 |
2707.49 |
1811.67 |
895.82 |
33.09% |
测试结论1
结论: 相关测试结果表明,在测试软硬件资源环境和相关MySQL配置参数条件下,使用sysbench读写综合的 oltp_read_write.lua 测试脚本进行多线程压力测试,当Audit Filter采用记录所有事件(即不过滤掉任何事件)时,启用Audit Log对数据库OLTP业务负载运行性能影响显著。在threads=128时,“无Audit”/“有Audit”的TPS均达到最高(2853.80/2128.11),此时“有Audit”的TPS比“无Audit”下降 25.43%;其后,这个差异率随threads的增加有增加的趋势;说明在达到最好工作状况后,随着负载的增加,启用Audit Log对数据库OLTP业务运行性能影响可能随之加大。
图表数据采用的sysbench的threads 数量值使用前面“无Audit/有Audit”对比测试结果中,TPS达到最高时对应的threads 数量值(即前面最好工况时的threads=128)和threads=64 数量值较优工况的TPS对比图
- 调整audit-log-buffer-size 值对数据库OLTP业务负载运行性能影响测试
|
有audit 多线程测试 |
||
|
audit-log-buffer-size |
TPS总均值(64 thread) |
TPS总均值(128 thread) |
|
1M |
2128.05 |
2191.68 |
|
4M |
2132.44 |
2215.34 |
|
16M |
2137.14 |
2235.73 |
|
64M |
2137.27 |
2236.62 |
|
256M |
2124.56 |
2220.85 |
|
512M |
2049.94 |
2179.9 |
|
1G |
1983.73 |
2045.49 |
|
|
|
|
|
总均值 |
2099.02 |
2189.37 |
|
最大值 |
2137.27 |
2236.62 |
|
最小值 |
1983.73 |
2045.49 |
测试结论2
相关测试结果表明,在测试软硬件资源环境和相关MySQL配置参数条件下,使用sysbench读写综合的 oltp_read_write.lua 测试脚本进行多线程压力测试,当Audit Filter采用记录所有事件(即不过滤掉任何事件)时,从缺省的audit-log-buffer-size=1M开始,增加audit-log-buffer-size 值对数据库OLTP业务负载运行性能影响不明显;而且当audit-log-buffer-size=64M,TPS达到相对最大值2236.62之后,随着audit-log-buffer-size的增加,TPS反而有下降的趋势。由此可以看出,当前测试条件下,使用缺省audit-log-buffer-size的因素基本可以忽略,其值无需调整,采用缺省值即可。
浙公网安备 33010602011771号