前言
1 背景概述
1.1 授权用户查询不到表?
是这样子,前几日我的一位同事需要创建一个用户并且授权几张业务表提供给伙伴小组同事使用。脚本创建,提供授权。给伙伴使用时,伙伴小组给予的回复是查询不到表,整整给摆了一道乌龙。由于是半道儿上临时受命接的项目,也不知道前任捣鼓了啥,经过排查日志发现,是设置了MySQL的审计。好,那今日就浅浅的聊一下吧,作为一个成长。
1.2 什么是MySQL审计?遵循什么规范?
MySQL Enterprise Edition 包括 MySQL Enterprise Audit,使用服务器插件实现。MySQL Enterprise Audit 使用开放的 MySQL Audit API 来启用标准的、基于策略的监控和记录在特定 MySQL 服务器上执行的连接和查询活动。MySQL Enterprise Audit 旨在满足 Oracle 审计规范,为受内部和外部监管准则约束的应用程序提供了一个开箱即用、易于使用的审计和合规性解决方案。安装后,审计插件使 MySQL 服务器能够生成包含服务器活动审计记录的日志文件。日志内容包括客户端连接和断开连接的时间,以及它们在连接时执行的操作,例如它们访问的数据库和表。
关于Oracle审计的规范,可以参考下官方提供的白皮文档。
审计概述:https://docs.oracle.com/cd/E26926_01/html/E25889/auditov-1.html#scrolltoc
审计白皮书:https://www.oracle.com/cn/a/tech/docs/technical-resources/bwp-security-audit-vault.pdf
1.3 MySQL审计解决什么问题?
// to do
2 本地实验环境
MySQL专业版(MySQL Enterprise Edition)审计请参考官方提供的解决方案和操作执行步骤:MySQL Enterprise Edition审计 ,下面来说说MySQL Community (GPL) 社区版本自建测试环境审计是如何设置的。本文是在 GNU/Linux(CentOS 7 x86_64)环境下实验,后续我又在Mac上面实验了下,都是一致的结果。
MySQL审计这里提供几种方式来讲一下,根据自己实验操作的步骤一一列出来,提供给大家借鉴,欢迎大家提出意见,不胜感激
。也希望在MySQL进阶技能树的进阶可以有这个实践。
MySQL审计的三种方式:
- General Query Log
- BinLog init_connect
- 审计插件
下面先讲一下这个 general_log。
2.1 general_log(不推荐)
默认情况下,MySQL不开启General Query Log;开启General Query Log后,MySQL将所有到达MySQL Server的SQL语句记录下来。 关于MySQL的日志,官方给予了明确的解释和说明,从字面的意思理解下,通常有以下几种日志:
日志类型 | 名称 | 日志信息 |
---|---|---|
Error log | 错误日志 | 启动、运行或停止 mysqld时遇到的问题 |
General query log | 一般查询日志 | 已建立的客户端连接和从客户端收到的语句 |
Binary log | 二进制日志 | 更改数据的语句(也用于复制) |
Relay log | 中继日志 | 从复制源服务器接收的数据更改 |
Slow query log | 慢查询日志 | 执行时间超过 long_query_time几秒钟的查询 |
DDL log (metadata log) | DDL 日志(元数据日志) | DDL 语句执行的元数据操作 |
2.2.1 查看general_log设置
执行SQL
命令可以看到默认general_log
是OFF
的,SQL关键字语句和属性值是不区分大小写(这个可以设置)。
mysql> show variables like 'general_log';
2.2.2 查看日志文件
General Query Log打开后,所有SQL的访问都会记录在general_log_file
指向的日志文件。关于全局变量general_log_file值,日志文件位置,可以执行下面命令获取到。
mysql> show variables like 'general_log_file';
默认情况下,日志文件会放在你的MySQL文件下,命名规则为机器名称.log,例如我的mysql日志放在了/usr/local/mysql-8.0.18-macos10.14-x86_64/data/
(通常情况下,我们称/usr/local/mysql-8.0.18-macos10.14-x86_64/
为MySQ_HOME
)目录,机器名称为Macbook
,那么这里的日志文件则是Macbook.log
。
首先,我们可以看一下这个文件存放了什么内容。
代码语言:javascript复制Aion.Liu $ tail -200f /usr/local/mysql-8.0.18-macos10.14-x86_64/data/Macbook.log
tail: /usr/local/mysql-8.0.18-macos10.14-x86_64/data/Macbook.log: No such file or directory
No such file or directory
这提示我们没有这个文件或目录?事实上,这个也验证了我们第1步骤的准确性,默认是关闭的。
2.2.3 手工打开General Query Log
当执行mysql> set global general_log = on;
后,我们设置了全局变量general_log
为打开状态,再次查看general_log
是打开的,为ON状态。
当我们打开之后,我们再次按照2.2.2
的步骤查看下日志文件的内容,惊喜来了,里面有文本内容了(下面我截取了部分)。
Aion.Liu $ tail -200f /usr/local/mysql-8.0.18-macos10.14-x86_64/data/Macbook.log
alert_notification.is_default,
alert_notification.disable_resolve_message,
alert_notification.send_reminder,
alert_notification.frequency
FROM alert_notification
WHERE alert_notification.org_id = 1 AND ((alert_notification.is_default = '1'))
2022-08-30T14:19:49.933094Z 3678 Prepare SELECT
alert_notification.id,
alert_notification.uid,
alert_notification.uid
FROM alert_notification
WHERE alert_notification.org_id = 1 AND alert_notification.id = 1
2022-08-30T14:20:35.933719Z 3608 Close stmt
2022-08-30T14:20:35.933977Z 3678 Prepare SELECT `id`, `org_id`, `version`, `name`, `type`, `access`, `url`, `password`, `user`, `database`, `basic_auth`, `basic_auth_user`, `basic_auth_password`, `with_credentials`, `is_default`, `json_data`, `secure_json_data`, `read_only`, `uid`, `created`, `updated` FROM `data_source` WHERE `id`=? AND `org_id`=? LIMIT 1
2022-08-30T14:20:35.934139Z 3678 Execute SELECT `id`, `org_id`, `version`, `name`, `type`, `access`, `url`, `password`, `user`, `database`, `basic_auth`, `basic_auth_user`, `basic_auth_password`, `with_credentials`, `is_default`, `json_data`, `secure_json_data`, `read_only`, `uid`, `created`, `updated` FROM `data_source` WHERE `id`=4 AND `org_id`=1 LIMIT 1
2022-08-30T14:20:35.934361Z 3678 Close stmt
2022-08-30T14:20:35.935332Z 3608 Prepare SELECT
alert_notification.id,
alert_notification.uid,
alert_notification.org_id,
alert_notification.name,
alert_notification.type,
alert_notification.created,
alert_notification.updated,
alert_notification.settings,
alert_notification.secure_settings,
alert_notification.is_default,
alert_notification.disable_resolve_message,
alert_notification.send_reminder,
alert_notification.frequency
FROM alert_notification
WHERE alert_notification.org_id = ? AND ((alert_notification.is_default = ?))
2022-08-30T14:20:35.935422Z 3608 Execute SELECT
alert_notification.id,
alert_notification.uid,
alert_notification.org_id,
alert_notification.name,
alert_notification.type,
alert_notification.created,
alert_notification.updated,
alert_notification.settings,
alert_notification.secure_settings,
alert_notification.is_default,
alert_notification.disable_resolve_message,
alert_notification.send_reminder,
alert_notification.frequency
……
查看下当前日志文件的大小324K,这里我们打开日志后,日志就会实时写入到日志文件中。
代码语言:javascript复制Aion.Liu $ du -h /usr/local/mysql-8.0.18-macos10.14-x86_64/data/Macbook.log
324K /usr/local/mysql-8.0.18-macos10.14-x86_64/data/Macbook.log
2.2.4 实验
1)我们在命令行工具窗口任意执行一些语句,我这里就查询下table1的表记录数
有多少。
2)这个时候,我们看下日志文件的内容是如何记录的
很好理解了吧,查询类型
以及执行语句的内容
已经被记录到了日志中。
3)使用客户端工具执行SQL命令,在我本地实验数据库study中,查询abc这张表的两个列数据。
4)这个时候,我们在过去日志文件查询下。
是不是很好理解了,这个时候在服务器执行的操作会被记录到设置的日志文件Macbook.log
中。
5)我们关闭全局日志设置试试 执行命令如下命令
代码语言:javascript复制mysql> set global general_log = off;
Query OK, 0 rows affected (0.00 sec)
查看日志文件内容
代码语言:javascript复制tail -200f /usr/local/mysql-8.0.18-macos10.14-x86_64/data/Macbook.log
由于我这里开启了调度事件和一些触发器,导致一直在执行SQL语句,所以会打印出来很多日志信息。当我们再次关闭时,日志将不在打印,并且在最后一行告知我们已经关闭了日志。那是不是所有的操作都会被记录到日志中呢,你如果有兴趣可以在本地试试。写到这里,前面遗留的一个 // to do
就无需我再多言了。
3 总结
开启General Query Log只要用户执行了操作,无论对错,MySQL就会记录日志,这样的话日志量会非常庞大,对数据库效率有影响。所以我们一般不建议开启开功能,个别情况下可能会临时的开一段时间以供排查故障等使用。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!