Skip to content

MySQL 审计日志配置与分析

审计日志概述

审计日志的作用

作用详细说明
合规审计满足PCI DSS、HIPAA、SOX等合规要求
安全监控记录所有数据库访问和操作
故障追溯追踪导致数据库问题的操作
权限审计验证用户权限使用是否合规
操作审计记录管理员的关键操作

版本差异

特性MySQL 5.6MySQL 5.7MySQL 8.0
企业版审计插件支持支持支持
审计日志JSON格式不支持支持支持
审计日志过滤基础支持增强支持完整支持
审计日志加密不支持不支持支持
审计日志压缩不支持不支持支持
审计日志旋转策略基础支持增强支持完整支持

审计日志的实现方式

实现方式特点适用场景
MySQL企业版审计插件官方支持,功能全面企业级生产环境
MariaDB审计插件开源,与MySQL兼容开源环境
Percona Audit Log Plugin开源,Percona Server内置Percona用户
第三方审计工具如McAfee MySQL Audit、Imperva特定需求场景
二进制日志+慢查询日志基础审计能力轻量级需求

审计日志配置

Percona Audit Log Plugin配置

安装与启用

bash
# 1. 确认插件是否已安装
mysql -u root -p -e "SHOW PLUGINS;" | grep audit_log

# 2. 如未安装,安装插件
mysql -u root -p -e "INSTALL PLUGIN audit_log SONAME 'audit_log.so';"

# 3. 验证插件安装成功
mysql -u root -p -e "SHOW PLUGINS;" | grep audit_log

核心配置参数

参数描述版本支持推荐值
audit_log启用审计日志5.6+ON
audit_log_file审计日志文件路径5.6+/var/log/mysql/audit.log
audit_log_format审计日志格式5.6+JSON
audit_log_rotation_policy审计日志轮换策略5.6+size
audit_log_rotate_on_size日志大小限制5.6+100M
audit_log_file_rotations日志保留数量5.6+10
audit_log_events审计事件类型5.6+CONNECT,QUERY,TABLE
audit_log_filter审计过滤规则5.7+按需配置
ini
# 审计日志插件配置
[mysqld]

# 启用审计日志
audit_log=ON

# 审计日志文件路径
audit_log_file=/var/log/mysql/audit.log

# 审计日志格式
audit_log_format=JSON
# 可选值:OLD、JSON、CSV

# 审计日志轮换策略
audit_log_rotation_policy=size
# 可选值:none、size、time

# 日志大小限制(当policy=size时)
audit_log_rotate_on_size=100M

# 日志保留数量
audit_log_file_rotations=10

# 审计事件类型
audit_log_events=CONNECT,QUERY,TABLE
# 可选值:CONNECT,QUERY,TABLE,QUERY_DDL,QUERY_DML,QUERY_DCL

# 审计过滤规则
audit_log_filter='{"filter":{"log":{"connect":true,"query":true,"table":true}}}'

不同场景的配置示例

生产环境配置
ini
[mysqld]
audit_log=ON
audit_log_file=/var/log/mysql/audit.log
audit_log_format=JSON
audit_log_rotation_policy=size
audit_log_rotate_on_size=200M
audit_log_file_rotations=20
audit_log_events=CONNECT,QUERY_DDL,QUERY_DCL,TABLE
audit_log_filter='{"filter":{"log":{"connect":true,"query":{"types":["create","alter","drop","grant","revoke","delete"]},"table":true}}}'
开发测试环境配置
ini
[mysqld]
audit_log=ON
audit_log_file=/var/log/mysql/audit-dev.log
audit_log_format=CSV
audit_log_rotation_policy=time
audit_log_rotate_interval=24h
audit_log_file_rotations=7
audit_log_events=CONNECT,QUERY,TABLE
audit_log_filter='{"filter":{"log":{"connect":true,"query":true,"table":true}}}'
高安全环境配置
ini
[mysqld]
audit_log=ON
audit_log_file=/var/log/mysql/audit-secure.log
audit_log_format=JSON
audit_log_rotation_policy=size
audit_log_rotate_on_size=100M
audit_log_file_rotations=30
audit_log_events=CONNECT,QUERY_DDL,QUERY_DML,QUERY_DCL,TABLE
audit_log_filter='{"filter":{"log":true}}'
# 记录所有事件

MariaDB Audit Plugin配置

安装与启用

bash
# 1. 安装插件
mysql -u root -p -e "INSTALL SONAME 'server_audit';"

# 2. 验证插件
mysql -u root -p -e "SHOW PLUGINS;" | grep server_audit

核心配置参数

ini
[mysqld]
# 启用审计
server_audit_logging=ON

# 审计日志文件
server_audit_file_path=/var/log/mysql/server_audit.log

# 日志格式
server_audit_format=OLD
# 可选值:OLD, JSON

# 审计事件类型
server_audit_events='CONNECT,QUERY,TABLE'

# 日志大小限制
server_audit_file_rotations=10
server_audit_file_size_limit=100000000

# 排除的数据库
server_audit_excl_users='mysql.sys,root@localhost'

# 包含的用户
server_audit_incl_users='admin,app_user'

MySQL企业版审计插件配置

ini
[mysqld]
# 启用审计插件
plugin-load=audit_log.so
audit-log=FORCE_PLUS_PERMANENT

# 审计日志文件
audit-log-file=/var/log/mysql/audit.log

# 审计日志格式
audit-log-format=JSON

# 审计事件
audit-log-events=CONNECT,QUERY,TABLE

# 审计策略
audit-log-policy=ALL
# 可选值:ALL, LOGINS, QUERIES, NONE

审计日志分析

审计日志格式解析

JSON格式示例

json
{
  "timestamp": "2023-01-01T10:00:00Z",
  "server_id": 100,
  "command_class": "connect",
  "connection_id": 12345,
  "status": 0,
  "user": "admin",
  "host": "192.168.1.100",
  "db": "",
  "sql_text": "",
  "table_name": "",
  "table_schema": ""
}

字段说明

字段描述重要性
timestamp事件发生时间用于时间范围分析
server_id服务器ID主从环境标识
command_class命令类型事件分类依据
connection_id连接ID关联同一连接的事件
status操作结果状态码成功/失败判断
user操作用户权限审计
host客户端主机来源分析
db操作数据库范围限定
sql_text执行的SQL语句核心审计内容
table_name操作的表名表级审计
table_schema表所属数据库库级审计

审计日志分析工具

命令行工具

bash
# 查看审计日志的基本信息
wc -l /var/log/mysql/audit.log

# 查看今天的审计记录
grep "$(date +"%Y-%m-%d")" /var/log/mysql/audit.log

# 统计不同用户的操作次数
grep -o '"user": "[^"]*"' /var/log/mysql/audit.log | sort | uniq -c

# 查找特定用户的操作
grep '"user": "admin"' /var/log/mysql/audit.log

# 查找特定命令类型
grep '"command_class": "DELETE"' /var/log/mysql/audit.log

# 查找失败的登录尝试
grep -E '"command_class": "connect".*"status": [1-9]' /var/log/mysql/audit.log

# 提取所有DDL操作
grep -E '"command_class": "(CREATE|ALTER|DROP|TRUNCATE)"' /var/log/mysql/audit.log

使用jq工具分析JSON格式审计日志

bash
# 安装jq
yum install jq -y
# 或
debian install jq -y

# 查看所有DELETE操作
jq 'select(.command_class == "DELETE")' /var/log/mysql/audit.log

# 统计每种命令类型的数量
jq -s 'group_by(.command_class) | map({class: .[0].command_class, count: length})' /var/log/mysql/audit.log

# 查找影响特定表的操作
jq 'select(.table_name == "users" and .table_schema == "mydb")' /var/log/mysql/audit.log

# 查找执行时间在特定范围的操作
jq 'select(.timestamp >= "2023-01-01T10:00:00Z" and .timestamp <= "2023-01-01T11:00:00Z")' /var/log/mysql/audit.log

# 查找失败的操作
jq 'select(.status != 0)' /var/log/mysql/audit.log

专业审计分析平台

平台特点适用场景
MySQL Enterprise Monitor官方工具,集成审计分析企业版用户
Percona Monitoring and Management (PMM)开源,集成审计日志分析Percona用户
ELK Stack开源,强大的日志分析能力通用场景
Splunk企业级日志管理大型环境
Graylog开源,易于部署中小型环境

审计日志监控与告警

基于脚本的监控

bash
#!/bin/bash

# 配置信息
AUDIT_LOG="/var/log/mysql/audit.log"
ALERT_EMAIL="admin@example.com"
LOG_FILE="/var/log/mysql/audit_monitor.log"

echo "$(date +"%Y-%m-%d %H:%M:%S") - Audit log monitoring started" >> $LOG_FILE

# 检查审计日志文件是否存在
if [ ! -f $AUDIT_LOG ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") - Audit log file not found: $AUDIT_LOG" >> $LOG_FILE
    exit 1
fi

# 检测失败的登录尝试(最近24小时)
FAILED_LOGINS=$(grep -c -E '"command_class": "connect".*"status": [1-9]' $AUDIT_LOG | tail -20000)

if [ $FAILED_LOGINS -gt 5 ]; then
    # 提取失败的登录详情
    FAILURE_DETAILS=$(grep -E '"command_class": "connect".*"status": [1-9]' $AUDIT_LOG | tail -20000 | tail -10)
    
    # 发送告警邮件
    echo -e "Subject: MySQL Failed Login Alert\n\nFailed login attempts in the last 24 hours: $FAILED_LOGINS\n\nDetails:\n$FAILURE_DETAILS" | sendmail $ALERT_EMAIL
    
    echo "$(date +"%Y-%m-%d %H:%M:%S") - Sent failed login alert, count: $FAILED_LOGINS" >> $LOG_FILE
fi

# 检测敏感表的DELETE操作(最近24小时)
SENSITIVE_DELETES=$(grep -c -E '"command_class": "DELETE".*"table_name": "(users|accounts|orders)"' $AUDIT_LOG | tail -20000)

if [ $SENSITIVE_DELETES -gt 0 ]; then
    # 提取敏感删除详情
    DELETE_DETAILS=$(grep -E '"command_class": "DELETE".*"table_name": "(users|accounts|orders)"' $AUDIT_LOG | tail -20000)
    
    # 发送告警邮件
    echo -e "Subject: MySQL Sensitive Table Delete Alert\n\nSensitive table DELETE operations detected: $SENSITIVE_DELETES\n\nDetails:\n$DELETE_DETAILS" | sendmail $ALERT_EMAIL
    
    echo "$(date +"%Y-%m-%d %H:%M:%S") - Sent sensitive delete alert, count: $SENSITIVE_DELETES" >> $LOG_FILE
fi

# 检测权限变更操作(最近24小时)
PRIVILEGE_CHANGES=$(grep -c -E '"command_class": "(GRANT|REVOKE|CREATE USER|DROP USER)"' $AUDIT_LOG | tail -20000)

if [ $PRIVILEGE_CHANGES -gt 0 ]; then
    # 提取权限变更详情
    PRIVILEGE_DETAILS=$(grep -E '"command_class": "(GRANT|REVOKE|CREATE USER|DROP USER)"' $AUDIT_LOG | tail -20000)
    
    # 发送告警邮件
    echo -e "Subject: MySQL Privilege Change Alert\n\nPrivilege change operations detected: $PRIVILEGE_CHANGES\n\nDetails:\n$PRIVILEGE_DETAILS" | sendmail $ALERT_EMAIL
    
    echo "$(date +"%Y-%m-%d %H:%M:%S") - Sent privilege change alert, count: $PRIVILEGE_CHANGES" >> $LOG_FILE
fi

echo "$(date +"%Y-%m-%d %H:%M:%S") - Audit log monitoring completed" >> $LOG_FILE

集成到监控平台

Prometheus + Alertmanager

  1. 配置Prometheus监控审计日志指标

    yaml
    # prometheus.yml
    scrape_configs:
      - job_name: 'mysql_audit'
        static_configs:
          - targets: ['localhost:9104']
        metrics_path: /metrics
  2. 配置Alertmanager告警规则

    yaml
    groups:
    - name: mysql_audit_alerts
      rules:
      - alert: MySQLFailedLoginAttempts
        expr: mysql_audit_failed_logins_total > 5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High number of failed MySQL login attempts"
          description: "MySQL server {{ $labels.instance }} has seen {{ $value }} failed login attempts in the last 5 minutes."
      
      - alert: MySQLSensitiveTableDeletes
        expr: mysql_audit_sensitive_deletes_total > 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Sensitive table delete operations detected"
          description: "MySQL server {{ $labels.instance }} has seen {{ $value }} delete operations on sensitive tables."

Zabbix监控

  1. 创建监控项

    • 类型:Zabbix agent (active)
    • 键值:log[/var/log/mysql/audit.log,"command_class": "connect".*"status": [1-9],,,]
    • 数据类型:数字(无正负号)
  2. 创建触发器

    • 名称:MySQL Failed Login Attempts
    • 表达式:{mysql-server:log[/var/log/mysql/audit.log,"command_class": "connect".*"status": [1-9],,,].count(5m)} > 5
    • 严重性:警告

审计日志管理

日志轮转

使用logrotate

bash
# 创建logrotate配置文件
cat > /etc/logrotate.d/mysql-audit << 'EOF'
/var/log/mysql/audit.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 640 mysql mysql
    postrotate
        # 通知MySQL重新打开日志文件
        mysqladmin -u root -p flush-logs
    endscript
}
EOF

插件内置轮转

根据插件配置自动轮转,如:

  • audit_log_rotation_policy=size:按大小轮转
  • audit_log_rotation_policy=time:按时间轮转

日志保留策略

环境保留时间轮转频率压缩方式版本建议
生产环境90天每天gzip5.6+
开发环境7天每天不压缩5.6+
测试环境3天每天不压缩5.6+
高安全环境1年每天gzip + 归档5.6+

日志清理

bash
# 手动清理30天前的审计日志
find /var/log/mysql -name "audit.log.*" -mtime +30 -delete

# 清理超过指定大小的旧日志
ls -lh /var/log/mysql/audit.log.* | awk '$5 > "100M" {print $9}' | xargs rm -f

# 自动化清理脚本
#!/bin/bash

LOG_DIR="/var/log/mysql"
RETENTION_DAYS=30

# 清理旧的审计日志
find $LOG_DIR -name "audit.log.*" -mtime +$RETENTION_DAYS -delete

# 记录清理操作
echo "$(date +"%Y-%m-%d %H:%M:%S") - Cleaned up audit logs older than $RETENTION_DAYS days" >> $LOG_DIR/audit_cleanup.log

审计日志最佳实践

配置最佳实践

  1. 合理选择审计事件类型

    • 生产环境:只审计必要的事件类型(如CONNECT、DDL、DCL、敏感表操作)
    • 避免审计所有事件,减少性能影响
    • 根据合规要求调整审计范围
  2. 使用过滤规则

    • 排除系统用户和频繁访问的应用用户
    • 只审计关键数据库和表
    • 针对不同用户设置不同的审计规则
  3. 选择合适的日志格式

    • JSON格式便于自动化分析和处理
    • 生产环境推荐JSON格式
    • 开发环境可使用CSV格式便于直接查看
  4. 设置合理的日志大小和保留时间

    • 平衡磁盘空间和审计需求
    • 定期归档和清理旧日志
    • 根据合规要求调整保留期限
  5. 启用插件永久化

    ini
    [mysqld]
    # 确保插件无法被动态卸载
    audit-log=FORCE_PLUS_PERMANENT

性能优化

优化项具体措施预期效果版本要求
减少审计事件只审计必要事件降低CPU和I/O开销5.6+
使用过滤规则排除不必要的用户和操作减少日志量5.7+
选择合适的存储使用SSD存储审计日志提高写入性能5.6+
合理设置轮转避免单文件过大提高查询性能5.6+
异步写入配置插件异步写入日志减少对主业务的影响5.7+
批量写入配置插件批量写入日志降低I/O频率8.0+

安全最佳实践

  1. 保护审计日志文件

    bash
    # 设置正确的权限
    chown mysql:mysql /var/log/mysql/audit.log
    chmod 640 /var/log/mysql/audit.log
    
    # 限制访问权限
    setfacl -m u:auditor:r /var/log/mysql/audit.log
  2. 加密传输和存储

    • 对审计日志进行加密存储(MySQL 8.0+支持内置加密)
    • 使用SSL/TLS加密审计日志的传输
    • 定期轮换加密密钥
  3. 定期备份审计日志

    bash
    # 自动化备份脚本
    #!/bin/bash
    
    BACKUP_DIR="/backup/mysql/audit/$(date +%Y%m%d)"
    mkdir -p $BACKUP_DIR
    
    # 备份审计日志
    cp /var/log/mysql/audit.log.* $BACKUP_DIR/
    
    # 压缩备份
    tar -zcvf $BACKUP_DIR.tar.gz $BACKUP_DIR
    
    # 复制到远程服务器
    scp $BACKUP_DIR.tar.gz backup@remote-server:/backup/mysql/audit/
    
    # 清理本地临时文件
    rm -rf $BACKUP_DIR
  4. 限制审计日志的访问

    • 只有授权的审计人员可以访问
    • 定期审查访问权限
    • 记录审计日志的访问情况
  5. 完整性验证

    • 定期验证审计日志的完整性
    • 使用哈希算法确保日志未被篡改
    bash
    # 生成审计日志哈希值
    sha256sum /var/log/mysql/audit.log > /var/log/mysql/audit.log.sha256

审计日志案例分析

案例一:未授权访问检测

问题现象:审计日志中出现大量来自未知IP的登录尝试

审计日志分析

json
{
  "timestamp": "2023-01-01T10:00:00Z",
  "command_class": "connect",
  "user": "root",
  "host": "10.0.0.1",
  "status": 1045
}

处理流程

  1. 立即封禁该IP:iptables -A INPUT -s 10.0.0.1 -j DROP
  2. 检查是否有成功登录记录
  3. 重置root密码:ALTER USER 'root'@'%' IDENTIFIED BY 'new_strong_password';
  4. 启用IP白名单:bind-address = 192.168.1.0/24
  5. 配置更严格的登录失败限制

案例二:误操作追踪

问题现象:数据库中的重要表被意外删除

审计日志分析

json
{
  "timestamp": "2023-01-01T14:30:00Z",
  "command_class": "drop_table",
  "user": "admin",
  "host": "192.168.1.100",
  "db": "mydb",
  "sql_text": "DROP TABLE important_table;",
  "status": 0
}

处理流程

  1. 从备份恢复表结构和数据
  2. 对admin用户进行权限审查
  3. 实施更严格的操作审批流程
  4. 配置敏感操作告警
  5. 定期演练误操作恢复

案例三:权限滥用检测

问题现象:普通用户执行了只有管理员才能执行的操作

审计日志分析

json
{
  "timestamp": "2023-01-01T16:45:00Z",
  "command_class": "grant",
  "user": "app_user",
  "host": "192.168.2.200",
  "sql_text": "GRANT ALL PRIVILEGES ON *.* TO 'hacker'@'%';",
  "status": 0
}

处理流程

  1. 立即撤销非法授予的权限:REVOKE ALL PRIVILEGES ON *.* FROM 'hacker'@'%';
  2. 检查app_user的权限:SHOW GRANTS FOR 'app_user'@'%';
  3. 收回不必要的权限:REVOKE ALL PRIVILEGES ON *.* FROM 'app_user'@'%'; GRANT SELECT, INSERT, UPDATE ON mydb.* TO 'app_user'@'%';
  4. 审计所有用户权限
  5. 配置权限变更告警

审计日志与其他日志的协同

与错误日志协同

  • 审计日志记录"who did what"
  • 错误日志记录"what went wrong"
  • 结合分析可以完整还原事件场景

与慢查询日志协同

  • 慢查询日志记录性能问题
  • 审计日志记录执行慢查询的用户和上下文
  • 结合分析可以找出性能问题的责任人

与二进制日志协同

  • 二进制日志用于数据恢复
  • 审计日志用于操作审计
  • 结合使用可以实现完整的"操作审计+数据恢复"方案

总结

审计日志是MySQL安全运维的重要组成部分,通过合理配置和分析审计日志,可以:

  1. 提高数据库安全性:及时发现和阻止未授权访问
  2. 满足合规要求:提供完整的审计轨迹
  3. 快速定位问题:追踪导致数据库问题的操作
  4. 优化权限管理:验证用户权限使用是否合规
  5. 改进操作流程:基于审计结果优化操作流程

作为DBA,应该根据业务需求和合规要求,选择合适的审计方案,建立完善的审计日志管理和分析机制,确保MySQL数据库的安全可靠运行。