支持的版本:当前 (17) / 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 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;此外,还会检查 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;

在这里,将检查 t1.xdb_column:update,因为它正在被更新,将检查 t1.ydb_column:{select update},因为它既被更新又被引用,将检查 t1.zdb_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 简介

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

SELinux 用户和管理员指南

本文档提供了在您的系统上管理 SELinux 的广泛知识。它主要侧重于 Red Hat 操作系统,但不限于这些系统。

Fedora SELinux 常见问题解答

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

F.38.9. 作者 #

KaiGai Kohei

提交更正

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