安全审计

数据库审计是对数据库操作进行细粒度审计的合规性管理,对数据库遭受到的风险行为进行告警,对攻击行为进行阻断。它通过对用户访问数据库行为进行记录、分析和汇报,可以用来帮助用户事后生成合规报告、事故追根溯源,同时加强内外部数据库网络行为记录,提高数据资产安全。

YMatrix 审计方式可以通过log_XXX 和 pgAudit 两种方式进行:

log_XXX

log_xxx 系列参数用于配置日志记录的行为,帮助监控和调试数据库的运行情况。将所有的数据库操作行为记录到数据库运行日志里,然后分析日志进行危险行为预警处理。

配置参数

logging_collector     --是否开启日志收集开关,默认off,推荐on
log_destination       --日志记录类型,默认是stderr,只记录错误输出,推荐csvlog,总共包含:stderr, csvlog, syslog, and eventlog,
log_directory          --日志路径,默认是$PGDATA/pg_log, 
log_filename            --日志名称,默认是postgresql-%Y-%m-%d_%H%M%S.log
log_file_mode           --日志文件类型,默认为0600
log_truncate_on_rotation  --默认为off,设置为on的话,文件内容覆盖方式:off后面附加,on:清空再加
log_rotation_age      --保留单个文件的最大时长,默认是1d,也有1h,1min,1s
log_rotation_size       --保留单个文件的最大尺寸,默认是10MB
log_error_verbosity    --默认为default,verbose表示冗长的
log_connections    --用户session登陆时是否写入日志,默认off,推荐为on
log_disconnections --用户session退出时是否写入日志,默认off,推荐为on
log_statement    --记录用户登陆数据库后的各种操作 
    none,即不记录
    ddl(记录create,drop和alter)
    mod(记录ddl+insert,delete,update和truncate)
    all(mod+select)
log_min_duration_statement = 2s   --记录超过2秒的SQL
log_checkpoints = on
log_lock_waits = on
deadlock_timeout = 1s

配置示例

以下是一个配置示例,将这些参数添加到 postgresql.conf 文件中:

注意!
修改 postgresql.conf 文件后,需要重启 YMatrix 服务以使配置生效。

logging_collector = on
log_directory = 'stderr'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1d
log_rotation_size = 10MB
log_truncate_on_rotation = off

log_statement = 'all'
log_min_duration_statement = 100

log_connections = on
log_disconnections = on
log_lock_waits = on

pgAudit

仅从 YMatrix 6.4.6 版本(包括 6.4.6 版本)开始支持

引入 pg_audit 扩展进行更加精细的审计。

安装与启用

--修改参数,新增pgaudit
gpconfig -c shared_preload_libraries -v matrixts,matrixmgr,matrixgate,mxstream,telemetry,pgaudit
--修改参数后需重启数据库
mxstop -arf
mxstart -a
--重启数据库实例后
CREATE EXTENSION pgaudit;

配置参数

pgAudit 会提供会话和对象两种审计模式。数据库会存在如下可配置参数。

pgaudit.log     -- 指定会话审计日志记录将记录哪些类语句,默认 none。取值包括如下:
    READ (select, copy from)
    WRITE (insert, update, delete, truncate, copy to)
    FUNCTION (function calls and DO blocks)
    ROLE (grant, revoke, create/alter/drop role)
    DDL (all DDL except those in ROLE)
    MISC (discard, fetch, checkpoint, vacuum)
    MISC_SET (Miscellaneous SET commands, e.g. SET ROLE.)
    ALL (Include all of the above.)
pgaudit.log_catalog    -- 控制是否审计 pg_catalog 模式下的表的变动,默认 on。
pgaudit.log_client     -- 是否记录客户端的应用程序类型,默认 off。
pgaudit.log_level      -- 审计日志记录的记录级别,默认 log。
pgaudit.log_parameter  -- 控制审计日志是否记录会话级别的参数设置行为,默认 off。
pgaudit.log_parameter_max_size  -- 审计参数设置的最大值,单位是byte,默认 0。
pgaudit.log_relation   -- 控制会话审计时,是否为每个表都记录一条日志,默认 off。
pgaudit.log_rows       -- 控制是否记录语句的影响记录数,默认 off。   
pgaudit.log_statement  -- 控制是否记录语句信息,默认 on。
pgaudit.log_statement_once     -- 控制一组语句执行是否只在第一个审计条目里记录明细信息,默认 off。
pgaudit.role           -- 指定用于对象审计日志记录的主角色,无默认值

配置示例

会话级审计

会话级审计会对用户会话中执行的所有符合规则的 SQL 进行审计,适合安全合规场景。

-- 1. 设定审计范围
set pgaudit.log = 'read, ddl'; 

-- 2.执行操作 
-- 2.1 创建表
create table account
(
    id int,
    name text,
    password text,
    description text
);

-- 2.2 插入数据
insert into account (id, name, password, description)
             values (1, 'user1', 'HASH1', 'blah, blah');

-- 2.3查询数据
select *
    from account;

-- 3.查看日志(由于审计范围不包含 write 类,所以 insert 操作不会被记录)
AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.account,create table account
(
    id int,
    name text,
    password text,
    description text
);,<not logged>
AUDIT: SESSION,2,1,READ,SELECT,,,select *
    from account,,<not logged>

对象审计

仅审计访问特定对象的行为,需要配合审计角色使用。

在本示例中,这个例子展示了如何通过 pgAudit 扩展记录审计角色(auditor)对特定表和列的操作日志。

--1. 创建审计角色
CREATE ROLE auditor;

--2. 启用对象审计
set pgaudit.role = 'auditor';    

--3. 授权对象给审计角色
grant select (password) on public.account to auditor;

--4. 执行操作
--4.1 查询指定password列
postgres=# select password   
  from account;                                                                                                                                                                       
 password              
----------             
 HASH2                  
 HASH2              
 HASH2           
(3 rows)                  

--4.2 查询id,name列     
postgres=# select id, name 
  from account;   
 id | name    
----+-------   
  1 | user1   
  1 | user1
  1 | user1 
(3 rows) 

--5. 查看日志,仅访问password时被审计
"AUDIT: OBJECT,2,1,READ,SELECT,TABLE,public.account,""select password from account;"","
,,,,,,,0,,"pgaudit.c",767,  

--6. 授予对象update权限
grant update (name, password) on public.account to audit;

--6.1 执行update操作
update account set password = 'HASH2';

--7. 查看日志
"AUDIT: OBJECT,4,1,WRITE,UPDATE,TABLE,public.account,""update account                                 
   set password = 'HASH2';"",",,,,,,,0,,"pgaudit.c",767,

对象审计与会话审计

对象审计日志记录旨在成为 pgaudit.log='read,write' 的更细粒度的替代品,将它们简单结合使用可能没有意义,但一种可能的情况是使用会话日志记录来捕获每个语句,然后使用对象日志记录来补充以获取有关特定关系的更多详细信息。

--1. 建表
create table account_role_map(account_id int,role_id int);

--2.授予auditor对象表的查询权限
grant select on public.account_role_map to auditor; 

--3. 执行操作
--3.1 关闭会话审计时,为每个表记录一条日志
set pgaudit.log_relation to off; 

--3.2 执行查询
select account.password,account_role_map.role_id \
from account inner join account_role_map \
on account.id = account_role_map.account_id;

select account_role_map.account_id \
from account inner join account_role_map
on account.id = account_role_map.account_id;

--4. 查看日志
--4.1 第一条由于访问了 password,且访问了 account_role_map,所以两个表都有审计
"AUDIT: OBJECT,9,1,READ,SELECT,TABLE,public.account,""select account.password,   
       account_role_map.role_id    
   from account         
       inner join account_role_map   
            on account.id = account_role_map.account_id       
;"",",,,,,,,0,,"pgaudit.c",767,  
"AUDIT: OBJECT,9,1,READ,SELECT,TABLE,public.account_role_map,""select account.password,  
       account_role_map.role_id   
  from account                                 
       inner join account_role_map                     
            on account.id = account_role_map.account_id    
;"",",,,,,,,0,,"pgaudit.c",767, 

--4.2 第二条由于没有访问 password,所以只有一条审计
"AUDIT: OBJECT,10,1,READ,SELECT,TABLE,public.account_role_map,""select   
       account_role_map.account_id   
  from account                   
       inner join account_role_map                                  
            on account.id = account_role_map.account_id                                                                                                                                                                                                     
;"",",,,,,,,0,,"pgaudit.c",767, 

--4.3 由于两条sql都访问了account_role_map,因此都触发了account_role_map的审计
"AUDIT: OBJECT,10,1,READ,SELECT,TABLE,public.account_role_map,""select                                
       account_role_map.account_id  
  from account                           
       inner join account_role_map      
            on account.id = account_role_map.account_id   
;"",",,,,,,,0,,"pgaudit.c",767, 
"AUDIT: OBJECT,11,1,READ,SELECT,TABLE,public.account_role_map,""select                                
       account_role_map.role_id    
  from account                   
       inner join account_role_map 
            on account.id = account_role_map.account_id  
;"",",,,,,,,0,,"pgaudit.c",767,