数据审计是一个跟踪表内容随时间变化的系统,在现在安全合规方面数据审计是必须要的功能之一。PostgreSQL作为一个强大现代的开源关系数据库,也有一个相关插件PGAudit可以提供审计功能。
关于PGAudit插件以后有机会可以详细介绍,本文我们介绍一个简单SQL语句实现的数据集审计功能。
最终实现效果为:
创建一个示例表:
启用审计:
增改删操作:
清空表:
查看审计日志:
请注意,record_id和old_record_id在更新行时保持不变,这样就可以轻松查询单行的历史记录。
要关闭审计追踪,只需执行:
首先创建一个名为audit schema为审计用:
接下来,需要一个表来跟踪插入、更新和删除。
传统上,使用audit schema并附加了一些元数据列,如提交的时间戳。
该解决方案存在一些维护挑战:
为此使用PostgreSQL的无模式JSONB数据类型将每条记录的数据存储在单个列中的。这种方法的另一个好处是允许将多个表的审计历史存储在一个审计表中。
查询性能很重要,如果不能快速查询日志,则该审计日志没有多大实际意义。为了提高查询的性能,需要对最常用的查询涉及字段创建索引。
对于时间范围,需要一个索引ts。 由于审计表仅用于插入记录,其中ts列插入操作时间,其值ts自然是升序排列。PostgreSQL的内置BRIN索引可以利用值和物理位置之间的相关性来生成一个索引,该索引在规模上比默认值(BTREE索引)小数百倍,并且查找时间更快。
对于表查询,包含了一个 table_oid跟踪PostgreSQL内部数字表标识符的列。可以为该列添加索引而不是table_schema和 able_name列,最小化索引大小并提供更好的性能。
将每一行的数据存储为的缺点之一jsonb是基于列值的过滤变得非常低效。如果想快速查找一行的历史记录,需要为每一行提取和索引一个唯一标识符。
对于全局唯一标识符,使用以下结构:
并将该数组散列为UUID v5以获得有效的可索引UUID类型,以识别对数据更改具有鲁棒性的行。
使用一个实用函数来查找记录的主键列名:
另一个为table_oid和主键,将结果转换为记录的UUID。
最后,索引record_id和old_record_id包含这些用于快速查询的唯一标识符的列。
为了让审计功能真正起作用,需要在最终用户不对其事务进行任何更改的情况下插入记录给审计表。为此,设置一个触发器在数据更改时触发,为每个插入/更新/删除的行为触发一次触发器。
将公开的用于对表启用审计的API:
禁用跟踪:
这些函数根据请求由表注册审计触发器:
开启审计表后会降低插入、更新和删除的吞吐量。但是在吞吐量低于每秒1000次写入的情况下,其开销通常可以忽略不计。对于写入频率较高的表,建议使用pgAudit。
通过简单纯sql语句就实现了Postgresql数据库的安全审计,总体上算起来实现才150行sql语句。大家可以自己手动尝试一下,主要是搞清楚其原理,如果生产环境中有需求还是建议用pgAudit。