F.33. sepgsql
sepgsql
是一个可加载的模块,支持基于标签的强制访问控制(MAC), 以SELinux安全策略为基础。
Warning |
---|
当前的实现有很大的局限性,并不为所有的动作都执行强制访问控制。 参阅Section F.33.7。 |
F.33.1. 概述
这个模块与SELinux结合,提供一个PostgreSQL 正常提供的安全检查的附加层。从SELinux来看,这个模块允许 PostgreSQL起到用户空间对象管理者的作用。 DML查询发起的每个表和函数访问都将针对系统安全策略做检查。 这个检查是PostgreSQL执行的通常的SQL权限检查之外的东西。
SELinux访问控制决策利用安全标签, 以字符串表示,如system_u:object_r:sepgsql_table_t:s0
。 每个访问控制决策包含两个标签:尝试执行动作的主题的标签, 和要被执行操作的对象的标签。因为这些标签可以用于任意类型的对象, 所以存储在数据库中的对象的访问控制决策会(用这个模块是这样的) 和任意其他类型的对象(比如,文件)一样使用通用标准。 这个设计是为了允许集中的安全策略保护信息资产独立于这些资产的存储细节。
SECURITY LABEL语句允许分配安全标签给数据库对象。
F.33.2. 安装
sepgsql
只能用于Linux 2.6.28 或更高的启用SELinux的系统。 在其他的平台上不能使用。也需要libselinux 2.1.10 或更高版本和selinux-policy 3.9.13或更高版本 (尽管一些分支可以移植需要的规则到老的政策版本)。
sestatus
命令允许检查SELinux的状态。 一个典型的显示是:
$ sestatus
SELinux status: enabled
SELinuxfs mount: /selinux
Current mode: enforcing
Mode from config file: enforcing
Policy version: 24
Policy from config file: targeted
如果禁用了SELinux或者没有安装SELinux, 那么必须在安装这个模块之前先配置该产品。
要建立这个模块,在你的PostgreSQL configure
命令中包含选项 --with-selinux
。确保在建立时已经安装了 libselinux-devel
RPM。
要使用这个模块,必须在postgresql.conf
的 shared_preload_libraries参数中包含了sepgsql
。 如果以任何其他方式加载,该模块将不会正确的运行。一旦加载了该模块, 你应该在每个数据库中执行sepgsql.sql
。 这将安装安全标签管理需要的函数,并且分配最初的安全标签。
这里是一个示例,显示如何用sepgsql
函数和安装的安全标签初始化新的数据库集群。 为你的安装适当的调整显示的路径:
$ export PGDATA=/path/to/data/directory
$ initdb
$ vi $PGDATA/postgresql.conf
change
#shared_preload_libraries = '' # (change requires restart)
to
shared_preload_libraries = 'sepgsql' # (change requires restart)
$ for DBNAME in template0 template1 postgres; do
postgres --single -F -c exit_on_error=true $DBNAME \
</usr/local/pgsql/share/contrib/sepgsql.sql >/dev/null
done
请注意,你可能会看到一些或者所有下列的通知,取决于你的 libselinux和selinux-policy版本:
/etc/selinux/targeted/contexts/sepgsql_contexts: line 33 has invalid object type db_blobs
/etc/selinux/targeted/contexts/sepgsql_contexts: line 36 has invalid object type db_language
/etc/selinux/targeted/contexts/sepgsql_contexts: line 37 has invalid object type db_language
/etc/selinux/targeted/contexts/sepgsql_contexts: line 38 has invalid object type db_language
/etc/selinux/targeted/contexts/sepgsql_contexts: line 39 has invalid object type db_language
/etc/selinux/targeted/contexts/sepgsql_contexts: line 40 has invalid object type db_language
这些信息是无害的,应该忽略。
如果安装进程没有错误的完成了,那么你现在可以正常的启动服务器。
F.33.3. 回归测试
由于SELinux的性质,为sepgsql
运行回归测试需要几个额外的配置步骤,其中一些必须作为root用户完成。 回归测试不通过一个普通的make check
或make installcheck
命令来运行;你必须设置配置,然后手动的调用测试脚本。 测试必须在配置的PostgreSQL构造树的contrib/sepgsql
目录中运行。 尽管他们需要一个构造树,但是测试的目的是针对一个已经安装的服务器执行的, 这点他们可以与make installcheck
作比较。
第一步,根据Section F.33.2中的指示, 在一个运行的数据库中设置sepgsql
。 请注意,当前的操作系统用户必须能够作为超级用户不需要密码认证的连接到数据库。
第二步,为回归测试建立和安装策略包。sepgsql-regtest
策略是一个特定用途的策略包, 提供了一组在回归测试期间被允许的规则。应该从策略源文件sepgsql-regtest.te
中建立,使用make
和SELinux提供的Makefile来实现。 你需要在你的系统上定位适当的Makefile;下面显示的路径只是一个示例。 一旦建立,使用semodule
命令安装这个策略包, 它加载提供的策略包到内核中。如果策略包正确的安装了, 那么semodule
-l应该会将 sepgsql-regtest
作为一个可用的策略包列出:
$ cd .../contrib/sepgsql
$ make -f /usr/share/selinux/devel/Makefile
$ sudo semodule -u sepgsql-regtest.pp
$ sudo semodule -l | grep sepgsql
sepgsql-regtest 1.07
第三步,打开sepgsql_regression_test_mode
。 出于安全考虑,sepgsql-regtest
中的规则缺省是不启用的; sepgsql_regression_test_mode
参数启用需要发出回归测试的规则。 可以使用setsebool
命令打开:
$ sudo setsebool sepgsql_regression_test_mode on
$ getsebool sepgsql_regression_test_mode
sepgsql_regression_test_mode --> on
第四步,验证你的shell是在unconfined_t
域中运行:
$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
如果需要,请参阅Section F.33.8获取调整你的工作域的详细信息。
最后,运行回归测试脚本:
$ ./test_sepgsql
这个脚本将尝试验证你已经正确的做了所有的配置步骤, 然后它将为sepgsql
模块运行归回测试。
完成测试之后,建议你禁用sepgsql_regression_test_mode
参数:
$ sudo setsebool sepgsql_regression_test_mode off
你可能想要彻底删除sepgsql-regtest
策略:
$ sudo semodule -r sepgsql-regtest
F.33.4. GUC 参数
sepgsql.permissive
(boolean
)
这个参数使得sepgsql
能够在许可的模式运行,无视系统的设置。 缺省为off。这个参数只能在postgresql.conf
文件中或者在服务器的命令行设置。
当这个参数为on时,sepgsql
函数在许可模式, 即使SELinux通常运行在强制模式。这个参数对于测试目的尤其有用。
sepgsql.debug_audit
(boolean
)
这个参数启用审计信息的打印,无视系统策略设置。缺省是off, 意味着信息将根据系统设置来打印。
SELinux的安全策略也有规则控制是否记录特殊的访问。 缺省的,只记录违规的访问。
这个参数强制打开所有可能的记录,无视系统的策略。
F.33.5. 特性
F.33.5.1. 控制对象类
SELinux的安全模型描述了所有的访问控制规则, 作为主题的实体(通常,数据库的一个客户端)和对象的实体(比如一个数据库对象) 的关系,每一个都由安全标签来鉴别。如果尝试访问一个没有标签的对象, 那么该对象被当做是分配了unlabeled_t
标签。
目前,sepgsql
允许分配安全标签给模式、表、字段、序列、 视图和函数。当正在使用sepgsql
时, 自动分配安全标签给在创建时支持的数据库对象。这个标签被称为缺省的安全标签, 并且是根据系统的安全策略决定的,数据库会拿这个系统的安全策略输入来当作创建人的标签, 该标签分配给新对象的父对象,并且可以选择以构造对象名来命名。
一个新的数据库对象基本上继承父对象的安全标签,除了安全策略有特殊的类型转换规则时, 会应用一个不同的标签。对于模式来说,父对象是当前数据库;对于表、序列、视图和函数, 是包含的模式;对于字段,是包含的表。
F.33.5.2. DML 权限
对于表,db_table:select
、db_table:insert
、 db_table:update
或db_table:delete
,根据语句的类型, 为所有引用的目标表做检查;另外,db_table:select
也为所有在WHERE
或RETURNING
子句中的包含字段引用的表做检查, UPDATE
的数据源也是如此,等等。
也将为每个引用的字段检查字段级别的权限。db_column:select
不只是检查被SELECT
读取的字段,也检查在其他DML语句中引用的字段; db_column:update
或db_column:insert
也将检查被UPDATE
或INSERT
修改的字段。
例如,考虑:
UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
这里,db_column:update
将为t1.x
做检查, 因为它被更新了,db_column:{select update}
将为t1.y
做检查,因为它被更新和引用了, db_column:select
将为t1.z
做检查, 因为它被引用了。db_table:{select update}
也将在表级别做检查。
对于序列,当我们使用SELECT
引用一个序列对象时,对 db_sequence:get_value
做检查;不过,请注意, 我们当前不检查执行对应的函数的权限,如lastval()
。
对于视图,将检查db_view:expand
, 然后任何其他需要的权限都将分别在从视图扩展的对象上做检查。
对于函数,当用户尝试将函数作为查询的一部分执行,或使用快速路径调用时, 会对db_procedure:{execute}
做检查。如果这个函数是一个受信任的程序, 那么也会检查db_procedure:{entrypoint}
的权限, 看看它是否可以作为受信任的程序的入口点来执行。
为了访问任意模式对象,在包含的模式上需要db_schema:search
权限。 当不带有模式限定的引用一个对象时,这个模式的权限没有出现将不会被搜索 (就好像用户在这个模式上没有USAGE
权限)。 如果给出了明确的模式限定,如果用户在命名的模式上没有必需的权限, 那么将会出现一个错误。
客户端必须被允许访问所有引用的表和字段,即使它们起源于随后扩张的视图, 所以我们应用一致的访问控制规则,独立于引用表内容的方式。
缺省的数据库权限系统允许数据库超级用户使用DML命令修改系统目录, 引用和修改toast表。当启用sepgsql
时,禁止这些操作。
F.33.5.3. DDL 权限
SELinux为每个对象类型定义了几个控制一般操作的权限;比如创建、 修改、删除和重新贴安全标签。另外,几个对象类型有特殊的权限控制它们的典型操作; 如在一个特别的模式中添加或删除名字入口。
创建一个新的数据库对象需要create
权限。SELinux 将根据客户端的安全标签授予或拒绝这个权限,并且为新的对象拟建安全标签。 在某些情况下,需要额外的权限:
CREATE DATABASE还需要源或模板数据库的
getattr
权限。创建一个模式对象还需要在父模式上有
add_name
权限。创建一个表还需要有权限创建每个单独的表字段,就好像每个表字段是一个独立的顶级对象。
创建一个标记为
LEAKPROOF
的函数还需要install
权限。 (当为一个现有的函数设置LEAKPROOF
时,也需要检查这个权限。)
当执行DROP
命令时,将在要被删除的对象上检查drop
。 也要检查通过CASCADE
直接删除的对象的权限。 包含在特定模式(表、视图、序列和程序)中对象的删除还需要在该模式上的remove_name
。
当执行ALTER
命令时,将为每个对象类型的被修改的对象检查setattr
, 除了附属的对象,如表的索引或触发器,这里的权限是在父对象上检查的。 在某些情况下,需要额外的权限:
移动一个对象到新的模式还需要在旧的模式上有
remove_name
权限, 和在新的模式上有add_name
权限。在一个函数上设置
LEAKPROOF
属性需要install
权限。在一个对象上使用SECURITY LABEL还需要在与老的安全标签结合的对象上有
relabelfrom
权限,和在与新的安全标签结合的对象上有relabelto
权限。 (在安装了多个标签提供者和用户尝试设置一个安全标签,但不被SELinux 管理的情况下,只应该检查setattr
。这是由于实现的限制,目前没有做到的。)
F.33.5.4. 受信任的程序
受信任的程序类似于安全定义函数或setuid命令。SELinux 提供一个特性,允许受信任的代码使用一个不同于客户端的安全标签运行, 通常是为了提供到敏感数据的高度控制的访问(例如,可能会忽略行, 或者存储值的精度可能会减少)。一个函数是否作为受信任的程序动作, 是由它的安全标签和操作系统安全策略控制的。例如:
postgres=# CREATE TABLE customer (
cid int primary key,
cname text,
credit text
);
CREATE TABLE
postgres=# SECURITY LABEL ON COLUMN customer.credit
IS 'system_u:object_r:sepgsql_secret_table_t:s0';
SECURITY LABEL
postgres=# CREATE FUNCTION show_credit(int) RETURNS text
AS 'SELECT regexp_replace(credit, ''-[0-9]+$'', ''-xxxx'', ''g'')
FROM customer WHERE cid = $1'
LANGUAGE sql;
CREATE FUNCTION
postgres=# SECURITY LABEL ON FUNCTION show_credit(int)
IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
SECURITY LABEL
以上的操作应该由管理员用户执行。
postgres=# SELECT * FROM customer;
ERROR: SELinux: security policy violation
postgres=# SELECT cid, cname, show_credit(cid) FROM customer;
cid | cname | show_credit
-----+--------+---------------------
1 | taro | 1111-2222-3333-xxxx
2 | hanako | 5555-6666-7777-xxxx
(2 rows)
在这种情况下,普通用户不能直接引用customer.credit
, 但是一个受信任的程序show_credit
允许他带有一些数字标记的打印客户的信用卡号码。
F.33.5.5. 动态域转换
使用SELinux的动态域转换特性来转换客户端程序、客户端域的安全标签到一个新的内容是可能的, 如果安全策略允许这么做。客户端域需要setcurrent
权限, 还有从老的都新的域的dyntransition
权限。
动态域转换应该仔细考虑,因为他们允许用户转换他们的标签, 并且因此他们在选项上的权限不受系统的授权(在受信任的程序的情况下)。 因此,dyntransition
权限只在用于转换一个域到更小的权限集合时认为是安全的。 例如:
regression=# select sepgsql_getcon();
sepgsql_getcon
-------------------------------------------------------
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
(1 row)
regression=# SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-s0:c1.c4');
sepgsql_setcon
----------------
t
(1 row)
regression=# SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-s0:c1.c1023');
ERROR: SELinux: security policy violation
在上面的例子中,允许我们从较大的MCS范围c1.c1023
转换到较小的范围c1.c4
,但是反过来转换就被拒绝了。
动态域转换和受信任的程序的组合使得一个有趣的用例满足连接池软件的典型的生命周期过程。 尽管你的连接池软件不能运行大多数的SQL命令,但是你可以允许它使用sepgsql_setcon()
函数从一个受信任的程序里面切换客户端的安全标签;可能需要一些证书批准切换客户端标签的请求。 之后,这个会话将会拥有目标用户的权限,而不是连接池的权限。该连接池可以稍后使用带有 NULL
参数的sepgsql_setcon()
函数恢复安全标签的改变, 再次从受信任的程序里面用适当的权限检查调用。 这里的要点是只有那个受信任的程序实际上拥有改变有效的安全标签的权限,并且给出适当的证书。 当然,对于安全的操作,证书的存储(表、过程定义或其他东西)必须防止越权访问。
F.33.5.6. 其他
我们拒绝LOAD命令包括一切, 因为加载的任何模块都能很容易的绕开安全策略实施。
F.33.6. Sepgsql 函数
Table F-27显示了可用的函数。
Table F-27. Sepgsql 函数
| sepgsql_getcon() returns text
| 返回客户端的域,客户端当前的安全标签。 |
| sepgsql_setcon(text) returns bool
| 如果安全策略允许,则切换当前会话的客户端的域到一个新的域。 也接受NULL
输入作为转换到客户端原来的域的一个请求。 |
| sepgsql_mcstrans_in(text) returns text
| 如果mcstrans进程正在运行,则转化给出的限定MLS/MCS范围为行格式。 |
| sepgsql_mcstrans_out(text) returns text
| 如果mcstrans进程正在运行,则转化给出的行MCS/MCS范围为限定的格式。 |
| sepgsql_restorecon(text) returns bool
| 为当前数据库中所有的对象设置初始的安全标签。参数可以是NULL, 或特定文件的名字用于系统默认的选择。 |
F.33.7. 限制
数据定义语言 (DDL) 权限
由于实现的限制,一些DDL操作不检查权限。
数据控制语言 (DCL) 权限
由于实现的限制,DCL操作不检查权限。
行级别的访问控制
PostgreSQL不支持行级别的访问;因此sepgsql
也不支持。
隐藏通道
sepgsql
没有试图隐藏某一对象的存在,即使不允许用户访问它。 例如,我们可以推断一个不可见对象的存在,根据主键冲突、外键冲突等, 虽然我们不能获得该对象的内容。最高机密表的存在不能被隐藏;我们只希望能隐藏它的内容。
F.33.8. 外部资源
这个wiki页提供了一个简要概述、安全设计、构造、管理和即将到来的特性。
这个文档提供了在你的系统上管理SELinux的广泛的知识。 它主要集中于Fedora,但是不局限于Fedora。
这个文档回答了关于SELinux的常见问题。 它主要集中于Fedora,但是不局限于Fedora。
F.33.9. 作者
KaiGai Kohei <[[email protected]](mailto:[email protected])>