---
title: TiDB 审计插件
summary: 了解如何部署和使用 TiDB 审计插件。
---

# TiDB 审计插件

TiDB 审计插件 (TiDB Audit Plugin) 记录 TiDB 服务器上的活动，这些活动应遵守企业的审计规范。对于每个用户 session，该插件记录用户访问服务器的信息（即用户名和 IP 地址）、执行的 SQL 查询、访问的数据库和表、环境变量变更、执行的 DDL 操作等信息。审计信息记录在一个日志文件中以备将来使用。

本文介绍了如何部署和使用 TiDB 审计插件。

## 获取插件

请联系 PingCAP 销售获取插件安装包文件。

## 部署审计插件

你可以使用 TiDB Operator 或者 TiUP 来部署审计插件。

### 使用 TiDB Operator 部署审计插件

配置 TidbCluster CR。

```yaml

  tidb:
    additionalContainers:
    - command:
      - sh
      - -c
      - touch /var/log/tidb/tidb-audit.log; tail -n0 -F /var/log/tidb/tidb-audit.log;
      image: busybox:1.26.2
      imagePullPolicy: IfNotPresent
      name: auditlog
      resources:
        limits:
          cpu: 100m
          memory: 50Mi
        requests:
          cpu: 20m
          memory: 5Mi
      terminationMessagePath: /dev/termination-log
      terminationMessagePolicy: File
      volumeMounts:
      - mountPath: /var/log/tidb
        name: slowlog
    baseImage: &lt;your_private_docker_hub_username>/tidb-ent:v5.4.0
    plugins:
    - audit-1
```

### 使用 TiUP 部署审计插件

本节介绍了几种使用 TiUP 部署审计插件的场景：

* 在已部署集群上追加插件
* 安装时部署
* 扩容
* 升级集群

#### 在已部署集群上追加插件

1. 在所有目标服务器上建立文件夹。

    ```shell
    tiup cluster exec cluster_name --command "mkdir {{.DeployDir}}/plugin" -R tidb
    ```

2. 传输插件到所有目标服务器。

    ```shell
    tiup cluster push cluster_name ~/Download/audit-1.so {{.DeployDir}}/plugin/audit-1.so -R tidb
    ```

3. 修改 TiDB 配置。

    ```shell
    tiup cluster edit-config cluster_name
    ```

    在每个 TiDB 节点下的 config 字段中，配置 plugin.dir 为对应的**绝对路径**，plugin.load 为插件名。

    ```yaml
    tidb_servers:
    -  host: 172.16.7.213
       ssh_port: 22
       port: 4000
       status_port: 10080
       deploy_dir: /tidb-deploy/tidb-4000
       log_dir: /tidb-deploy/tidb-4000/log
       arch: amd64
       os: linux
       config:
         plugin.dir: /tidb-deploy/tidb-4000/plugin
         plugin.load: audit-1
    ```

4. 滚动重启所有 TiDB 节点。

    ```shell
    tiup cluster reload cluster_name -R tidb
    ```

建议：

* 在步骤 3 中，如果所有节点部署路径完全相同，可直接在 server_configs.tidb 中进行全局配置，避免手动修改每一个节点。如果路径不完全相同，可以修改步骤 1、2 中 plugin 的路径为某一相同路径。
* 如果不是所有 TiDB 节点都要部署插件，则通过 -N 参数来指定节点（tiup cluster display 显示的 ID）。

#### 安装时部署

安装时部署与“在已部署集群上追加插件”的操作步骤相似：在部署前的拓扑文件中配置好 plugin.load 和 plugin.dir，在启动集群前执行 `tiup cluster exec` 和 `tiup cluster push`。

#### 扩容

按照常规操作正常扩容节点，然后参考“在已部署集群上追加插件”的操作步骤，通过 -N 参数指定刚扩容的节点。

请注意，你需要在扩容进行期间将插件安装文件（如上面例子中的 audit-1.so）上传到目标服务器，而且要确保在扩容结束之前传完，否则扩容会报错。

如果扩容报错，你可以执行以下操作重新安装插件：

1. 重新进行扩容。
2. 在扩容完成后上传插件安装文件。
3. 执行 tiup cluster start cluster_name 命令重启。

#### 升级集群

1. 删除老插件。

    ```shell
    tiup cluster exec cluster_name --command "rm {{.DeployDir}}/plugin/audit-1.so" -R tidb
    ```

2. 传输新插件到所有目标服务器。为了避免修改配置，使用相同名称。

    ```shell
    tiup cluster push cluster_name ~/Download/audit-1_new.so {{.DeployDir}}/plugin/audit-1.so -R tidb
    ```

    **说明：**域名不能包含 “-” （如 tidb-server1），否则该命令会执行失败。

3. 升级集群。

    ```shell
    tiup cluster upgrade cluster_name version
    ```

### 插件的 Events

TiDB 审计插件有以下几种 Events。

#### CONNECTION: Connection events and authentication events.

CONNECTION logs 示例：

* A successful authentication

    [2022/04/18 21:50:29.669 +08:00] [INFO] [logger.go:70] [ID=16502898290] [TIMESTAMP=2022/04/18 21:50:29.669 +08:00] [EVENT_CLASS=**CONNECTION**] [EVENT_SUBCLASS=Disconnect] [STATUS_CODE=0] [COST_TIME=0] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[]"] [TABLES="[]"] [SQL_TEXT=] [ROWS=0] [CLIENT_PORT=39290] [CONNECTION_ID=11] [CONNECTION_TYPE=Socket] [SERVER_ID=1] [SERVER_PORT=4000] [DURATION=4522.55501] [SERVER_OS_LOGIN_USER=] [OS_VERSION="Centos 6"] [CLIENT_VERSION=] [SERVER_VERSION=v5.2.0] [AUDIT_VERSION=] [SSL_VERSION=v1.2.0] [PID=32638] [Reason=]

* A failed authentication

    [2022/04/18 21:50:40.198 +08:00] [INFO] [logger.go:70] [ID=16502898400] [TIMESTAMP=2022/04/18 21:50:40.198 +08:00] [EVENT_CLASS=**CONNECTION**] [EVENT_SUBCLASS=Reject] [STATUS_CODE=0] [COST_TIME=0] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=ccd] [DATABASES="[]"] [TABLES="[]"] [SQL_TEXT=] [ROWS=0] [CLIENT_PORT=39296] [CONNECTION_ID=15] [CONNECTION_TYPE=Socket] [SERVER_ID=1] [SERVER_PORT=4000] [DURATION=0] [SERVER_OS_LOGIN_USER=] [OS_VERSION=”Centos 6"] [CLIENT_VERSION=] [SERVER_VERSION=v5.2.0] [AUDIT_VERSION=] [SSL_VERSION=v1.2.0] [PID=32638] [Reason="[server:1045]Access denied for user 'ccd'@'127.0.0.1' (using password: NO)"]

#### TABLE_ACCESS: SQL queries related to tables.

TABLE_ACCESS logs 示例：

* Queries on a table (`select * from t`)

    [2022/04/18 22:00:47.085 +08:00] [INFO] [logger.go:70] [ID=16502904470] [TIMESTAMP=2022/04/18 22:00:47.085 +08:00] [EVENT_CLASS=**TABLE_ACCESS**] [EVENT_SUBCLASS=Select] [STATUS_CODE=0] [COST_TIME=0] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[test]"] [TABLES="[t]"] [SQL_TEXT="select * from `t`"] [ROWS=0] [CONNECTION_ID=19] [CLIENT_PORT=39522] [PID=32638] [COMMAND=Query] [SQL_STATEMENTS=Select]

* Drop a table (`drop table t`)

    [2022/04/18 22:02:40.775 +08:00] [INFO] [logger.go:70] [ID=16502905600] [TIMESTAMP=2022/04/18 22:02:40.775 +08:00] [EVENT_CLASS=**TABLE_ACCESS**] [EVENT_SUBCLASS=DropTable] [STATUS_CODE=0] [COST_TIME=0] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[test]"] [TABLES="[t,t1]"] [SQL_TEXT="drop table `t` , `t1`"] [ROWS=0] [CONNECTION_ID=19] [CLIENT_PORT=39522] [PID=32638] [COMMAND=Query] [SQL_STATEMENTS=DropTable]

> **注意：**
>
> * 默认情况下，TABLE_ACCESS events 不会被记录在日志中。请参考本文档中 “修改 TABLE_ACCESS 相关配置”了解如何配置。
> * 失败的 statements **不会**被记录到日志中。

#### GENERAL: SQL queries that don’t access tables.

GENERAL logs 示例：

* `show tables` statement:

    [2022/04/18 22:10:34.845 +08:00] [INFO] [logger.go:70] [ID=16502910340] [TIMESTAMP=2022/04/18 22:10:34.845 +08:00] [EVENT_CLASS=**GENERAL**] [EVENT_SUBCLASS=] [STATUS_CODE=0] [COST_TIME=0] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[]"] [TABLES="[]"] [SQL_TEXT="show tables"] [ROWS=0] [CONNECTION_ID=19] [CLIENT_PORT=39522] [PID=32638] [COMMAND=Query] [SQL_STATEMENTS=Show]

* `begin` statement:

    [2022/04/18 22:06:53.198 +08:00] [INFO] [logger.go:70] [ID=16502908130] [TIMESTAMP=2022/04/18 22:06:53.198 +08:00] [EVENT_CLASS=**GENERAL**] [EVENT_SUBCLASS=] [STATUS_CODE=0] [COST_TIME=0] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[]"] [TABLES="[]"] [SQL_TEXT=begin] [ROWS=0] [CONNECTION_ID=19] [CLIENT_PORT=39522] [PID=32638] [COMMAND=Query] [SQL_STATEMENTS=Begin]

## 查看状态

通过 MySQL 的 `show plugins` 命令可以查看当前插件加载和启用状态信息：

* Name：插件名称
* Status：插件状态，由加载状态 (uninitialized, ready) 和启用状态 (enable, disable) 组成
* Type：插件类型
* Library：插件二进制文件位置
* Version：插件版本

![Show Plugins](media/plugin-audit-show.png)

## 启用和禁用插件

审计插件加载后，默认会对 CONNECTION 和 GENERAL 事件进行审计。启用或禁用命令在任意一个 TiDB 节点执行成功后，会作用于集群中所有 TiDB 节点。

执行以下命令启用审计插件：

```shell
mysql> admin plugins enable audit;
```

如果不想对这两种事件做审计，执行如下命令禁用审计插件：

```shell
mysql> admin plugins disable audit;
```

![Disable Plugins](media/plugin-audit-disable.png)

## 修改 TABLE_ACCESS 相关配置

对于 TABLE_ACCESS 事件，默认不会进行审计。如需使用，需要进行相关配置。

TABLE_ACCESS 支持通过用户名 + 数据库 + 表名 + 语句类型这 4 个维度的组合对审计进行细粒度控制。修改配置需要运行 flush，使其在所有 TiDB 节点生效。

### 修改配置表 tidb_audit_table_access

在首次使用审计插件时，会在 TiDB 的 MySQL 库中创建一个名为 tidb_audit_table_access 的插件配置表。你可以通过修改配置表来控制审计插件对 table_access 的审计。

```shell
mysql> show create table mysql.tidb_audit_table_access;
CREATE TABLE `tidb_audit_table_access` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(32) NOT NULL COMMENT 'username need be audit(regex)',
  `db` varchar(32) NOT NULL COMMENT 'db name need be audit(regex)',
  `tbl` varchar(32) NOT NULL COMMENT 'table name need be audit(regex)',
  `access_type` varchar(128) NOT NULL COMMENT 'table access types split by comma',
  `create_time` timestamp NULL DEFAULT NULL COMMENT 'record create time',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'record last update time',
  PRIMARY KEY (`id`),
  UNIQUE KEY `user` (`user`,`db`,`tbl`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
```

相关参数解释如下：

* user：开启 table_access 事件审计的用户。
* db：开启 table_access 事件审计的数据库。
* tbl：开启 table_access 事件审计的表名。
* access_type：开启 table_access 事件审计语句类型，类型同上面提到的 subClass，支持多个逗号分割，空字符串则代表所有都审计。

**注意**：user、db、tbl 使用正则且区分大小写，**.*** 代表 table-access 对所有 user、db 或 tbl 都开启。

例如，如果希望对任意用户访问任意库和表的所有 SQL 进行审计，可以插入以下数据：

```shell
mysql> insert into mysql.tidb_audit_table_access (user, db, tbl, access_type) values ('.*', '.*', '.*', '');
```

如果希望对任意用户访问 ac 库 account 表的所有 SQL 进行审计，可以插入以下数据：

```shell
mysql> insert into mysql.tidb_audit_table_access (user, db, tbl, access_type) values (".*", 'ac', ^account$, '');
```

如果希望对以 `op_` 开头的用户名访问全部数据库 `account` 表的所有 SQL 进行审计，可以插入以下数据：

```shell
mysql> insert into mysql.tidb_audit_table_access (user, db, tbl, access_type) values ('op_.*', '.*', '.*', '');
```

注意匹配的规则不是通配符风格的。例如，如果 `user` 设置为 `abc*`，会匹配到 "ab", "abc", "abcc", "abccc" 等。

支持的 access_type 请参考下面列表中的 SubEvent，支持多个逗号分割。空字符串则代表所有都审计。

* Insert
* Select
* Update
* Replace
* Delete
* LoadData
* Alter
* DropTable
* CreateTable

### 刷新配置

对 mysql.tidb_audit_table_access 表进行修改后，需要执行 flush tidb plugins audit; 命令进行刷新，以通知集群中所有 TiDB 节点从表中 load 最新配置。如该命令执行失败，则需要进行重试执行 flush 操作。

```shell
mysql> flush tidb plugins audit;
Query OK, 0 rows affected (0.00 sec)
```

## 使用插件输出审计日志

审计插件加载后，会根据配置把不同类型的审计日志输出到和 TiDB 配置项 slow-query-file 相同的目录下，日志文件名称为 `tidb-audit.log`。

### 支持的审计事件类型

下表列出了目前支持的审计事件类型。

<table>
  <tr>
   <td>Event Class
   </td>
   <td>SubEvent
   </td>
   <td>开关
   </td>
   <td>备注
   </td>
  </tr>
  <tr>
   <td>CONNECTION
   </td>
   <td>Connected
<p>
Disconnect
<p>
ChangeUser
<p>
PreAuth
<p>
Reject
   </td>
   <td>默认开启。
<p>
只能通过禁用插件关闭。
   </td>
   <td>连接事件和鉴权事件。
   </td>
  </tr>
  <tr>
   <td>TABLE_ACCESS
   </td>
   <td>Insert
<p>
Select
<p>
Update
<p>
Replace
<p>
Delete
<p>
LoadData
<p>
Alter
<p>
DropTable
<p>
CreateTable
   </td>
   <td>默认关闭。
<p>
需要通过修改配置表指定 db - user - table - 事件 来开启。
   </td>
   <td>带 table 的 SQL。
<p>
会对 SQL sql 中的参数脱敏处理替换为 “?”。
   </td>
  </tr>
  <tr>
   <td>GENERAL
   </td>
   <td>-
   </td>
   <td>默认开启。
<p>
只能通过禁用插件关闭。
   </td>
   <td>没有 table 访问的其他 SQL。
   </td>
  </tr>
</table>

## 日志输出

所有事件类型的日志输出中，头部分是通用的字段, 在跳过前 3 个由日志库输出的字段后，有以下字段：

* ID：事件 ID
* TIMESTAMP：事件时间
* EVENT_CLASS：事件类型
* EVENT_SUBCLASS：事件子类型
* STATUS_CODE：语句响应状态
* COST_TIME：语句耗时
* HOST：服务器 IP
* CLIENT_IP：客户端 IP
* USER：登录用户名
* DATABASE：事件相关 db
* TABLES：事件相关的表名
* SQL_TEXT：脱敏后的 SQL
* ROWS：影响行数，无则为 0

日志输出中，会出现冗余或没数据也固定输出的情况，主要目的是方便当前日志分析系统处理。

CONNECTION、TABLE_ACCESS、GENERAL 还提供了补充输出的内容。

### CONNECTION 相关日志

CONNECTION 连接事件补充输出的内容如下:

* CLIENT_PORT：客户端端口号
* CONNECTION_ID：连接 ID
* CONNECTION_TYPE：是通过 socket 还是 unix-socket 连接
* SERVER_ID：TiDB Server ID
* SERVER_PORT：TiDB server 监听 MySQL 协议端口
* SERVER_OS_LOGIN_USER：TiDB 进程启动系统用户名
* OS_VERSION：TiDB Server 所在操作系统版本
* SSL_VERSION：TiDB 当前 SSL 版本
* PID：TiDB 进程 PID

示例：

[2019/07/24 22:13:30.099 +08:00] [INFO] [logger.go:71] [ID="15640224010"] [TIMESTAMP=2019/07/24 22:13:30.099 +08:00] [EVENT_CLASS=CONNECTION] [EVENT_SUBCLASS=Disconnect] [STATUS_CODE=0] [COST_TIME=0] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[test]"] [TABLES="[]"] [SQL_TEXT=] [ROWS=0] [CLIENT_PORT=45814] [CONNECTION_ID=1] [CONNECTION_TYPE=Socket] [SERVER_ID=1] [SERVER_PORT=4000] [DURATION=1233372.167907] [SERVER_OS_LOGIN_USER=robi] [OS_VERSION="Linux 5.0.0-20-generic.x86_64"] [CLIENT_VERSION=] [SERVER_VERSION=v2.1.15-16-g136e334df-dirty] [AUDIT_VERSION=] [SSL_VERSION=v1.2.0] [PID=24108]

#### TABLE_ACCESS 相关日志

TABLE_ACCESS 事件补充输出的内容如下：

* CONNECTION_ID：连接 ID
* COMMAND：MySQL 协议的 command 类型
* SQL_STATEMENTS：SQL 语句类型
* PID：TiDB 进程所在 PID

示例：

[2019/07/24 22:35:01.640 +08:00] [INFO] [logger.go:71] [ID="15640226010"] [TIMESTAMP=2019/07/24 22:35:01.640 +08:00] [EVENT_CLASS=TABLE_ACCESS] [EVENT_SUBCLASS=Insert] [STATUS_CODE=0] [COST_TIME=31581.623] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[mysql]"] [TABLES="[t1]"] [SQL_TEXT="insert into t1 ( a ) values ( ? )"] [ROWS=1] [CONNECTION_ID=2] [CLIENT_PORT=47430] [PID=24108] [COMMAND=Query] [SQL_STATEMENTS=Insert]

#### GENERAL 相关日志

GENERAL 事件补充输出的内容如下：

* CONNECTION_ID：连接 ID
* COMMAND：MySQL 协议的 command 类型
* SQL_STATEMENTS：SQL 语句类型
* PID：TiDB 进程所在 PID

示例：

[2019/07/24 22:31:22.612 +08:00] [INFO] [logger.go:71] [ID="15640334010"] [TIMESTAMP=2019/07/24 22:31:22.612 +08:00] [EVENT_CLASS=GENERAL] [EVENT_SUBCLASS=] [STATUS_CODE=0] [COST_TIME=67.6] [HOST=127.0.0.1] [CLIENT_IP=127.0.0.1] [USER=root] [DATABASES="[]"] [TABLES="[]"] [SQL_TEXT="set @@tidb_max_chunk_size = ?"] [ROWS=0] [CONNECTION_ID=2] [CLIENT_PORT=47430] [PID=24108] [COMMAND=Query] [SQL_STATEMENTS=Set]

## 清除审计日志

TiUP 对于审计插件产生的审计日志不会自动清除。如果需要清除审计日志，执行以下命令：

```shell
tiup cluster clean &lt;cluster-name> --audit-log
```

> **注意：**
>
> * 执行以上命令默认删除所有审计日志。
> * 清除操作不可逆，请先备份数据后使用。
