Skip to content

F.40. sepgsql — 基于 SELinux 的标签强制访问控制 (MAC) 安全模块#

F.40.1. 概述
F.40.2. 安装
F.40.3. 回归测试
F.40.4. GUC 参数
F.40.5. 功能
F.40.6. Sepgsql 函数
F.40.7. 限制
F.40.8. 外部资源
F.40.9. 作者

sepgsql是一个可加载模块,它基于SELinux安全策略支持基于标签的强制访问控制 (MAC)。

警告

当前实现有很大的限制,并且不能对所有操作强制访问控制。请参见第 F.40.7 节

F.40.1. 概述#

此模块与SELinux集成,以提供一个额外的安全检查层,高于PostgreSQL通常提供的安全层。从SELinux的角度来看,此模块允许PostgreSQL作为用户空间对象管理器运行。由 DML 查询发起的每个表或函数访问都将根据系统安全策略进行检查。此检查是除了PostgreSQL执行的常规 SQL 权限检查之外的额外检查。

SELinux访问控制决策是使用安全标签做出的,这些标签由字符串表示,例如system_u:object_r:sepgsql_table_t:s0。每个访问控制决策涉及两个标签:尝试执行操作的主体的标签和要对其执行操作的对象的标签。由于这些标签可以应用于任何类型的对象,因此可以(并且通过此模块)将存储在数据库中的对象的访问控制决策置于与用于任何其他类型对象(例如文件)的相同通用标准之下。此设计旨在允许集中式安全策略保护信息资产,而不管这些资产如何存储。

SECURITY LABEL语句允许为数据库对象分配安全标签。

F.40.2. 安装#

sepgsql只能在启用SELinux的Linux2.6.28 或更高版本上使用。它在任何其他平台上均不可用。您还需要libselinux2.1.10 或更高版本以及selinux-policy3.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已禁用或未安装,您必须先设置该产品,然后再安装此模块。

要构建此模块,请在 PostgreSQLconfigure命令中包含选项--with-selinux。确保在构建时已安装libselinux-develRPM。

要使用此模块,您必须在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.40.3. 回归测试#

由于SELinux的特性,运行sepgsql的回归测试需要几个额外的配置步骤,其中一些必须以 root 身份完成。回归测试不会通过普通的make checkmake installcheck命令运行;您必须设置配置,然后手动调用测试脚本。测试必须在已配置的 PostgreSQL 构建树的contrib/sepgsql目录中运行。尽管它们需要一个构建树,但这些测试被设计为针对已安装的服务器执行,即它们类似于make installcheck而不是make check

首先,根据第 F.40.2 节中的说明在工作数据库中设置sepgsql。请注意,当前操作系统用户必须能够在没有密码身份验证的情况下以超级用户身份连接到数据库。

其次,为回归测试构建并安装策略包。sepgsql-regtest策略是一个特殊用途策略包,它提供了一组在回归测试期间允许的规则。它应该从策略源文件sepgsql-regtest.te中构建,使用 SELinux 提供的 Makefile 通过make完成。您需要在系统上找到合适的 Makefile;下面显示的路径只是一个示例。(此 Makefile 通常由selinux-policy-develselinux-policyRPM 提供。)构建完成后,使用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

有关在必要时调整工作域的详细信息,请参见第 F.40.8 节

最后,运行回归测试脚本

$ ./test_sepgsql

此脚本将尝试验证您是否已正确完成所有配置步骤,然后它将运行sepgsql模块的回归测试。

完成测试后,建议您禁用sepgsql_regression_test_mode参数

$ sudo setsebool sepgsql_regression_test_mode off

您可能更愿意完全删除sepgsql-regtest策略

$ sudo semodule -r sepgsql-regtest

F.40.4. GUC 参数#

sepgsql.permissive (boolean) #

无论系统设置如何,此参数都允许 sepgsql 以宽容模式运行。默认值为关闭。此参数只能在 postgresql.conf 文件或服务器命令行中设置。

当此参数打开时,即使 SELinux 整体上以强制模式运行,sepgsql 也会以宽容模式运行。此参数主要用于测试目的。

sepgsql.debug_audit (boolean) #

此参数允许打印审计消息,而不管系统策略设置如何。默认值为关闭,这意味着将根据系统设置打印消息。

SELinux 的安全策略还具有规则来控制是否记录特定访问。默认情况下,会记录访问违规,但不会记录允许的访问。

此参数强制打开所有可能的日志记录,而不管系统策略如何。

F.40.5. 功能#

F.40.5.1. 受控对象类#

SELinux的安全模型将所有访问控制规则描述为主体实体(通常是数据库的客户端)和对象实体(例如数据库对象)之间的关系,每个实体都由安全标签标识。如果尝试访问未标记的对象,则该对象将被视为已分配标签unlabeled_t

目前,sepgsql允许将安全标签分配给模式、表、列、序列、视图和函数。当使用sepgsql时,安全标签会在创建时自动分配给受支持的数据库对象。此标签称为默认安全标签,并根据系统安全策略确定,该策略将创建者的标签、分配给新对象父对象的标签以及构造对象的名称(可选)作为输入。

新的数据库对象基本上会继承父对象的安全性标签,除非安全策略具有称为类型转换规则的特殊规则,在这种情况下可能会应用不同的标签。对于模式,父对象是当前数据库;对于表、序列、视图和函数,是包含模式;对于列,是包含表。

F.40.5.2. DML 权限#

对于表,db_table:selectdb_table:insertdb_table:updatedb_table:delete会根据语句类型检查所有引用的目标表;此外,db_table:select还会检查所有包含WHERERETURNING子句中引用的列的表,作为UPDATE的数据源,依此类推。

还会检查每个引用列的列级权限。db_column:select不仅会检查使用SELECT读取的列,还会检查在其他 DML 语句中引用的列;db_column:updatedb_column:insert还会检查由UPDATEINSERT修改的列。

例如,考虑

UPDATE t1 SET x = 2, y = func1(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.40.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.40.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.40.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.40.5.6. 其他#

我们全面拒绝LOAD命令,因为加载的任何模块都可以轻松规避安全策略执行。

F.40.6. Sepgsql 函数#

表 F.31显示了可用函数。

表 F.31. Sepgsql 函数

函数

说明

sepgsql_getcon () → text

返回客户端域,即客户端的当前安全标签。

sepgsql_setcon ( text ) → boolean

如果安全策略允许,则将当前会话的客户端域切换到新域。它还接受 NULL 输入作为过渡到客户端原始域的请求。

sepgsql_mcstrans_in ( text ) → text

如果 mcstrans 守护程序正在运行,则将给定的限定 MLS/MCS 范围转换为原始格式。

sepgsql_mcstrans_out ( text ) → text

如果 mcstrans 守护程序正在运行,则将给定的原始 MLS/MCS 范围转换为合格格式。

sepgsql_restorecon ( text ) → boolean

为当前数据库中的所有对象设置初始安全标签。参数可以是 NULL,或者作为系统默认值替代项使用的规范文件名称。

F.40.7. 限制#

数据定义语言 (DDL) 权限

由于实现限制,某些 DDL 操作不会检查权限。

数据控制语言 (DCL) 权限

由于实现限制,DCL 操作不会检查权限。

行级访问控制

PostgreSQL 支持行级访问,但 sepgsql 不支持。

隐蔽信道

sepgsql 不会尝试隐藏某个对象的存在,即使用户不允许引用该对象。例如,即使我们无法获取对象的具体内容,我们也可以通过主键冲突、外键冲突等方式推断出不可见对象的存在。机密表的存在无法隐藏;我们只能希望隐藏其内容。

F.40.8. 外部资源#

SE-PostgreSQL 简介

此 wiki 页面提供了简要概述、安全设计、架构、管理和即将推出的功能。

SELinux 用户和管理员指南

此文档提供了广泛的知识,用于在系统上管理 SELinux。它主要关注 Red Hat 操作系统,但并不局限于此。

Fedora SELinux 常见问题解答

此文档回答了有关 SELinux 的常见问题。它主要关注 Fedora,但并不局限于 Fedora。

F.40.9. 作者#

KaiGai Kohei<[[email protected]](/cdn-cgi/l/email-protection#f69d979f91979fb6979dd89c86d8989395d895999b)>