GaussDB(DWS)数据库安全守护者之审计日志
GaussDB(DWS)数据库安全守护者之审计日志
1.前言
适用版本:【8.1.0(及以上)】
数据库安全对数据库系统来说至关重要,而数据库审计日志是数据库安全的重要一环。GaussDB(DWS)将用户的所有操作写入审计日志。数据库安全管理员可以利用这些日志信息,重现导致数据库现状的一系列事件,找出非法操作的用户、时间和内容等。
2.背景简介
GaussDB(DWS)的审计日志通过日志文件来承载,默认目录为$GAUSSLOG/pg_audit。其中,存在多个审计文件和一个index_table,index_table中标识了现有的文件数量、文件大小、文件时间等详细信息,根据该内容可对审计日志进行老化、新增、分裂、查询索引等操作。经过了多次演进,审计日志中记录的内容已经日益全面,且具有很强的配置性。不同版本之间审计日志新增内容简介如下:
| 版本 | 实现或优化内容 | 字段数 | 备注 | 
|---|---|---|---|
| 8.0.0 | 最初版审计日志,支持审计DML、存储过程、copy操作 | 12 | 审计雏形,保证语句级记录 | 
| 8.1.1 | 全面覆盖对各操作类型的审计,同时将命令执行失败场景也纳入系统审计 | 17 | 优化审计选项,场景覆盖全面 | 
| 8.2.1 | DML操作和部分DDL操作中对于列的操作纳入审计,并记录返回行数 | 20 | 增加审计细粒度 | 
3. 审计日志配置介绍
关于审计功能的配置,需要清楚审计开关的设计。审计的开关可配置性较多,灵活性较强,以下将介绍其中重要的开关选项。
3.1 审计日志记录配置
- audit_enabled:审计总开关,为布尔型开关,默认值为on,表示开启审计功能。审计总开关的开启和关闭也会被记录到审计日志中。
 - audit_inner_tool:内部维护工具对应的审计开关,控制是否对来自内部维护工具的操作进行审计;为布尔型开关,默认值为off,表示关闭对来自内部维护工具的操作进行审计。内部维护工具包括:cm_agent、gs_clean、OM、gs_roach、gs_redis、wlm、gs_ctl、gs_rewind等。
 - audit_operation_exec:执行成功操作对应的审计开关,支持对各操作类型进行配置,只有审计类型被配置,对应的操作执行成功时才会被记录到审计日志中。
 - audit_operation_error:执行失败操作对应的审计开关,支持对各操作类型进行配置,只有审计类型被配置,对应的操作执行失败时才会被记录到审计日志中。
 - audit_system_object:控制DDL操作对象的审计开关,数据库的DDL(CREATE,ALTER,DROP,表对象还包含TRUNCATE)操作的对象较多,通过该配置参数在操作对象维度上对审计进行更细粒度的控制。
 - audit_object_details:控制object_details字段是否对语句中的表名、列名以及列使用的类型以json格式进行审计;其中字段记录的场景有:SELECT、DELETE、UPDATE、INSERT、MERGE、CREATE TABLE AS SELECT,GRANT、DECLARE CURSOR,其中对于执行失败的GRANT语句不予记录(8.2.1版本及以上)
 - audit_object_name_format:控制审计日志object_name字段所显示的对象名的格式。其中选项为single时,表示object_name字段显示单个对象名,且为目标对象的名称。选项为all,表示object_name字段显示多个对象名称,并以json格式展示。(8.2.0版本及以上)
 
通常情况下,为保证审计日志中内容不会重复记录,默认仅会开启CN上的audit_enabled开关,从而使日志均记录在CN上,并且如果为非客户端下发语句而是从其他CN上下发的语句,也不做记录。
3.2 审计日志维护配置
- audit_directory:审计文件的存储目录。一个相对于数据目录data的路径,可自行指定,默认值为pg_audit。如果指定,也只能指定在$GAUSSLOG下
 - audit_space_limit:审计文件占用的磁盘空间总量。取值范围为1024KB~1024GB
 - audit_file_remain_threshold:审计目录下审计文件个数的最大值。默认值为1048576
 - audit_data_format:审计日志文件的格式。当前仅支持二进制格式。
 - audit_rotation_interval:指定创建一个新审计日志文件的时间间隔。当现在的时间减去上次创建一个审计日志的时间超过了此参数值时,服务器将生成一个新的审计日志文件。
 - audit_rotation_size:指定审计日志文件的最大容量。当审计日志消息的总量超过此参数值时,服务器将生成一个新的审计日志文件。
 - audit_resource_policy:控制审计日志的保存策略,以空间还是时间限制为优先策略。如果开启了以时间限制为优先,存储的审计日志所占磁盘空间达到audit_space_limit,此时也会对审计日志做老化操作。
 - audit_file_remain_time:表示需记录审计日志的最短时间要求,该参数audit_resource_policy在为off时生效。
 
以上参数中,如果需要控制审计日志的存储空间和时间,最好使用audit_resource_policy、audit_space_limit和audit_file_remain_time参数进行控制。
**注:**9.1.0以前版本,audit_space_limit参数有大变小调整范围过大时,审计线程会一直执行老化操作,可能会导致业务语句无法处理和记录。因此建议该参数由大变小时每次调整10G。9.1.0版本对此做了优化,每次对于审计日志的老化最多老化10个,当在业务空闲期再对审计日志进行老化操作。
4 审计日志参数具体配置及记录范围
4.1审计开关audit_operation_exec的配置
audit_operation_exec的默认配置项为:login, logout, database_process, user_lock, grant_revoke, select, set, transaction, cursor
表示对用户登录、注销、数据库启动\停止\切换\恢复、用户锁定\解锁、权限授予\收回、SET操作、事务操作、游标操作的成功场景进行审计。
如需要增加审计操作,支持的配置项如下:
| 配置项 | 描述 | 
|---|---|
| none | 表示未配置审计项,如果同时配置了其他任何审计项,则none失效 | 
| all | 表示对所有操作成功的场景进行审计。如果同时配置了其他任何审计项,则覆盖所有其他审计项的配置。需要注意,即使配置为all,也不表示对所有的DDL操作进行审计,仍然需要结合audit_system_object,对DDL操作的对象级别进行控制 | 
| login | 表示对用户登录成功的场景进行审计,默认配置 | 
| logout | 表示对用户退出进行审计,默认配置 | 
| database_process | 表示对数据库启动、停止、切换、恢复操作进行审计,默认配置 | 
| user_lock | 表示对用户锁定和解锁成功的场景进行审计,默认配置 | 
| grant_revoke | 表示对用户权限授予和回收成功的场景进行审计,默认配置 | 
| ddl | 表示对DDL操作成功的场景进行审计,因为DDL操作由会根据操作对象进行更细粒度控制,仍然沿用审计开关audit_system_object,即由audit_system_object控制对哪些对象的DDL操作进行审计(此处不配置ddl,只要配置了audit_system_object,审计也会生效) | 
| select | 表示对select操作成功的场景进行审计 | 
| copy | 表示对copy操作成功的场景进行审计 | 
| userfunc | 表示对用户自定义函数、存储过程、匿名块操作成功的场景进行审计 | 
| set | 表示对set操作成功的场景进行审计,默认配置 | 
| transaction | 表示对事务操作成功的场景进行审计 | 
| vacuum | 表示对vacuum操作成功的场景进行审计 | 
| analyze | 表示对analyze操作成功的场景进行审计 | 
| explain | 表示对explain操作成功的场景进行审计 | 
| specialfunc | 表示对特殊函数调用操作成功的场景进行审计,包括:pg_terminate_backend、pg_cancel_backend等强制终止业务函数 | 
| insert | 表示对insert操作成功的场景进行审计 | 
| update | 表示对update操作成功的场景进行审计 | 
| delete | 表示对delete操作成功的场景进行审计 | 
| merge | 表示对merge操作成功的场景进行审计 | 
| show | 表示对show操作成功的场景进行审计 | 
| checkpoint | 表示对checkpoint操作成功的场景进行审计 | 
| barrier | 表示对barrier操作成功的场景进行审计 | 
| cluster | 表示对cluster操作成功的场景进行审计 | 
| comment | 表示对comment操作成功的场景进行审计 | 
| cleanconn | 表示对clean connection操作成功的场景进行审计 | 
| prepare | 表示对PREPARE、EXECUTE、DEALLOCATE操作成功的场景进行审计 | 
| constraints | 表示对constraints操作成功的场景进行审计 | 
| cursor | 表示对游标操作成功的场景进行审计 | 
4.2审计开关audit_operation_error的配置
audit_operation_error的默认配置项为:login表示对登录失败的场景进行审计;
支持的配置项如下:
| 配置项 | 描述 | 
|---|---|
| none | 表示未配置审计项,如果同时配置了其他任何审计项,则none失效 | 
| syn_success | 表示同步audit_operation_exec的配置,即配置了某操作执行成功场景的审计,则对应的执行失败场景也记入审计。需注意,配置了syn_success后,仍可以继续配置其他操作执行失败场景的审计;如果audit_operation_exec配置为all,则所有的失败场景均记入审计;如果audit_operation_exec配置为none,则syn_success等同于none,即未配置审计项 | 
| parse | 表示对用户输入命令解析失败场景进行审计,包含等待命令超时的失败场景 | 
| login | 表示对用户登录失败的场景进行审计,默认配置 | 
| user_lock | 表示对用户锁定和解锁失败的场景进行审计 | 
| violation | 表示对用户访问存在越权的场景进行审计 | 
| grant_revoke | 表示对用户权限授予和回收失败的场景进行审计 | 
| ddl | 表示对DDL操作失败的场景进行审计,因为DDL操作由会根据操作对象进行更细粒度控制,仍然需要结合audit_system_object的配置情况,所以此处配置ddl后,将对audit_system_object指定类型的DDL失败场景进行审计 | 
| select | 表示对SELECT操作失败的场景进行审计 | 
| copy | 表示对COPY操作失败的场景进行审计 | 
| userfunc | 表示对用户自定义函数、存储过程、匿名块操作失败的场景进行审计 | 
| set | 表示对SET操作失败的场景进行审计 | 
| transaction | 表示对事务操作失败的场景进行审计 | 
| vacuum | 表示对VACUUM操作失败的场景进行审计 | 
| analyze | 表示对ANALYZE操作失败的场景进行审计 | 
| explain | 表示对EXPLAIN操作失败的场景进行审计 | 
| specialfunc | 表示对特殊函数调用操作失败的场景进行审计,包括:pg_terminate_backend、pg_cancel_backend等强制终止业务函数 | 
| insert | 表示对INSERT操作失败的场景进行审计 | 
| update | 表示对UPDATE操作失败的场景进行审计 | 
| delete | 表示对DELETE操作失败的场景进行审计 | 
| merge | 表示对MERGE操作失败的场景进行审计 | 
| show | 表示对SHOW操作失败的场景进行审计 | 
| checkpoint | 表示对CHECKPOINT操作失败的场景进行审计 | 
| barrier | 表示对BARRIER操作失败的场景进行审计 | 
| cluster | 表示对CLUSTER操作失败的场景进行审计 | 
| comment | 表示对COMMENT操作失败的场景进行审计 | 
| cleanconn | 表示对CLEAN CONNECTION操作失败的场景进行审计 | 
| prepare | 表示对PREPARE、EXECUTE、DEALLOCATE操作失败的场景进行审计 | 
| constraints | 表示对CONSTRAINTS操作失败的场景进行审计 | 
| cursor | 表示对游标操作失败的场景进行审计 | 
| blacklist | 表示对黑名单操作的执行失败进行审计 | 
4.3审计开关audit_system_object的配置
audit_system_object的值由22个二进制位的组合求出,这22个二进制位分别代表GaussDB(DWS)的22类数据库对象。
每一位可以取值0或1,取值的含义为:
- 取值为0:表示不审计对应的数据库对象的DDL操作;
 - 取值为1:表示审计对应的数据库对象的DDL操作;
 
例如:默认值为12295,对应的二进制为0011 0000 0000 0111(高位在前,低位在后),表示打开第0位、第1位、第2位、第12位、第13位对应对象的DDL操作的审计,具体对应DATABASE、SCHEMA、USER、DATA SOURCE、NODE GROUP这五个对象。
如需要增加审计table类型的DDL操作,可以通过以下方式进行设置:
- 
table在第3位,对应的十进制为8
 - 
在原有12295的基础上加上8,得12303
 - 
将audit_system_object的值设置为12303即可,如下:
gs_guc reload -Z coordinator -Z datanode -N all -I all -c "audit_system_object = 12303" 
这22个二进制位代表的具体含义如下:
| 二进制位 | 含义说明 | 
|---|---|
| 第0位 | 是否审计DATABASE对象的CREATE、DROP、ALTER操作 | 
| 第1位 | 是否审计SCHEMA对象的CREATE、DROP、ALTER操作 | 
| 第2位 | 是否审计USER对象的CREATE、DROP、ALTER操作 | 
| 第3位 | 是否审计TABLE对象的CREATE、DROP、ALTER、TRUNCATE操作 | 
| 第4位 | 是否审计INDEX对象的CREATE、DROP、ALTER操作 | 
| 第5位 | 是否审计VIEW对象的CREATE、DROP、ALTER操作 | 
| 第6位 | 是否审计TRIGGER对象的CREATE、DROP、ALTER操作 | 
| 第7位 | 是否审计PROCEDURE/FUNCTION对象的CREATE、DROP、ALTER操作 | 
| 第8位 | 是否审计TABLESPACE对象的CREATE、DROP、ALTER操作 | 
| 第9位 | 是否审计RESOURCE POOL对象的CREATE、DROP、ALTER操作 | 
| 第10位 | 是否审计WORKLOAD对象的CREATE、DROP、ALTER操作 | 
| 第11位 | 是否审计SERVER FOR HADOOP对象的CREATE、DROP、ALTER操作 | 
| 第12位 | 是否审计DATA SOURCE对象的CRAETE、DROP、ALTER操作 | 
| 第13位 | 是否审计NODE GROUP对象的CREATE、DROP、ALTER操作 | 
| 第14位 | 是否审计ROW LEVEL SECURITY对象的CREATE、DROP、ALTER操作 | 
| 第15位 | 是否审计TYPE对象的CREATE、DROP、ALTER操作 | 
| 第16位 | 是否审计TEXT SEARCH对象(CONFIGURATION和DICTIONARY)的CREATE、DROP、ALTER操作 | 
| 第17位 | 是否审计DIRECTORY对象的CREATE、DROP、ALTER操作 | 
| 第18位 | 是否审计SYNONYM对象的CREATE、DROP、ALTER操作 | 
| 第19位 | 是否审计REDACTION POLICY对象的CREATE、DROP、ALTER操作 | 
| 第20位 | 是否审计SEQUENCE对象的CREATE、DROP、ALTER操作 | 
| 第21位 | 是否审计NODE对象的CREATE、DROP、ALTER操作 | 
**注:**事务操作具有一定的特殊性,一个事务块涉及到多个语句的执行。如果在事务块进行中,对事务审计配置项(transaction)进行动态修改,将导致该事务块的审计记录不完整的问题。事务审计部分对这种情况按如下约定方式处理:
- 事务进行中事务配置项开启(无头有尾),不审计后续操作(无头有尾不记尾)
 - 事务进行中事务配置项关闭(有头无尾),审计后续操作直到事务end(有头无尾不掉尾)
 - 事务进行中,事务开关保持开启,但审计总开关开启(开总闸),因事务块的部分语句已经执行完毕,无法记录,所以不审计改事务块的后续操作(无头有尾不记尾)
 - 事务进行中,事务开关保持开启,但审计总开关关闭(断总闸),因事务块部分操作已经被记录,为保证事务记录的完整性,审计线程将继续运行,直到该事务块的end被审计后审计线程才退出(有头无尾不掉尾)
 - 事务进行中,事务开关保持开启,会话结束,记录事务回滚(未提交事务必回滚)
 
5. 审计日志查看
只有拥有AUDITADMIN属性的用户才可以查看审计记录。
审计日志需通过以下数据库接口
- pg_query_audit(timestamptz startime,timestamptz endtime, audit_log):查看当前CN的审计日志,可以指定需要读取审计日志的目录,默认从$GAUSSHOME/audit_directory中读取。
 - pgxc_query_audit(timestamptz startime,timestamptz endtime):查看所有CN的审计日志
 - pg_query_audit_details(timestamptz startime,timestamptz endtime, text node_mode):查看审计日志并将审计日志中的object_name和object_details字段由json格式解析出来;其中node_mode字段选项为current表示查询当前CN节点的审计日志,all表示查询所有CN节点的审计日志。
 
以上三个函数中,最开始的startime和endtime分别表示审计记录的开始时间和结束时间,满足审计条件的记录为startime ≤ 单条审计信息记录的结束时间 < endtime;
审计日志查看结果解析(821版本),各字段含义如下:
| 字段 | 含义 | 
|---|---|
| begintime | 执行操作的开始时间(811版本新增) | 
| endtime | 执行操作的结束时间,查看审计日志是根据此时间判断的 | 
| operation_type | 操作类型(811版本新增) | 
| audit_type | 审计类型 | 
| result | 执行操作的结果 | 
| username | 执行操作的用户名 | 
| database | 数据库名称 | 
| client_conninfo | 客户端信息 | 
| object_name | 操作对象的名称 | 
| object_details | 对语句中的表名、列名以及列使用的类型以json格式进行审计(821版本新增) | 
| command_text | 执行操作的命令(811版本新增) | 
| detail_info | 执行操作详细信息 | 
| transaction_xid | 事务id(811版本新增) | 
| query_id | query id(811版本新增) | 
| node_name | 节点名称 | 
| thread_id | 线程id | 
| local_port | 本地节点 | 
| remote_port | 远端节点 | 
| result_rows | 执行成功时的返回行(821版本新增) | 
| error_code | 执行失败时的错误码(821版本新增) | 
设置GUC参数,执行SELECT语句,查看审计日志记录,查询结果如下:
1.设置GUC参数
gs_guc reload -Z coordinator -Z datanode -N all -I all -c "audit_operation_exec='login, logout, database_process, user_lock, grant_revoke, set, transaction, cursor,select'"
gs_guc reload -Z coordinator -Z datanode -N all -I all -c "audit_object_details=on'"
gs_guc reload -Z coordinator -Z datanode -N all -I all -c "audit_object_name_format='all'"
2.执行select
postgres=# select * from t1 left join t2 on t1.a = t2.a;
 a | b | c | a | b | c
---+---+---+---+---+---
 1 | 1 | 1 |   |   |
(1 row)
3.查看审计日志记录
postgres=# select * from pg_query_audit(sysdate-0.1,sysdate) order by begintime desc, endtime desc limit 1;
-[ RECORD 3 ]---+-------------------------------------------------------------------------------------------------
begintime       | 2024-01-23 10:34:56.972+08
endtime         | 2024-01-23 10:34:56.985+08
operation_type  | dml
audit_type      | dml_action_select
result          | ok
username        | w00804127
database        | postgres
client_conninfo | gsql@[local]
object_name     | ["public.t1","public.t2"]
object_details  | {"public.t1":[{"a":"22"},{"b":"2"},{"c":"2"}],"public.t2":[{"a":"22"},{"b":"2"},{"c":"2"}]}
command_text    | select * from t1 left join t2 on t1.a = t2.a;
detail_info     |
transaction_xid | 0
query_id        | 72339069014638717
node_name       | coordinator1
session_id      | 1705976808.140052286080432.coordinator1
local_port      | 37100
remote_port     |
result_rows     | 1
error_code      |
postgres=# select * from pg_query_audit_details(sysdate-0.1,sysdate,'current') where command_text like 'select * from t1 left join%' and query_id = 72339069014638717 order by begintime desc, endtime desc limit 4;
-[ RECORD 1 ]---+----------------------------------------------
begintime       | 2024-01-23 10:34:56.972+08
endtime         | 2024-01-23 10:34:56.985+08
operation_type  | dml
audit_type      | dml_action_select
result          | ok
username        | w00804127
database        | postgres
client_conninfo | gsql@[local]
transaction_xid | 0
query_id        | 72339069014638717
node_name       | coordinator1
session_id      | 1705976808.140052286080432.coordinator1
local_port      | 37100
remote_port     |
object_name     | public.t1
column_name     | a
type_of_use     | 22
use_type        | Access,Conditional,Outer join
command_text    | select * from t1 left join t2 on t1.a = t2.a;
-[ RECORD 2 ]---+----------------------------------------------
begintime       | 2024-01-23 10:34:56.972+08
endtime         | 2024-01-23 10:34:56.985+08
operation_type  | dml
audit_type      | dml_action_select
result          | ok
username        | w00804127
database        | postgres
client_conninfo | gsql@[local]
transaction_xid | 0
query_id        | 72339069014638717
node_name       | coordinator1
session_id      | 1705976808.140052286080432.coordinator1
local_port      | 37100
remote_port     |
object_name     | public.t1
column_name     | b
type_of_use     | 2
use_type        | Access
command_text    | select * from t1 left join t2 on t1.a = t2.a;
-[ RECORD 3 ]---+----------------------------------------------
begintime       | 2024-01-23 10:34:56.972+08
endtime         | 2024-01-23 10:34:56.985+08
operation_type  | dml
audit_type      | dml_action_select
result          | ok
username        | w00804127
database        | postgres
client_conninfo | gsql@[local]
transaction_xid | 0
query_id        | 72339069014638717
node_name       | coordinator1
session_id      | 1705976808.140052286080432.coordinator1
local_port      | 37100
remote_port     |
object_name     | public.t1
column_name     | c
type_of_use     | 2
use_type        | Access
command_text    | select * from t1 left join t2 on t1.a = t2.a;
-[ RECORD 4 ]---+----------------------------------------------
begintime       | 2024-01-23 10:34:56.972+08
endtime         | 2024-01-23 10:34:56.985+08
operation_type  | dml
audit_type      | dml_action_select
result          | ok
username        | w00804127
database        | postgres
client_conninfo | gsql@[local]
transaction_xid | 0
query_id        | 72339069014638717
node_name       | coordinator1
session_id      | 1705976808.140052286080432.coordinator1
local_port      | 37100
remote_port     |
object_name     | public.t2
column_name     | a
type_of_use     | 22
use_type        | Access,Conditional,Outer join
command_text    | select * from t1 left join t2 on t1.a = t2.a;
6.总结
GaussDB(DWS)审计日志作为GaussDB(DWS)集群数据安全运维的重要支撑手段,记录着数据库的启动和停止、用户的登录和退出、各种各样的语句的执行情况、访问越权操作、事务操作等等,可以提供合规审计依据,支持审计数据转储以满足对审计数据保存期限的要求,可以记录、分析、追踪数据库安全事件,可以进行问题定位等。本文详细介绍了审计日志的版本发展历程,并总结了现有规格,标明了审计中常常遇到的问题及具体解决方案。
7.参考文献
- GaussDB(DWS)数据库安全守护者之审计日志 https://bbs.huaweicloud.com/blogs/253698
 - 【如何保证你的DWS数据更安全】GaussDB(DWS) 8.2.1版本审计日志新增功能介绍 https://bbs.huaweicloud.com/blogs/407529
 
- 点赞
 - 收藏
 - 关注作者
 
            
           
评论(0)