深度解读RDS for MySQL 审计日志功能和原理
本文分享自华为云社区《【华为云MySQL技术专栏】RDS for MySQL 审计日志功能介绍》,作者:GaussDB数据库。
1. 背景
在生产环境中,当数据库出现故障或问题时,运维人员需要快速定位出异常或者高危的SQL语句。这时,审计日志能够提供详细的记录,帮助追踪每个数据库操作的执行者、执行时间以及受影响的数据对象,从而大大加速故障排查和恢复流程。
MySQL企业版提供了审计日志插件,可以对数据库操作进行细粒度的审计。该插件支持记录用户登录、查询执行、数据修改等重要操作。然而,在MySQL社区版中,只是提供了审计日志的相关插件接口定义和功能描述,并不支持原生的审计日志功能。
为了弥补这一功能的缺失,华为云RDS for MySQL通过集成Percona公司开源的审计日志插件,实现了MySQL审计日志功能。该功能已在RDS for MySQL 5.7和RDS for MySQL 8.0版本中开放,满足了用户对数据库安全审计的需求,同时增强了数据库的合规性和可用性。
本文将以RDS for MySQL为研究对象,对于审计日志进行功能介绍和原理解析。
2. 功能参数介绍
当在RDS for MySQL上开启审计日志功能,用户可以通过SHOW variables LIKE 'audit%';语句查看与审计日志功能相关的变量名和参数值。
mysql> SHOW variables LIKE 'audit%';
+-------------------------------------+---------------+
| Variable_name                       | Value         |
+-------------------------------------+---------------+
| audit_log_anonymized_ip             |               |
| audit_log_buffer_size               | 1048576       |
| audit_log_csv2_escape               | OFF           |
| audit_log_csv2_old_separated_format | OFF           |
| audit_log_csv2_truncation           | ON            |
| audit_log_exclude_accounts          |               |
| audit_log_exclude_commands          |               |
| audit_log_exclude_databases         |               |
| audit_log_file                      | audit.log     |
| audit_log_flush                     | OFF           |
| audit_log_force_rotate              | OFF           |
| audit_log_format                    | CSV2          |
| audit_log_handler                   | FILE          |
| audit_log_include_accounts          |               |
| audit_log_include_commands          |               |
| audit_log_include_databases         |               |
| audit_log_policy                    | ALL           |
| audit_log_rotate_on_size            | 104857600     |
| audit_log_rotations                 | 50            |
| audit_log_strategy                  | ASYNCHRONOUS  |
| audit_log_syslog_facility           | LOG_USER      |
| audit_log_syslog_ident              | percona-audit |
| audit_log_syslog_priority           | LOG_INFO      |
+-------------------------------------+---------------+
23 rows in set (0.01 sec)这些参数控制着审计日志插件的整体功能,允许用户灵活调节审计日志的各个方面。通过合理设置和调整这些参数,用户可以精确确定日志的记录范围、记录级别、存储方式等。例如,用户可以通过audit_log_policy 决定审计日志的记录级别,也可以通过改变audit_log_strategy 调整审计日志的刷新策略。
在 RDS for MySQL中,部分变量因安全合规考虑未开放修改。下表对审计日志功能中相关变量的作用和默认值进行介绍。



表格 1 审计日志变量介绍
3. 日志内容解析
在RDS for MySQL上,audit_log_policy的默认值为ALL。在该级别下,审计日志会记录包括DML(数据操作语言)、DDL(数据定义语言)、DCL(数据控制语言)操作以及连接或断开连接等数据库活动。需要注意的是,不同类型的活动包含的日志字段有所不同。下面将从常见DDL、DML、DCL操作以及数据库连接与断开连接产生的审计日志进行内容解析。
DDL、DML和DCL
对于DDL、DML和DCL操作,所生成的审计日志格式是相同的。对于日志字段的具体含义详见如下。
- RECORD ID:审计日志唯一ID,用来标识每条审计日志。 
- STATUS:状态码,非0表示ERROR。 
- NAME:操作命令分类,QUERY、EXECUTE、QUIT、CONNECT等。 
- TIMESTAMP:记录日志发生的时间戳。 
- COMMAND_CLASS:记录DDL、DML和DCL操作的类型,SELECT、INSERT、DELETE等。 
- SQLTEXT:执行SQL语句的内容。 
- USER:连接数据库的用户名。 
- HOST:连接数据库的主机名。 
- IP:连接数据库的客户端IP地址。 
- DATABASE:连接指定的数据库名。 
Connect和Disconnect
连接或断开连接事件,在用户登录成功或登录失败时均会有日志记录。与DDL和DDL操作产生的审计日志不同,连接事件产生审计日志增加了PRIV_USER、OS_LOGIN等字段,下面对于连接或断开连接产生的审计日志进行解析。
- RECORD ID: 审计日志唯一ID,用来标识每条审计日志。 
- STATUS:状态码,非0表示ERROR。 
- NAME: 操作命令分类,QUERY、EXECUTE、QUIT、CONNECT等。 
- TIMESTAMP:记录日志发生的时间戳 
- USER:连接数据库的用户名。 
- PRIV_USER:经过身份验证的用户名。 
- OS_LOGIN:外部用户名。 
- PROXY_USER:代理用户名。 
- HOST:连接数据库的主机名。 
- IP:连接数据库的客户端IP地址。 
- DATABASE:连接指定的数据库名。 
通过对审计日志内容的解析,用户不仅可以快速地查看任意时间段数据库的活动状态,还能够准确了解每条SQL语句的详情,包括执行的用户、时间戳、查询类型等关键信息。这样详细的记录为安全审查、问题排查以及性能优化提供了强有力的支撑。
4.RDS for MySQL审计日志原理浅析
RDS for MySQL审计功能的核心是通过不同类型的事件驱动审计日志插件完成对应类型日志的记录。在RDS for MySQL中一共支持两类事件,即一般事件和连接事件。一般事件可以理解为用户执行的DDL、DML和DCL语句。连接事件则是连接数据库(Connect)和断开连接(Disconnect)数据库。审计日志插件支持事件定义的相关代码如下。
static int is_event_class_allowed_by_policy(mysql_event_class_t event_class,num audit_log_policy_t policy) {
  static unsigned int class_mask[] = {
      /* ALL */
      (1 << MYSQL_AUDIT_GENERAL_CLASS) | (1 << MYSQL_AUDIT_CONNECTION_CLASS),
      0,                                   /* NONE */
      (1 << MYSQL_AUDIT_CONNECTION_CLASS), /* LOGINS */
      (1 << MYSQL_AUDIT_GENERAL_CLASS),    /* QUERIES */
  };
  return (class_mask[policy] & (1 << event_class)) != 0;
}当发生可审计事件时,服务器会调用相关的审计接口,以便向已注册的审计日志插件传递该事件的信息,确保审计插件在必要时能够接收到并处理该事件。
审计日志功能在RDS for MySQL内核的入口函数是mysql_audit_notify。通过对应事件驱动审计日志插件的工作。主要工作流程调用栈如下所示。
  do_command
    ->dispatch_commnad
        ->mysql_audit_notify
            ->event_class_dispatch
                  // 检查当前插件是否需要处理此事件
                ->plugin_dispatch
                    // 按事件类别下发审计任务
                    ->audit_log_notify数据库内核在收到一条SQL的执行请求后,首先,会通过do_command函数处理该连接。处理完成后,由dispatch_command函数依据不同SQL类型进行命令分发。之后,审计入口函数mysql_audit_notify会完成审计日志记录前的准备和校验工作。如果校验通过,则后续工作会由已注册的审计日志插件中的其他函数完成。
通过函数调用栈可以看出,审计日志功能与数据库内核之间实现了高度解耦。二者通过预先注册的函数接口进行对接,这种设计提高了未来功能扩展的灵活性。
审计日志插件的校验和资源准备工作由mysql_audit_acquire_plugins函数完成,当该函数完成校验后,即审计日志插件已完成注册并且相关资源也已完成绑定,接下来将由audit_log_notify函数按照事件的类型和相关参数设定完成任务分发。audit_log_notify会调用audit_log_write函数完成审计日志的写入,audit_log_write会依据audit_log_handler变量的值来判断是写入审计日志文件还是系统日志。
若是写入日志文件中,此时还会判断日志的写入策略;如果audit_log_strategy是PERFORMANCE或ASYNCHRONOUS,则会调用audit_handle_file_write_buf函数,将日志内容写入审计日志插件的缓冲区中,否则会调用audit_handle_file_write_nobuf函数,将日志内容直接写入操作系统文件缓存。
若audit_log_handler值为SYSLOG,则意味着审计日志会直接写到系统日志中。那么则会通过调用audit_handler_syslog_write完成日志向系统日志的写入。审计日志内部函数调用流程如图所示。

图1 审计日志插件工作流程图
从图中可以看到,审计日志的落盘方式主要有两种,分别是通过文件系统完成日志落盘和利用审计日志刷盘线程不断地将缓冲区的日志写入磁盘中。审计日志的缓冲区是在审计日志插件初始化时完成相关资源的分配,其结构体如下:
struct audit_log_buffer {
  // 缓冲区内容
  char *buf;
  // 缓冲区大小
  size_t size;
  // 写日志位置
  size_t write_pos;
  // 日志落盘位置
  size_t flush_pos;
  // 日志落盘工作线程
  pthread_t flush_worker_thread;
  // 缓冲区是否暂停
  int stop;
  // 缓冲区满是否丢弃该日志
  int drop_if_full;
  void *write_func_data;
  audit_log_write_func write_func;
  mysql_mutex_t mutex;
  mysql_cond_t flushed_cond;
  mysql_cond_t written_cond;
  log_record_state_t state;
};从审计日志缓冲区结构体可以看到,日志缓冲区主要通过日志写入函数和日志落盘线程完成其核心功能。
当日志需要写入缓冲区时,首先会比较日志的长度和缓冲区的大小。如果审计日志的长度大于日志缓冲区的大小,并且缓冲区满且选择不丢弃该日志时,审计日志的落盘线程暂停工作,并会绕过日志的缓冲区,直接写入文件缓冲区中。当审计日志长度小于日志缓冲区大小时,此时会将日志的内容拷贝到文件缓冲区中,并更新缓冲区write_pos等相关参数,等待日志落盘线程的工作。如果当前写入位置超过整个缓冲区大小的一半,则会立刻通知落盘线程,完成审计日志的落盘。
审计日志的落盘工作主要由日志落盘工作线程完成。如果日志缓冲区没有关闭并且缓冲区中还存在日志尚未落盘,则会循环调用日志落盘函数进行日志写入。
static void *audit_log_flush_worker(void *arg) {
  audit_log_buffer_t *log = (audit_log_buffer_t *)arg;
  // 线程初始化
  my_thread_init();
  // 如果日志缓冲区没有关闭并且当前还有日志未落盘
  while (!(log->stop && log->flush_pos == log->write_pos)) {
    // 进行日志的落盘工作
    audit_log_flush(log);
  }
  // 关闭线程
  my_thread_end();
  return nullptr;
}对于日志落盘函数,会通过循环判断write_pos和flush_pos是否相等,如果二者相等并且日志缓冲区没有停止工作,此时会等待1秒进入循环;如果二者不相等,说明缓冲区中有新的日志需要落盘。
此时,若write_pos大于缓冲区的大小,日志插件会把flush_pos后的所有日志进行落盘,并将当前日志的状态设为LOG_RECORD_INCOMPLETE。若write_pos在缓冲区大小范围内,则会将该条日志完整写入审计日志文件中并将该日志状态设为LOG_RECORD_COMPLETE。在完成日志落盘操作后,与缓冲区相关变量值会同步更新,并为下次日志落盘做好准备。
5.使用说明
1)数据库实例开启审计日志
登录管理控制台,在云数据库RDS for MySQL的“实例管理”页面,单击目标实例名称,进入基本信息页面。在左侧导航栏,点击“SQL审计”,在“SQL审计”右侧点击开启按钮,在弹框中点击“确定”,打开审计日志开关。

图2 设置审计日志功能
2)审计日志的下载
开启审计日志后,数据库的相关活动都会以日志的形式记录在OBS中,用户可以在控制台界面进行审计日志的下载。

图3 控制台界面下载审计日志
6.总结
RDS for MySQL的审计日志功能在用户活动监控、权限变更追踪和性能优化等方面有着重要的作用。它不仅帮助企业提升数据库的整体安全性,满足日益严格的合规性要求,还在故障排查中提供有价值的信息。这一功能能够精确的记录用户的数据库操作,有助于识别潜在的安全威胁,并为性能瓶颈分析和优化提供详实的数据支持。
华为开发者空间,汇聚鸿蒙、昇腾、鲲鹏、GaussDB、欧拉等各项根技术的开发资源及工具,致力于为每位开发者提供一台云主机、一套开发工具及云上存储空间,让开发者基于华为根生态创新。
深度解读RDS for MySQL 审计日志功能和原理的更多相关文章
- Ubuntu下rsyslog集中收集mysql审计日志
		服务端 1.安装最新版本rsyslog sudo apt-get install software-properties-common python-software-properties sudo ... 
- MySQL二进制日志功能介绍
		二进制日志记录所有更新数据的SQL语句,其中也包含可能更新数据的SQL语句,例如DELETE语句执行过程中无匹配的行.二进制日志中还包含了与执行SQL语句相关的内容,例如SQL语句执行的时间.错误代码 ... 
- rsyslog服务器同步其他服务器上面应用日志(如mysql审计日志 、nginx日志)
		**环境说明**系统:ubuntu 14.04 (CentOS可以参考http://www.cnblogs.com/hanyifeng/p/5463338.html) rsyslog版本 :8.16. ... 
- abp审计日志功能的关闭
		参考官网介绍:https://aspnetboilerplate.com/Pages/Documents/Audit-Logging 
- MySQL慢日志功能分析及优化增强
		本文由 网易云发布. MySQL慢日志(slow log)是MySQL DBA及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等SQL语句,为进行系统调优提供依据.本 ... 
- MySQL慢日志线上问题分析及功能优化
		本文来源于数据库内核专栏. MySQL慢日志(slow log)是MySQL DBA及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等SQL语句,为进行系统调优提供依据 ... 
- Kubernetes审计日志方案
		前言 当前Kubernetes(K8S)已经成为事实上的容器编排标准,大家关注的重点也不再是最新发布的功能.稳定性提升等,正如Kubernetes项目创始人和维护者谈到,Kubernetes已经不再是 ... 
- Abp + MongoDb 改造默认的审计日志存储位置
		一.背景 在实际项目的开发当中,使用 Abp Zero 自带的审计日志功能写入效率比较低.其次审计日志数据量中后期十分庞大,不适合与业务数据存放在一起.所以我们可以重新实现 Abp 的 IAuditi ... 
- 配置Mysql审计
		mysql-audit.json:Mysql审计日志 插件下载地址: https://bintray.com/mcafee/mysql-audit-plugin/release/1.1.4-725#f ... 
- 最全Kubernetes审计日志方案
		前言 当前Kubernetes(K8S)已经成为事实上的容器编排标准,大家关注的重点也不再是最新发布的功能.稳定性提升等,正如Kubernetes项目创始人和维护者谈到,Kubernetes已经不再是 ... 
随机推荐
- Python按条件删除Excel表格数据的方法
			本文介绍基于Python语言,读取Excel表格文件,基于我们给定的规则,对其中的数据加以筛选,将不在指定数据范围内的数据剔除,保留符合我们需要的数据的方法. 首先,我们来明确一下本文的具体需 ... 
- wpf 如何7步写一个badge控件
			首先看一下效果: 任意控件可以附加一个文字在控件的右上角,并带有红色背景 第一步,新建一个空的wpf项目: 第二步,创建一个类,取名为badge: 第三步,将badge的父类设置成 System.W ... 
- CF650D Zip-line
			CF650D Zip-line 大概题面: 给定一个长度为 \(n\) 的序列以及\(m\)个操作,每个操作形如" \(a_i,b_i\) ",表示将序列中第 \(a_i\) 个数 ... 
- poi的excel导出
			poi的excel导出 这个导出依赖于模板文件,可便捷设置表头样式. 也可以不使用模板,直接创建. 1.引入poi依赖 <dependency> <groupId>org.ap ... 
- 资产管理平台去除zabbix字样
			1.主机可用性 修改/usr/share/zabbix/include/html.inc.php,文件没有改动过的话在602行,将zbx改成我们需要的即可 2.修改系统信息 修改/usr/share/ ... 
- C# 使用 PaddleOCRSharp 识别 图片中的文字、 使用QRCoder生成二维码
			目录 使用PaddleOCRSharp识别图片中的文字 PaddleOCRSharp资料汇总: 1.将源码编译成对应的.Net 版本引入到项目中 2. 初始化PaddleOCREngine 3. 调用 ... 
- WebShell流量特征检测_哥斯拉篇
			80后用菜刀,90后用蚁剑,95后用冰蝎和哥斯拉,以phpshell连接为例,本文主要是对这四款经典的webshell管理工具进行流量分析和检测. 什么是一句话木马? 1.定义 顾名思义就是执行恶意指 ... 
- C#/.net core  “hello”.IndexOf(“\0”,2)中的坑
			先想想看,你认为下面代码返回值是多少? "hello".IndexOf("", 2); "hello".IndexOf("\0&q ... 
- IntelliJ Idea 常用快捷键参照列表
			IntelliJ Idea 常用快捷键参照列表 Ctrl+Shift + Enter,语句完成 "!",否定完成,输入表达式时按 "!"键 Ctrl+E,最近的 ... 
- Email 关于 POP3 IMAP SMTP office365 Outlook Gmail G-Suit shared mailbox小小理解
			Outlook 是微软的一个 email 软件, 管理 email 的 UI. Gmail 是 google 的 office365 是一个配套, 里面有 email, one drive, exce ... 
