強制訪問是基于自定義的安全策略最終通過標簽實現對用戶和表的行級安全加密。安全策略(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)