金仓数据库用户权限隔离:从功能兼容到安全增强的技术演进
《KingbaseES数据库》本篇文章所属专栏—持续更新中—欢迎订阅!
金仓数据库简介
KingbaseES(简称KES)是面向全行业、全客户关键应用的企业级大型通用融合数据库产品,适用于事务处理类应用、数据分析类应用、海量时序数据采集检索类应用、要求苛刻的互联网应用等场景;可用作管理信息系统、业务及生产系统、决策支持系统、多维数据分析系统、运行日志管理系统、全文检索系统、地理信息系统、时序数据处理相关系统的承载数据库。
KES采用融合数据库架构,通过多语法体系一体化架构实现一套软件兼容Oracle、MySQL、SQL、Server、PostgreSQL等多个异构数据库的语法;采用多模数据一体化存储,支持对关系模型、文档模型、全文本、GIS数据、时序等数据的统一存储、混合访问、模型间转换;采用集中分布一体化架构,满足不同级别的可用性,为客户提供不同级别的可用性、性能扩展、成本需求,确保业务连续,最大化投资价值。

在数据安全与合规要求日益严苛的今天,数据库权限控制已成为企业防护体系的核心环节。传统权限管理多停留在“授权即可访问”的基础层面,难以应对越权探测、数据泄露等高级安全威胁。
金仓数据库(KingbaseES)推出的用户权限隔离功能,基于行级安全策略(RLS)构建了精细化访问控制体系,通过“功能兼容”到“功能增强”的持续迭代,实现了从“基础隔离”到“纵深防护”的安全升级。下面我将深入解析其技术架构、演进路径及实践价值,结合核心代码示例,展现金仓在数据库安全领域的创新突破。
一、为什么需要用户权限隔离?数据安全的核心痛点破解
对于传统权限控制方案存在三大痛点:
- 隔离不彻底:未授权用户虽无法操作数据,但仍能查询到表、函数等对象的存在,为攻击者提供了探测攻击的入口;
- 权限颗粒度粗:仅支持表级、角色级授权,无法实现字段、触发器等细粒度对象的隔离;
- 兼容性不足:新增安全功能往往需要改造现有业务系统,升级成本高、风险大。
金仓数据库的用户权限隔离功能,核心目标是实现“无权即不可见”的彻底隔离,同时兼顾业务兼容性,让企业在不影响现有系统运行的前提下,快速提升数据安全防护能力。其核心价值体现在下面三个方面:
- 安全层面:未授权对象完全隐藏,阻断越权探测路径,符合等保2.0等合规要求;
- 业务层面:兼容传统DAC、RBAC权限体系,无需大规模改造应用代码;
- 管理层面:支持动态启用/禁用,策略配置灵活,降低运维复杂度。
二、技术基石:RLS驱动的权限隔离实现原理
金仓数据库的权限隔离功能并非简单的权限叠加,而是基于行级安全策略(Row-Level Security, RLS)构建的系统化解决方案。RLS作为PostgreSQL生态成熟的安全技术,能够在表级别定义过滤规则,实时筛选查询结果。金仓在此基础上进行深度扩展,将RLS的应用范围从用户数据表延伸至系统表,实现全量数据库对象的隔离。
2.1 核心实现逻辑
权限隔离的本质是通过RLS策略对系统表查询结果进行过滤,其技术流程如下:
- 启用功能后,数据库自动为含ACL(访问控制列表)字段的系统表(如sys_class、sys_database)添加预设RLS策略;
- 用户发起查询时,数据库触发对应系统表的RLS策略,调用权限判断函数验证用户权限;
- 权限判断函数根据用户身份、请求权限类型返回验证结果,RLS据此过滤结果集;
- 最终仅返回用户有权访问的对象,无权对象完全不显示,实现“彻底隔离”。
2.2 关键技术组件与代码实现
2.2.1 核心数据结构:标准化RLS策略配置
为实现策略的统一管理和可扩展性,金仓定义了CreateRLSForSystemTable结构体,记录每条RLS策略的关键属性:
// 定义RLS策略配置结构体,标准化系统表与策略的映射关系
typedef struct {int sysTabID; /* 系统表OID,唯一标识目标系统表 */char* relName; /* 系统表名称,如"rel"对应sys_class表 */char* policyName; /* RLS策略名称,全局唯一 */char* funcName; /* 权限判断函数名称 */char* schemaName; /* 权限判断函数所属模式 */char* relColname1; /* 权限判断函数第一个参数 */char* relColname2; /* 权限判断函数第二个参数 */char* privType; /* 支持的权限列表,用逗号分隔 */
} CreateRLSForSystemTable;
2.2.2 RLS策略列表:全量对象隔离覆盖
金仓通过CreateRLSForSystemTableList列表管理所有系统表的RLS策略,覆盖表、数据库、触发器、大对象等核心对象,以下是核心配置示例:
// 系统表RLS策略列表,维护所有对象的隔离规则
static const CreateRLSForSystemTable CreateRLSForSystemTableList[SYSTABLE_POLICY_MAXNUM] = {// 表对象(sys_class)策略:控制表、序列等对象访问{RelationRelationId, "rel", "sys_class_isolation_object_rls","is_object_inclass", "security_utils", "currentuser", "oid","select,insert,update,delete,truncate,references,trigger,dumptable,select,update,usage"},// 数据库对象(sys_database)策略:控制数据库连接、创建权限{DatabaseRelationId, "db", "sys_database_isolation_object_rls","has_database_privilege", "pg_catalog", "current_user", "datname","connect,create,temporary,temp"},// 触发器对象(sys_trigger)策略:控制触发器访问{TriggerRelationId, "trige", "sys_trigger_isolation_object_rls","has_trigger_privilege", "security_utils", "currentuser", "oid","execute"},// 大对象元数据(sys_largeobject_metadata)策略:控制大对象访问{LargeObjectMetadataRelationId, "lob_meta", "sys_largeobject_isolation_object_rls","has_largeobject_privilege", "security_utils", "currentuser", "id","select,update"}
};
该列表采用“配置化”设计,新增隔离对象时仅需补充结构体配置,无需修改核心逻辑,极大提升了可扩展性。
2.2.3 权限判断函数:策略执行核心
权限判断函数是RLS策略的执行单元,负责验证用户权限。以表对象权限判断函数has_class_privilege_name_id为例:
// 验证用户对表、序列等类对象的权限
Datum has_class_privilege_name_id(KDB_FUNCTION_ARGS) {// 获取输入参数:用户名、对象OID、权限类型Name username = KDB_GETARG_NAME(0);Oid classoid = KDB_GETARG_OID(1);text* priv_type_text = KDB_GETARG_TEXT_PP(2);char* priv_type_string = text_to_cstring(priv_type_text);// 定义支持的权限列表(含新增的dumptable权限)char* priv_type_string_table = "select,insert,update,delete,truncate,references,trigger,dumptable";char* priv_type_string_sequence = "select,update,usage";char priv_type[1024] = {'\0'};Oid roleid;AclMode mode;AclResult aclresult;// 验证权限类型合法性if (strstr(priv_type_string, priv_type_string_table) == NULL && strstr(priv_type_string, priv_type_string_sequence) == NULL) {ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),errmsg("unrecognized privilege type: %s", priv_type_string)));}// 拼接合法权限列表,二次校验strcat(priv_type, priv_type_string_table);strcat(priv_type, ",");strcat(priv_type, priv_type_string_sequence);if (kb_strcasecmp(priv_type, priv_type_string)) {ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),errmsg("unrecognized privilege type: %s", priv_type_string)));}// 获取用户角色OID,不存在则返回无权限roleid = get_role_oid(NameStr(*username), false);if (!OidIsValid(roleid)) {KDB_RETURN_BOOL(false);}// 解析权限模式并检查权限mode = aclparse(priv_type_string);aclresult = aclcheck(classoid, roleid, mode, NULL);// 返回权限检查结果KDB_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
2.3 基础功能使用:启用与验证示例
金仓权限隔离功能通过ALTER DATABASE语句启用/禁用,操作简单且支持在线动态调整,以下是完整使用流程:
步骤1:环境准备(创建表与用户)
-- 以system超级用户连接数据库
psql -U system -d test -h 127.0.0.1 -p 54321-- 创建测试表t1
test=# create table t1(a int);
CREATE TABLE-- 创建普通用户u1,设置密码
test=# create user u1 with password '12345678ab';
CREATE ROLE
步骤2:未启用隔离时的访问测试
-- 切换至u1用户
test=# \c -u1
您现在以用户名"u1"连接到数据库"test"。-- 未启用隔离,u1可查询到t1表(虽无操作权限)
test=> select oid, relname from sys_class where relname = 't1';oid | relname
-------+---------16638 | t1
(1行记录)
步骤3:启用隔离后的访问测试
-- 切换回system用户,启用权限隔离
test=> \c -system
test=# alter database test enable object isolation;
ALTER DATABASE-- 切换至u1用户,再次查询t1表
test=# \c -u1
test=> select oid, relname from sys_class where relname = 't1';oid | relname
-----+---------
(0行记录) -- 无结果,t1表已被隔离
步骤4:授予权限后的访问恢复
-- 切换回system用户,授予u1对t1表的SELECT权限
test=> \c -system
test=# grant SELECT on TABLE t1 to u1;
GRANT-- 切换至u1用户,查询t1表
test=# \c -u1
test=> select oid, relname from sys_class where relname = 't1';oid | relname
-------+---------16638 | t1
(1行记录) -- 有权限,可正常查询
三、演进之路:从功能兼容到安全增强的关键突破
金仓权限隔离功能的发展并非一蹴而就,而是围绕“安全增强”与“业务兼容”的平衡,经历了两个关键阶段的演进,每一步都精准解决了企业在不同阶段的安全需求。
3.1 第一阶段:功能兼容(基础隔离能力)
核心目标
在不影响现有业务运行的前提下,金仓数据库提供基础隔离能力,兼容传统权限体系,让用户“零改造”启用安全功能。
关键特性与代码实现
- 核心系统表覆盖:仅针对sys_class、sys_database、sys_namespace等核心系统表配置RLS策略,满足常规隔离需求:
// 功能兼容阶段的RLS策略列表(仅含核心系统表)
static const CreateRLSForSystemTable CreateRLSForSystemTableList[3] = {{RelationRelationId, "rel", "sys_class_isolation_object_rls","is_object_inclass", "security_utils", "currentuser", "oid","select,insert,update,delete,truncate,references,trigger"}, // 无自定义权限{DatabaseRelationId, "db", "sys_database_isolation_object_rls","has_database_privilege", "pg_catalog", "current_user", "datname","connect,create,temporary,temp"},{NamespaceRelationId, "nsp", "sys_namespace_isolation_object_rls","has_schema_privilege", "pg_catalog", "current_user", "id","usage,create"}
};
- 标准权限类型支持:仅兼容SQL标准权限(select、insert等),不引入自定义权限,确保与现有应用无缝对接:
// 功能兼容阶段的权限列表(无自定义权限)
char* priv_type_string_table = "select,insert,update,delete,truncate,references,trigger";
char* priv_type_string_sequence = "select,update,usage";
- 轻量化启用:通过简单SQL语句启用,无需修改配置文件或重启数据库,降低使用门槛。
适用场景
适用于常规业务场景,企业无需调整现有权限体系,即可快速获得基础隔离能力,防止越权探测。
3.2 第二阶段:功能增强(精细化安全防护)
随着企业安全需求升级,基础隔离能力已无法满足复杂场景(如金融、政务)的要求。金仓通过“新增隔离权限”“扩展隔离对象”“优化策略机制”三大突破,实现了安全能力的全面增强。
3.2.1 突破一:新增自定义隔离权限(以DUMPTABLE为例)
传统SQL权限无法覆盖“数据备份”等特殊场景,金仓新增DUMPTABLE权限,用于严格控制表备份操作,其开发流程如下:
- 定位RLS策略:确定
DUMPTABLE权限对应sys_class表的sys_class_isolation_object_rls策略; - 修改权限判断函数:在
has_class_privilege_name_id中添加dumptable权限:
// 功能增强阶段:添加dumptable权限至表权限列表
char* priv_type_string_table = "select,insert,update,delete,truncate,references,trigger,dumptable";
- 更新RLS策略配置:在策略列表中补充
dumptable权限:
{RelationRelationId, "rel", "sys_class_isolation_object_rls","is_object_inclass", "security_utils", "currentuser", "oid","select,insert,update,delete,truncate,references,trigger,dumptable,select,update,usage"},
- 功能验证示例:
-- 授予u1对t1表的DUMPTABLE权限(无SELECT权限)
test=# grant DUMPTABLE on TABLE t1 to u1;
GRANT-- u1用户查询t1表(DUMPTABLE权限触发隔离解除)
test=> \c -u1
test=> select oid, relname from sys_class where relname = 't1';oid | relname
-------+---------16638 | t1
(1行记录)-- 验证备份操作(有权限可成功备份)
pg_dump -U u1 -d test -t t1 -f t1_dump.sql
3.2.2 突破二:扩展隔离对象(以触发器为例)
初期仅支持核心系统表,功能增强后扩展至触发器、大对象等复杂对象。以触发器隔离为例,开发流程如下:
- 确定对象映射:触发器对象(trigger)对应系统表
_trigger,隔离映射为“trigger→_trigger”; - 定义权限判断函数
has_trigger_privilege_name_id:
// 验证用户对触发器的访问权限
Datum has_trigger_privilege_name_id(KDB_FUNCTION_ARGS) {Name username = KDB_GETARG_NAME(0);Oid trigid = KDB_GETARG_OID(1);text* priv_type_text = KDB_GETARG_TEXT_PP(2);Oid roleid;AclMode mode;AclResult aclresult;Relation tgrel;SysScanDesc tgscan;HeapTuple ht_trig;Form_trigger trigrec;ScanKeyData skey[1];char* priv_type_string = text_to_cstring(priv_type_text);// 触发器仅支持execute权限if (kb_strcasecmp(priv_type_string, "execute") != 0) {ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),errmsg("trigger only supports 'execute' privilege")));}// 打开_trigger系统表tgrel = table_open(TriggerRelationId, LockAccessShare);// 初始化扫描键,通过触发器OID定位记录ScanKeyInit(&skey[0], Anum_trigger_oid, BTEqualStrategyNumber, F_OIDEQ,ObjectIdGetDatum(trigid));// 扫描_trigger表tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true, NULL, 1, skey);ht_trig = systable_getnext(tgscan);// 未找到触发器记录,返回无权限if (!HeapTupleIsValid(ht_trig)) {systable_endscan(tgscan);table_close(tgrel, LockAccessShare);KDB_RETURN_BOOL(false);}// 解析触发器记录,验证关联表权限trigrec = (Form_trigger)GetStruct(ht_trig);if (!OidIsValid(trigrec->tgfoid) || !OidIsValid(trigrec->tgrelid)) {systable_endscan(tgscan);table_close(tgrel, LockAccessShare);KDB_RETURN_BOOL(false);}// 验证用户对关联表的权限if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(trigrec->tgrelid))) {systable_endscan(tgscan);table_close(tgrel, LockAccessShare);KDB_RETURN_BOOL(false);}// 获取用户角色OID并检查权限roleid = get_role_oid(NameStr(*username), false);if (!OidIsValid(roleid)) {systable_endscan(tgscan);table_close(tgrel, LockAccessShare);KDB_RETURN_BOOL(false);}mode = aclparse(priv_type_string);aclresult = aclcheck(trigid, roleid, mode, NULL);// 释放资源并返回结果systable_endscan(tgscan);table_close(tgrel, LockAccessShare);KDB_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
- 添加RLS策略配置:
// 新增触发器对象的RLS策略
{TriggerRelationId, "trige", "sys_trigger_isolation_object_rls","has_trigger_privilege", "security_utils", "currentuser", "oid","execute"},
3.2.3 突破三:优化策略机制
- 策略冲突检测:新增冲突检测逻辑,避免同一系统表配置相互冲突的RLS策略;
- 动态策略调整:支持通过SQL语句动态修改RLS策略,无需重启数据库:
-- 动态修改sys_class表的RLS策略权限
alter policy sys_class_isolation_object_rls on sys_class
using (is_object_inclass(currentuser, oid, 'select,insert,update,delete,alter'));
3.3 演进阶段核心差异对比
| 演进阶段 | 核心目标 | 关键特性 | 安全能力 | 适用场景 |
|---|---|---|---|---|
| 功能兼容 | 兼容现有业务,基础隔离 | 核心系统表覆盖、标准权限支持、静态策略 | 防止基础越权探测 | 常规业务场景,无需自定义权限 |
| 功能增强 | 精细化安全防护 | 自定义权限、全对象隔离、动态策略调整 | 全维度纵深防护,精准权限控制 | 金融、政务、医疗等高危行业 |
四、总结与展望
金仓数据库用户权限隔离功能的演进,是 “安全增强” 与 “业务兼容” 平衡的典范。从功能兼容阶段的基础隔离,到功能增强阶段的精细化防护,金仓通过核心数据结构设计、权限判断函数优化、策略机制升级,构建了覆盖全对象、支持自定义权限、动态调整的权限隔离体系,从根源上解决了传统权限管理的隔离不彻底、颗粒度粗、兼容性差等痛点。
金仓数据库始终以“成为世界卓越的数据库产品与服务提供商”为目标,通过持续的技术创新,为企业数据安全保驾护航,助力企业在数字化时代实现安全与发展的双赢。
