Ubuntu 22.04 MySQL 稽核日誌設定

Ubuntu 22.04 MySQL Audit Log Configuration

MySQL 稽核功能概述

在現代企業環境中,資料庫稽核是資訊安全的重要環節。MySQL 稽核日誌可以記錄所有資料庫操作,包括登入嘗試、查詢執行、資料修改等活動。這些日誌對於安全事件調查、合規性審計以及效能分析都具有重要價值。

為什麼需要 MySQL 稽核

  • 安全性:偵測未授權存取和可疑活動
  • 合規性:滿足 PCI DSS、HIPAA、SOX 等法規要求
  • 問題排除:追蹤資料庫問題的根本原因
  • 效能監控:分析查詢模式和效能瓶頸
  • 責任歸屬:確認誰在何時做了什麼操作

Ubuntu 22.04 環境準備

首先確認 MySQL 版本和系統環境:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 檢查 Ubuntu 版本
lsb_release -a

# 檢查 MySQL 版本
mysql --version

# 安裝 MySQL(如尚未安裝)
sudo apt update
sudo apt install mysql-server -y

# 啟動並設定開機自動啟動
sudo systemctl start mysql
sudo systemctl enable mysql

Enterprise Audit Plugin

MySQL Enterprise Audit 是 Oracle 官方提供的商業版稽核解決方案,僅在 MySQL Enterprise Edition 中可用。

Enterprise Audit 特點

  • 完整的稽核功能:支援所有 SQL 操作的稽核
  • XML 和 JSON 格式:靈活的日誌輸出格式
  • 效能優化:經過 Oracle 優化的實作
  • 官方支援:享有 Oracle 技術支援

安裝 Enterprise Audit Plugin

如果您擁有 MySQL Enterprise Edition 授權:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 登入 MySQL
mysql -u root -p

# 安裝稽核 Plugin
INSTALL PLUGIN audit_log SONAME 'audit_log.so';

# 確認安裝成功
SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME LIKE 'audit%';

基本設定

/etc/mysql/mysql.conf.d/mysqld.cnf 中加入設定:

1
2
3
4
5
6
7
[mysqld]
# 啟用稽核日誌
audit_log_format = JSON
audit_log_file = /var/log/mysql/audit.log
audit_log_policy = ALL
audit_log_rotate_on_size = 104857600
audit_log_rotations = 7

重新啟動 MySQL 使設定生效:

1
sudo systemctl restart mysql

開源替代方案:MariaDB Audit Plugin

對於使用 MySQL Community Edition 的用戶,MariaDB Audit Plugin 是一個優秀的開源替代方案。此 Plugin 與 MySQL Community Edition 相容,提供完整的稽核功能。

安裝 MariaDB Audit Plugin

1
2
3
4
5
6
7
8
9
# 安裝必要的開發工具
sudo apt install build-essential cmake libssl-dev -y

# 下載 MariaDB Audit Plugin 原始碼
cd /tmp
git clone https://github.com/MariaDB/server.git --depth 1 --branch 10.11

# 或者直接使用預編譯的 Plugin(推薦)
# 從 MariaDB 官網下載對應版本

使用 Percona Audit Log Plugin(推薦替代方案)

Percona 提供了一個與 MySQL Community Edition 完全相容的稽核 Plugin:

1
2
3
4
5
6
7
# 安裝 Percona 套件庫
wget https://repo.percona.com/apt/percona-release_latest.generic_all.deb
sudo dpkg -i percona-release_latest.generic_all.deb
sudo apt update

# 安裝 Percona Audit Log Plugin
sudo apt install percona-audit-log-plugin -y

啟用 Percona Audit Log Plugin

1
2
3
4
5
6
7
8
-- 登入 MySQL
mysql -u root -p

-- 安裝 Plugin
INSTALL PLUGIN audit_log SONAME 'audit_log.so';

-- 驗證安裝
SHOW PLUGINS;

McAfee MySQL Audit Plugin(開源選項)

另一個熱門的開源選擇是 McAfee MySQL Audit Plugin:

1
2
3
4
5
6
7
# 下載 McAfee Audit Plugin
cd /tmp
git clone https://github.com/mcafee/mysql-audit.git
cd mysql-audit

# 編譯安裝(需要對應 MySQL 版本的原始碼)
# 請參考官方文件進行編譯

設定 McAfee Audit Plugin:

1
2
3
4
5
6
-- 安裝 Plugin
INSTALL PLUGIN AUDIT SONAME 'libaudit_plugin.so';

-- 設定稽核規則
SET GLOBAL audit_json_file = ON;
SET GLOBAL audit_json_log_file = '/var/log/mysql/mysql-audit.json';

稽核事件類型與過濾

事件類型分類

MySQL 稽核可以捕獲以下類型的事件:

事件類型說明範例
CONNECT連線相關事件登入、登出、連線失敗
QUERYSQL 查詢事件SELECT、INSERT、UPDATE、DELETE
TABLE資料表存取事件資料表讀取、寫入
QUERY_DDL資料定義語言CREATE、ALTER、DROP
QUERY_DML資料操作語言INSERT、UPDATE、DELETE
QUERY_DCL資料控制語言GRANT、REVOKE

設定事件過濾

在 MySQL 設定檔中配置過濾規則:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[mysqld]
# 僅記錄特定事件類型
audit_log_policy = LOGINS
# 可選值:ALL, LOGINS, QUERIES, NONE

# 排除特定使用者
audit_log_exclude_accounts = 'monitoring@localhost,backup@localhost'

# 包含特定使用者
audit_log_include_accounts = 'admin@%,app_user@%'

使用過濾函數(MySQL 8.0+)

MySQL 8.0 引入了更靈活的過濾機制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
-- 建立過濾規則
SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }');

-- 建立僅記錄 DML 操作的過濾器
SELECT audit_log_filter_set_filter('log_dml_only', '{
  "filter": {
    "class": [
      { "name": "table_access" }
    ]
  }
}');

-- 將過濾器指派給使用者
SELECT audit_log_filter_set_user('%', 'log_all');
SELECT audit_log_filter_set_user('app_user@%', 'log_dml_only');

-- 移除使用者的過濾器
SELECT audit_log_filter_remove_user('app_user@%');

進階過濾範例

建立複雜的過濾規則:

 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
26
27
28
29
30
31
32
33
34
35
-- 記錄所有失敗的登入嘗試
SELECT audit_log_filter_set_filter('failed_logins', '{
  "filter": {
    "class": [
      {
        "name": "connection",
        "event": [
          {
            "name": "connect",
            "log": {
              "field": { "name": "status", "value": { "not": 0 } }
            }
          }
        ]
      }
    ]
  }
}');

-- 記錄對敏感資料表的所有存取
SELECT audit_log_filter_set_filter('sensitive_tables', '{
  "filter": {
    "class": [
      {
        "name": "table_access",
        "log": {
          "field": {
            "name": "table_name.str",
            "value": ["customers", "credit_cards", "passwords"]
          }
        }
      }
    ]
  }
}');

日誌格式與儲存

JSON 格式日誌

JSON 格式是現代化的日誌格式,便於機器解析:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "timestamp": "2025-09-04T10:30:45.123456Z",
  "id": 1,
  "class": "connection",
  "event": "connect",
  "connection_id": 12345,
  "account": {
    "user": "app_user",
    "host": "192.168.1.100"
  },
  "login": {
    "user": "app_user",
    "os": "",
    "ip": "192.168.1.100",
    "proxy": ""
  },
  "connection_data": {
    "connection_type": "ssl",
    "status": 0,
    "db": "production_db"
  }
}

查詢事件的 JSON 格式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "timestamp": "2025-09-04T10:31:22.654321Z",
  "id": 2,
  "class": "general",
  "event": "query",
  "connection_id": 12345,
  "account": {
    "user": "app_user",
    "host": "192.168.1.100"
  },
  "query_data": {
    "query": "SELECT * FROM customers WHERE id = 123",
    "status": 0,
    "sql_command": "select"
  }
}

XML 格式日誌

傳統的 XML 格式仍被許多 SIEM 系統支援:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<AUDIT_RECORD>
  <TIMESTAMP>2025-09-04T10:30:45.123456Z</TIMESTAMP>
  <RECORD_ID>1</RECORD_ID>
  <NAME>Connect</NAME>
  <CONNECTION_ID>12345</CONNECTION_ID>
  <STATUS>0</STATUS>
  <USER>app_user</USER>
  <HOST>192.168.1.100</HOST>
  <OS_USER></OS_USER>
  <IP>192.168.1.100</IP>
  <DB>production_db</DB>
</AUDIT_RECORD>

日誌輪替設定

設定自動日誌輪替以管理磁碟空間:

1
2
3
4
5
6
7
8
9
[mysqld]
# 當日誌達到 100MB 時輪替
audit_log_rotate_on_size = 104857600

# 保留 7 個輪替檔案
audit_log_rotations = 7

# 日誌檔案路徑
audit_log_file = /var/log/mysql/audit.log

使用 logrotate 進行更細緻的控制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 建立 logrotate 設定檔
sudo tee /etc/logrotate.d/mysql-audit << 'EOF'
/var/log/mysql/audit.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 640 mysql adm
    postrotate
        mysqladmin flush-logs
    endscript
}
EOF

日誌儲存最佳實踐

1
2
3
4
5
6
7
# 建立專用的日誌目錄
sudo mkdir -p /var/log/mysql/audit
sudo chown mysql:adm /var/log/mysql/audit
sudo chmod 750 /var/log/mysql/audit

# 設定適當的權限
sudo chmod 640 /var/log/mysql/audit/*.log

效能影響與優化

效能影響評估

啟用稽核日誌會對資料庫效能產生一定影響。以下是主要考量因素:

因素影響程度說明
日誌量記錄的事件越多,I/O 負擔越大
日誌格式JSON 比 XML 略慢但更緊湊
同步寫入同步寫入確保日誌完整但影響效能
過濾規則複雜過濾規則輕微增加 CPU 使用

效能優化策略

1. 使用非同步日誌寫入

1
2
3
4
5
6
[mysqld]
# 使用非同步寫入模式
audit_log_strategy = ASYNCHRONOUS

# 設定緩衝區大小
audit_log_buffer_size = 4194304

2. 實施智慧過濾

只記錄必要的事件:

1
2
3
4
5
6
7
8
9
-- 僅記錄 DDL 和登入失敗
SELECT audit_log_filter_set_filter('minimal', '{
  "filter": {
    "class": [
      { "name": "connection", "event": [{ "name": "connect", "log": { "field": { "name": "status", "value": { "not": 0 } } } }] },
      { "name": "general", "event": [{ "name": "status", "log": { "field": { "name": "sql_command", "value": ["create", "alter", "drop", "grant", "revoke"] } } }] }
    ]
  }
}');

3. 使用獨立的日誌磁碟

1
2
3
4
# 將稽核日誌移至獨立磁碟
sudo mkdir -p /mnt/audit_logs/mysql
sudo mount /dev/sdb1 /mnt/audit_logs
sudo chown mysql:mysql /mnt/audit_logs/mysql

更新 MySQL 設定:

1
2
[mysqld]
audit_log_file = /mnt/audit_logs/mysql/audit.log

4. 效能監控腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/bash
# mysql_audit_monitor.sh - 監控稽核日誌效能影響

# 檢查稽核日誌大小
AUDIT_SIZE=$(du -sh /var/log/mysql/audit.log 2>/dev/null | awk '{print $1}')
echo "稽核日誌大小: $AUDIT_SIZE"

# 檢查日誌寫入速率
CURRENT_SIZE=$(stat -c %s /var/log/mysql/audit.log 2>/dev/null)
sleep 60
NEW_SIZE=$(stat -c %s /var/log/mysql/audit.log 2>/dev/null)
RATE=$(( (NEW_SIZE - CURRENT_SIZE) / 60 ))
echo "日誌寫入速率: ${RATE} bytes/sec"

# 檢查 MySQL 效能指標
mysql -u root -e "SHOW GLOBAL STATUS LIKE 'Audit%';" 2>/dev/null

基準測試

執行效能基準測試以評估稽核對系統的影響:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 使用 sysbench 進行基準測試
sysbench oltp_read_write \
  --mysql-host=localhost \
  --mysql-user=test \
  --mysql-password=test \
  --mysql-db=test \
  --tables=10 \
  --table-size=100000 \
  --threads=4 \
  --time=300 \
  run

與 SIEM 整合

Elasticsearch + Kibana 整合

使用 Filebeat 將稽核日誌送至 Elasticsearch:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/mysql/audit.log
  json.keys_under_root: true
  json.add_error_key: true
  fields:
    log_type: mysql_audit
  fields_under_root: true

output.elasticsearch:
  hosts: ["elasticsearch:9200"]
  index: "mysql-audit-%{+yyyy.MM.dd}"

setup.kibana:
  host: "kibana:5601"

安裝並啟動 Filebeat:

1
2
3
4
5
6
7
8
9
# 安裝 Filebeat
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update
sudo apt install filebeat -y

# 啟動 Filebeat
sudo systemctl enable filebeat
sudo systemctl start filebeat

Splunk 整合

建立 Splunk 輸入設定:

1
2
3
4
5
# /opt/splunkforwarder/etc/apps/mysql_audit/local/inputs.conf
[monitor:///var/log/mysql/audit.log]
disabled = false
sourcetype = mysql:audit:json
index = security

建立欄位抽取設定:

1
2
3
4
5
6
7
8
# /opt/splunkforwarder/etc/apps/mysql_audit/local/props.conf
[mysql:audit:json]
SHOULD_LINEMERGE = false
LINE_BREAKER = ([\r\n]+)
KV_MODE = json
TIME_FORMAT = %Y-%m-%dT%H:%M:%S.%6N%Z
TIME_PREFIX = "timestamp":"
MAX_TIMESTAMP_LOOKAHEAD = 32

Graylog 整合

設定 Graylog 接收 MySQL 稽核日誌:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 使用 rsyslog 轉發日誌
sudo tee /etc/rsyslog.d/50-mysql-audit.conf << 'EOF'
module(load="imfile")
input(type="imfile"
      File="/var/log/mysql/audit.log"
      Tag="mysql-audit"
      Severity="info"
      Facility="local0")

local0.* @graylog.example.com:1514
EOF

sudo systemctl restart rsyslog

警報規則設定

在 SIEM 中設定重要的警報規則:

 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
26
27
28
29
30
31
32
33
34
35
36
37
38
# 範例:Elasticsearch Watcher 警報
{
  "trigger": {
    "schedule": { "interval": "5m" }
  },
  "input": {
    "search": {
      "request": {
        "indices": ["mysql-audit-*"],
        "body": {
          "query": {
            "bool": {
              "must": [
                { "match": { "event": "connect" } },
                { "range": { "connection_data.status": { "gt": 0 } } }
              ],
              "filter": {
                "range": { "@timestamp": { "gte": "now-5m" } }
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": { "ctx.payload.hits.total.value": { "gt": 10 } }
  },
  "actions": {
    "email_admin": {
      "email": {
        "to": "security@example.com",
        "subject": "MySQL 登入失敗警報",
        "body": "偵測到 {{ctx.payload.hits.total.value}} 次登入失敗"
      }
    }
  }
}

合規性需求對應

PCI DSS 合規

PCI DSS(支付卡產業資料安全標準)要求追蹤所有資料存取:

要求稽核設定說明
10.2.1CONNECT 事件記錄所有使用者存取
10.2.2管理員操作記錄 root 使用者所有操作
10.2.4無效存取嘗試記錄登入失敗事件
10.2.5權限變更記錄 GRANT、REVOKE 操作
10.2.6稽核日誌操作保護日誌完整性

PCI DSS 合規設定範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
-- 建立 PCI DSS 合規過濾器
SELECT audit_log_filter_set_filter('pci_dss', '{
  "filter": {
    "class": [
      { "name": "connection" },
      { "name": "general", "event": [
        { "name": "status", "log": {
          "field": { "name": "sql_command", "value": ["grant", "revoke", "create", "alter", "drop"] }
        }}
      ]},
      { "name": "table_access", "log": {
        "field": { "name": "table_database.str", "value": ["cardholder_data"] }
      }}
    ]
  }
}');

-- 套用至所有使用者
SELECT audit_log_filter_set_user('%', 'pci_dss');

HIPAA 合規

HIPAA(健康保險可攜性與責任法案)要求保護醫療資訊:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
-- 建立 HIPAA 合規過濾器
SELECT audit_log_filter_set_filter('hipaa', '{
  "filter": {
    "class": [
      { "name": "connection" },
      { "name": "table_access", "log": {
        "field": { "name": "table_name.str", "value": ["patients", "medical_records", "prescriptions", "diagnoses"] }
      }},
      { "name": "general", "event": [
        { "name": "status", "log": {
          "field": { "name": "sql_command", "value": ["update", "delete", "insert"] }
        }}
      ]}
    ]
  }
}');

SOX 合規

沙賓法案(Sarbanes-Oxley)要求財務資料完整性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
-- 建立 SOX 合規過濾器
SELECT audit_log_filter_set_filter('sox', '{
  "filter": {
    "class": [
      { "name": "connection" },
      { "name": "table_access", "log": {
        "field": { "name": "table_database.str", "value": ["financial_db", "accounting_db"] }
      }},
      { "name": "general", "event": [
        { "name": "status", "log": true }
      ]}
    ]
  }
}');

GDPR 合規

一般資料保護規則要求追蹤個人資料存取:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
-- 建立 GDPR 合規過濾器
SELECT audit_log_filter_set_filter('gdpr', '{
  "filter": {
    "class": [
      { "name": "connection" },
      { "name": "table_access", "log": {
        "field": { "name": "table_name.str", "value": ["users", "personal_data", "customer_info", "contact_details"] }
      }},
      { "name": "general", "event": [
        { "name": "status", "log": {
          "field": { "name": "sql_command", "value": ["select", "update", "delete", "insert"] }
        }}
      ]}
    ]
  }
}');

合規性報告自動化

建立自動化報告腳本:

 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
26
27
28
29
30
31
32
#!/bin/bash
# compliance_report.sh - 產生合規性報告

REPORT_DATE=$(date +%Y-%m-%d)
REPORT_DIR="/var/reports/mysql-audit"
mkdir -p "$REPORT_DIR"

# 產生每日摘要報告
mysql -u audit_reader -p"${AUDIT_PASSWORD}" << EOF > "$REPORT_DIR/daily_summary_${REPORT_DATE}.txt"
-- 登入統計
SELECT
    DATE(timestamp) as date,
    COUNT(*) as total_connections,
    SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) as successful,
    SUM(CASE WHEN status != 0 THEN 1 ELSE 0 END) as failed
FROM mysql.audit_log
WHERE DATE(timestamp) = CURDATE() - INTERVAL 1 DAY
GROUP BY DATE(timestamp);

-- 高風險操作
SELECT
    user,
    sql_command,
    COUNT(*) as operation_count
FROM mysql.audit_log
WHERE DATE(timestamp) = CURDATE() - INTERVAL 1 DAY
  AND sql_command IN ('drop', 'truncate', 'grant', 'revoke')
GROUP BY user, sql_command;
EOF

# 發送報告
mail -s "MySQL 稽核日報 - ${REPORT_DATE}" security@example.com < "$REPORT_DIR/daily_summary_${REPORT_DATE}.txt"

結論

MySQL 稽核日誌是確保資料庫安全性和滿足合規性要求的關鍵工具。在 Ubuntu 22.04 環境中,您可以選擇:

  1. MySQL Enterprise Audit:適合有商業授權需求的企業
  2. Percona Audit Log Plugin:優秀的開源替代方案
  3. McAfee MySQL Audit Plugin:另一個可靠的開源選擇

無論選擇哪種方案,都應該:

  • 根據合規需求設定適當的事件過濾
  • 實施效能優化策略以降低對生產系統的影響
  • 與 SIEM 系統整合以實現集中化監控和警報
  • 定期審查稽核日誌和產生合規性報告

透過正確設定 MySQL 稽核日誌,您可以有效保護敏感資料、偵測安全威脅,並滿足各種法規合規要求。

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy