2024 年 9 月 26 日: PostgreSQL 17 发布!
支持版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1

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

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

警告

当前实现存在重大限制,并且不会对所有操作强制执行强制访问控制。见 第 F.38.7 节

F.38.1. 概述 #

此模块与 SELinux 集成,以提供除 PostgreSQL 通常提供的安全检查之外的另一层安全检查。从 SELinux 的角度来看,此模块允许 PostgreSQL 充当用户空间对象管理器。由 DML 查询启动的每个表或函数访问都将针对系统安全策略进行检查。此检查是在 PostgreSQL 执行的常规 SQL 权限检查之外进行的。

SELinux 访问控制决策是使用安全标签做出的,安全标签由字符串表示,例如 system_u:object_r:sepgsql_table_t:s0。每个访问控制决策都涉及两个标签:尝试执行操作的主题的标签,以及要执行操作的对象的标签。由于这些标签可以应用于任何类型的对象,因此存储在数据库中的对象的访问控制决策可以(并且使用此模块时就是)受用于任何其他类型对象的相同一般标准约束,例如文件。此设计旨在允许集中式安全策略独立于存储这些资产的具体方式来保护信息资产。

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

F.38.2. 安装 #

sepgsql 只能在启用了 SELinuxLinux 2.6.28 或更高版本上使用。它在任何其他平台上都不可用。您还需要 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 被禁用或未安装,则必须先设置该产品才能安装此模块。

要构建此模块,请指定 --with-selinux(在使用 make 和 autoconf 时)或 -Dselinux={ auto | enabled | disabled }(在使用 meson 时)。确保在构建时安装了 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

请注意,您可能会看到以下一些或所有通知,具体取决于您所拥有的 libselinuxselinux-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.38.3. 回归测试 #

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

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

其次,构建并安装回归测试的策略包。该 sepgsql-regtest 策略是一个特殊用途的策略包,它提供了一组在回归测试期间允许的规则。它应该从策略源文件 sepgsql-regtest.te 构建,这可以通过使用 make 和 SELinux 提供的 Makefile 来完成。您需要在您的系统上找到合适的 Makefile;下面显示的路径只是一个示例。(此 Makefile 通常由 selinux-policy-develselinux-policy RPM 提供。)构建完成后,使用 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.38.8 节,了解有关根据需要调整工作域的详细信息。

最后,运行回归测试脚本

$ ./test_sepgsql

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

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

$ sudo setsebool sepgsql_regression_test_mode off

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

$ sudo semodule -r sepgsql-regtest

F.38.4. GUC 参数 #

sepgsql.permissive (boolean) #

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

当此参数打开时,即使 SELinux 通常在强制模式下工作,sepgsql 也会以允许模式运行。此参数主要用于测试目的。

sepgsql.debug_audit (boolean) #

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

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

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

F.38.5. 功能 #

F.38.5.1. 受控对象类 #

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

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

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

F.38.5.2. DML 权限 #

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

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

例如,考虑

UPDATE t1 SET x = 2, y = func1(y) WHERE z = 100;

这里,会检查 t1.x 是否具有 db_column:update 权限,因为它正在被更新,会检查 t1.y 是否具有 db_column:{select update} 权限,因为它被更新和引用,会检查 t1.z 是否具有 db_column:select 权限,因为它只被引用。还会在表级别检查 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.38.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.38.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.38.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() 函数切换客户端的安全标签;这应该需要一些凭据来授权切换客户端标签的请求。之后,此会话将具有目标用户的权限,而不是连接池程序的权限。连接池程序稍后可以通过再次使用 sepgsql_setcon()(使用 NULL 参数)来恢复安全标签更改,同样是从具有适当权限检查的受信任过程中调用。这里关键在于,只有受信任的过程实际具有更改有效安全标签的权限,并且只有在给出适当的凭据时才会这样做。当然,为了安全操作,凭据存储(表、过程定义或任何其他内容)必须受到保护,以防止未经授权的访问。

F.38.5.6. 杂项 #

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

F.38.6. Sepgsql 函数 #

表 F.30 显示了可用的函数。

表 F.30. 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,也可以是作为系统默认值的替代使用的 specfile 的名称。


F.38.7. 限制 #

数据定义语言 (DDL) 权限

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

数据控制语言 (DCL) 权限

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

行级访问控制

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

隐蔽通道

sepgsql 不会试图隐藏某个对象的存在,即使用户没有被授权引用它。例如,我们可以推断出不可见对象的,即使我们无法获得对象的内容。机密级别为最高机密的表的不能被隐藏;我们只能希望隐藏其内容。

F.38.8. 外部资源 #

SE-PostgreSQL 简介

此维基页面简要概述了安全设计、体系结构、管理和即将推出的功能。

SELinux 用户和管理员指南

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

Fedora SELinux 常见问题解答

本文档解答了有关 SELinux 的常见问题。它主要关注 Fedora,但不限于 Fedora。

F.38.9. 作者 #

KaiGai Kohei

提交更正

如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符或需要进一步说明,请使用 此表格 报告文档问题。