强制访问是基于自定义的安全策略最终通过标签实现对用户和表的行级安全加密。安全策略(Policy)是等级(Level)和隔离区(Compartment),组(Group)和标签(Label)的集合,最终通过绑定标签实现行级安全。其实现原理是将表和用户绑定到标签上,再由标签关联等级(必选),隔离区(可选)和安全组(可选),形成了一个多级的行级安全加密体系。
- 安全策略(Policy):是指创建等级(Level),隔离区(Compartment),组(Group)和标签(Label)必须指定所属的安全策略。
- 等级(Level):提供第二等级的安全控制,标签必须指定等级。
- 隔离区(Compartment):提供第二等级的安全控制,可选。
- 组(Group):提供第三等级的安全控制,一种树状的结构,可选。
- 标签(Label):最终通过标签绑定体现行级安全。仅当用户被赋予的标签比此行标签有相同或更高等时,该行才可以被用户存取。
注意分号(:)和逗号(,)保留用于多级安全体系的表达,安全策略中组件的名字不要使用。
在Teledb中,创建安全策略需要通过teledbx_mls插件,需要创建插件
SQL
CREATE EXTENSION teledbx_mls;
安全策略
通过MLS_CLS_CREATE_POLICY()函数创建安全策略
SQL
SELECT MLS_CLS_CREATE_POLICY(policy_name, policy_id)
参数描述:
- policy_name(策略名称): 要创建的策略的名称,大小写敏感,不可以空。
- policy_id(策略ID): 用于标识策略的唯一ID,取值范围[1, 100]。
安全等级(Level)
通过函数MLS_CLS_CREATE_LEVEL()函数创建安全等级。
SQL
SELECT MLS_CLS_CREATE_LEVEL(policy_name, level_id, short_name, long_name)
参数描述:
- policy_name(策略名称): 指定要添加安全级别的策略名称,不可以为空。
- level_id(级别ID): 用于标识安全级别的唯一ID,取值范围[0, 32767]。
- short_name(名称): 安全级别的名称,大小写敏感,不可为空,不可以含空格和tabj键。
- short_name(名称): 安全级别的名称,大小写敏感,不可为空,不可以含空格和tabj键。
- long_name(完整名称): 安全级别的描述。
通过MLS_CLS_ALTER_LEVEL_DESCRIPTION()函数修改等级的标签描述。
SQL
SELECT MLS_CLS_ALTER_LEVEL_DESCRIPTION(policy_name, level_id, long_name)
安全隔离区(Compartment)
通过MLS_CLS_CREATE_COMPARTMENT()函数创建安全隔离区(Compartment)。
SQL
SELECT MLS_CLS_CREATE_COMPARTMENT(policy_name,
compartment_id, short_name, long_name)
参数 描述 :
- policy_name(策略名称): 指定要添加安全隔离区的策略名称。
- compartment_id(隔离区ID): 用于标识安全隔离区的唯一ID,取值范围[0, 32767]。
- short_name(简称): 安全隔离区的简称。
- long_name(完整名称): 安全隔离区的完整名称。
安全组(Group)
通过MLS_CLS_CREATE_GROUP_ROOT()函数创建新的安全组根节点(Group Root)
SQL
SELECT MLS_CLS_CREATE_GROUP_ROOT(policy_name,
root_id, short_name, long_name)
参数描述:
-
policy_name(策略名称): 指定要创建安全组根节点的策略名称。
-
root_id(根节点ID): 用于标识安全组根节点的唯一ID。
-
short_name(简称): 安全组根节点的简称。
-
long_name(完整名称): 安全组根节点的完整名称。
通过MLS_CLS_CREATE_GROUP_NODE()函数在数据库中创建新的安全组子节点(Group Node)并将其设置为指定父节点的子节点。
SQL SELECT MLS_CLS_CREATE_GROUP_NODE(policy_name, child_id, short_name, long_name, parent_short_z)
参数描述:
- policy_name(策略名称): 指定要创建安全组子节点的策略名称。
- child_id(子节点ID): 用于标识安全组子节点的唯一ID。
- short_name(简称): 安全组子节点的简称。
- long_name(完整名称): 安全组子节点的完整名称。
- parent_short_name(父节点简称): 安全组子节点所属的父节点的简称。
标签(LABEL)
通过MLS_CLS_CREATE_LABEL()函数创建或替换MLS 策略的标签(label),并将其存储到数据库中。
SQL
SELECT MLS_CLS_CREATE_LABEL(policy_name, label_id, label_str)
参数描述:
-
policy_name(策略名称): 指定要添加标签的策略名称。
-
label_id(标签ID): 用于标识标签的唯一ID,取值范围[0, 32767]。
-
label_str(标签名): 标签,不可为空,长度不超过256。由<level_id(必选) : compartment_ids(可选) : group_ids(可选)>,其compartment_ids和group_ids由1到N个ID构成,ID间用,分割。有效的表达形式如下:
- level_id:compartment_id1,compartmen_tid2,...compartment_idN:group_id1,group_id2,...group_idN
- level_id:compartment_id:group_id
- level_id:compartment_id:
- level_id::group_id
- level_id::
表标签绑定
通过MLS_CLS_CREATE_TABLE_LABEL()函数将指定标签绑定到指定的表(Table),并将相关数据存储到pg_cls_table系统表。
SQL
SELECT MLS_CLS_CREATE_TABLE_LABEL(policy_name
labelid, schema_name, table_name)
参数描述:
- policy_name(策略名称): 指定要应用的策略名称。
- labelid(标签ID): 要应用于表的标签ID,取值范围[0, 32767]。
- schema_name(模式名称): 表所在的模式名。
- table_name(表格名称): 要应用标签的表名。
通过MLS_CLS_DROP_TABLE_LABEL()函数删除绑定到表上的标签并更新pg_cls_table系统表数据。
SQL
MLS_CLS_DROP_TABLE_LABEL(policy_name, schema_name, table_name)
用户标签绑定/删除
通过MLS_CLS_CREATE_USER_LABEL()函数为指定的用户创建一个带有默认标签的用户账户,并将其存储到 pg_cls_user 表中。
SQL
SELECT MLS_CLS_CREATE_USER_LABEL(policy_name,
username name,
def_read_label,
def_write_label,
def_row_label)
参数描述:
- policy_name(策略名称): 指定要应用的策略名称。
- username(用户名): 要创建标签的用户账户名称。
- def_read_label(默认读标签): 为用户定义的默认读标签ID。
- def_write_label(默认写标签): 为用户定义的默认写标签ID。
- def_row_label(默认行标签): 为用户定义的默认行标签ID。
通过MLS_CLS_DROP_USER_LABEL()函数为指定用户删除标签,并将pg_cls_user 表中指定用户的标签删除,且断开指定用户当前所有的数据库连接。
SQL
SELECT MLS_CLS_DROP_USER_LABEL(user_name)
参数描述:
- user_name(用户名): 要删除指定用户标签的用户账户名称。
示例:
初始化环境
SQL
\c - mls_admin-- 创建安全策略
select MLS_CLS_CREATE_POLICY('rls_policy', 66);
-- 创建安全等级
select MLS_CLS_CREATE_LEVEL('rls_policy', 10, 'default_level', 'default Level');
select MLS_CLS_CREATE_LEVEL('rls_policy', 10, 'user_level', 'user Level');
select MLS_CLS_CREATE_LEVEL('rls_policy', 9, 'bad_level', 'bad Level');
select MLS_CLS_CREATE_LEVEL('rls_policy', 100, 'good_level', 'good Level');
-- 创建隔离区
select MLS_CLS_CREATE_COMPARTMENT('rls_policy', 30, 'rls_com0', 'RLS compartment 0');
select MLS_CLS_CREATE_COMPARTMENT('rls_policy', 31, 'rls_com1', 'RLS compartment 1');
select MLS_CLS_CREATE_COMPARTMENT('rls_policy', 32, 'rls_com2', 'RLS compartment 2');
-- 创建安全组
select MLS_CLS_CREATE_GROUP_ROOT('rls_policy', 50, 'root', 'group root');
select MLS_CLS_CREATE_GROUP_NODE('rls_policy', 51, 'child1', 'child of root node 1', 'root');
select MLS_CLS_CREATE_GROUP_NODE('rls_policy', 52, 'child2', 'child of root node 2', 'root');
select MLS_CLS_CREATE_GROUP_NODE('rls_policy', 511, 'child11', 'child of child1 node 1', 'child1');
select MLS_CLS_CREATE_GROUP_NODE('rls_policy', 512, 'child12', 'child of child1 node 2', 'child1');
-- 创建安全标签,此时和安全等级,隔离区以及安全组进行绑定
select MLS_CLS_CREATE_LABEL('rls_policy', 1024, 'default_level:rls_com0:child12');
-- 将标签绑定到表
alter table public.tbl1 add column _cls clsitem default '99:1024';
select MLS_CLS_CREATE_TABLE_LABEL('rls_policy', 1024, 'public', 'tbl1');
安全等级
SQL
select MLS_CLS_CREATE_LABEL('rls_policy', 1025, 'user_level::');
select MLS_CLS_CREATE_LABEL('rls_policy', 1026, 'bad_level::');
select MLS_CLS_CREATE_LABEL('rls_policy', 1027, 'good_level::');
-- 将标签绑定到用户
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'godlike1', 1024, 1024, 1024);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'godlike2', 1025, 1025, 1025);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'badgodlike1', 1026, 1026, 1026);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'goodgodlike1', 1027, 1027, 1027);
SQL
\c - godlike1
insert into public.tbl1 select generate_series(1,3), generate_series(1,3);
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:1024
2 | 2 | 66:1024
3 | 3 | 66:1024
(3 rows)
SQL
\c - godlike2
insert into public.tbl1 select generate_series(4,6), generate_series(4,6);
-- 当前用户不在隔离区,无法看到godlike1用户创建的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
4 | 4 | 66:1025
5 | 5 | 66:1025
6 | 6 | 66:1025
(3 rows)
SQL
\c - badgodlike1
-- 低优先级的用户无法看到高优先级的用户插入的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+------
(0 rows)
SQL
insert into public.tbl1 select generate_series(7,9), generate_series(7,9);
-- 低优先级用户可以看到自己创建的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
7 | 7 | 66:1026
8 | 8 | 66:1026
9 | 9 | 66:1026
(3 rows)
SQL
\c goodgodlike1
-- 高优先级用户可以看到低优先级用户创建的数据
-- 同时无法看到隔离区的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
4 | 4 | 66:1025
5 | 5 | 66:1025
6 | 6 | 66:1025
7 | 7 | 66:1026
8 | 8 | 66:1026
9 | 9 | 66:1026
(6 rows)
SQL
insert into public.tbl1 select generate_series(10,12), generate_series(10,12);
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
4 | 4 | 66:1025
5 | 5 | 66:1025
6 | 6 | 66:1025
7 | 7 | 66:1026
8 | 8 | 66:1026
9 | 9 | 66:1026
10 | 10 | 66:1027
11 | 11 | 66:1027
12 | 12 | 66:1027
(9 rows)
SQL
\c - godlike1
-- 高优先级用户可以看到比自己低优先级用户创建的数据
-- 无法看到比自己优先级高的用户创建的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:1024
2 | 2 | 66:1024
3 | 3 | 66:1024
4 | 4 | 66:1025
5 | 5 | 66:1025
6 | 6 | 66:1025
7 | 7 | 66:1026
8 | 8 | 66:1026
9 | 9 | 66:1026
(9 rows)
SQL
\c - common_user0
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+------
(0 rows)
安全隔离区
SQL
\c - mls_admin
select MLS_CLS_DROP_USER_LABEL('godlike1');
select MLS_CLS_DROP_USER_LABEL('godlike2');
select MLS_CLS_DROP_USER_LABEL('badgodlike1');
select MLS_CLS_DROP_USER_LABEL('goodgodlike1');
-- 创建安全标签,并绑定隔隔离区
select MLS_CLS_CREATE_LABEL('rls_policy', 2048, 'default_level:rls_com0:');
select MLS_CLS_CREATE_LABEL('rls_policy', 2049, 'default_level:rls_com0,rls_com1,rls_com2:');
select MLS_CLS_CREATE_LABEL('rls_policy', 2050, 'default_level:rls_com1,rls_com2:');
select MLS_CLS_CREATE_LABEL('rls_policy', 2051, 'default_level:rls_com0,rls_com2:');
-- 将标签绑定到用户
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'godlike1', 2048, 2048, 2048);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'godlike2', 2049, 2049, 2049);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'badgodlike1', 2050, 2050, 2050);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'goodgodlike1', 2051, 2051, 2051);
SQL
\c - godlike1
insert into public.tbl1 select generate_series(1,3), generate_series(1,3);
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:2048
2 | 2 | 66:2048
3 | 3 | 66:2048
(3 rows)
SQL
\c - godlike2
insert into public.tbl1 select generate_series(4,6), generate_series(4,6);
-- 当前用户所在隔离区含godlike1用户隔离区,可以看到godlike1的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:2048
2 | 2 | 66:2048
3 | 3 | 66:2048
4 | 4 | 66:2049
5 | 5 | 66:2049
6 | 6 | 66:2049
(6 rows)
SQL
\c - badgodlike1
insert into public.tbl1 select generate_series(7,9), generate_series(7,9);
-- 当前用户所在隔离区无法包含前面用户的隔离区,无法看到他们插入的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
7 | 7 | 66:2050
8 | 8 | 66:2050
9 | 9 | 66:2050
(3 rows)
SQL
\c - goodgodlike1
insert into public.tbl1 select generate_series(10,12), generate_series(10,12);
-- 相同等级,godlike1的隔离区是当前的子集,当前用户可以看到godlike1插入的数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:2048
2 | 2 | 66:2048
3 | 3 | 66:2048
10 | 10 | 66:2051
11 | 11 | 66:2051
12 | 12 | 66:2051
(6 rows)
SQL
\c - godlike2
-- 当前用户含rls_com0,rls_com1,rls_com2三个隔离区可以看到之前插入的所有数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:2048
2 | 2 | 66:2048
3 | 3 | 66:2048
4 | 4 | 66:2049
5 | 5 | 66:2049
6 | 6 | 66:2049
7 | 7 | 66:2050
8 | 8 | 66:2050
9 | 9 | 66:2050
10 | 10 | 66:2051
11 | 11 | 66:2051
12 | 12 | 66:2051
(12 rows)
安全组
SQL
\c - mls_admin
select MLS_CLS_DROP_USER_LABEL('godlike1');
select MLS_CLS_DROP_USER_LABEL('godlike2');
select MLS_CLS_DROP_USER_LABEL('badgodlike1');
select MLS_CLS_DROP_USER_LABEL('goodgodlike1');
-- 创建安全标签,并绑定用户组
select MLS_CLS_CREATE_LABEL('rls_policy', 4096, 'default_level:rls_com0:root');
select MLS_CLS_CREATE_LABEL('rls_policy', 4097, 'default_level:rls_com0:child1');
select MLS_CLS_CREATE_LABEL('rls_policy', 4098, 'default_level:rls_com0:child11,child12');
-- 将标签绑定到用户
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'godlike1', 4096, 4096, 4096);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'godlike2', 4097, 4097, 4097);
select MLS_CLS_CREATE_USER_LABEL('rls_policy', 'badgodlike1', 4098, 4098, 4098);
SQL
\c - badgodlike1
insert into public.tbl1 select generate_series(1,3), generate_series(1,3);
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:4098
2 | 2 | 66:4098
3 | 3 | 66:4098
(3 rows)
SQL
\c - godlike2
insert into public.tbl1 select generate_series(4,6), generate_series(4,6);
-- 安全组根节点可以看到子节点数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:4098
2 | 2 | 66:4098
3 | 3 | 66:4098
4 | 4 | 66:4097
5 | 5 | 66:4097
6 | 6 | 66:4097
(6 rows)
SQL
\c - godlike1
insert into public.tbl1 select generate_series(7,9), generate_series(7,9);
-- 安全组根节点可以看到所有子节点数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:4098
2 | 2 | 66:4098
3 | 3 | 66:4098
4 | 4 | 66:4097
5 | 5 | 66:4097
6 | 6 | 66:4097
7 | 7 | 66:4096
8 | 8 | 66:4096
9 | 9 | 66:4096
(9 rows)
SQL
\c - badgodlike1
-- 子节点 无法看到根节点数据
select * from public.tbl1 order by col1;
col1 | col2 | _cls
------+------+---------
1 | 1 | 66:4098
2 | 2 | 66:4098
3 | 3 | 66:4098
(3 rows)