sepgsql
是一个可加载的模块,它支持基于 SELinux 安全策略的基于标签的强制访问控制 (MAC)。
当前实现有明显的局限性,并且并非对所有操作都强制执行强制访问控制。请参阅 第 F.38.7 节。
此模块与 SELinux 集成,以提供高于 PostgreSQL 通常提供的安全检查的附加层。从 SELinux 的角度来看,此模块允许 PostgreSQL 作为用户空间对象管理器运行。由 DML 查询启动的每个表或函数访问都将根据系统安全策略进行检查。此检查是对 PostgreSQL 执行的常用 SQL 权限检查的补充。
SELinux 访问控制决策是使用安全标签做出的,安全标签由字符串表示,例如 system_u:object_r:sepgsql_table_t:s0
。每个访问控制决策都涉及两个标签:尝试执行操作的主体的标签,以及要对其执行操作的对象的标签。由于这些标签可以应用于任何类型的对象,因此可以(并且使用此模块,确实如此)对数据库中存储的对象的访问控制决策施加与任何其他类型对象(例如文件)相同的通用标准。此设计旨在允许集中式安全策略来保护信息资产,而与这些资产的存储方式无关。
SECURITY LABEL
语句允许将安全标签分配给数据库对象。
sepgsql
只能在启用了 SELinux 的 Linux 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
请注意,您可能会看到以下部分或全部通知,具体取决于您拥有的 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
这些消息是无害的,应该忽略。
如果安装过程完成且没有错误,您现在可以正常启动服务器。
由于 SELinux 的特性,运行 sepgsql
的回归测试需要几个额外的配置步骤,其中一些必须以 root 身份完成。回归测试不会通过普通的 make check
或 make installcheck
命令运行;您必须设置配置,然后手动调用测试脚本。这些测试必须在已配置的 PostgreSQL 构建树的 contrib/sepgsql
目录中运行。虽然它们需要构建树,但这些测试旨在针对已安装的服务器执行,也就是说,它们与 make installcheck
而不是 make check
相当。
首先,根据 第 F.38.2 节中的说明,在工作数据库中设置 sepgsql
。请注意,当前操作系统用户必须能够在没有密码身份验证的情况下以超级用户身份连接到数据库。
其次,构建并安装回归测试的策略包。sepgsql-regtest
策略是一个特殊用途的策略包,它提供了一组在回归测试期间允许的规则。它应该从策略源文件 sepgsql-regtest.te
构建,这是使用 make
和 SELinux 提供的 Makefile 完成的。您需要在您的系统上找到相应的 Makefile;下面显示的路径只是一个示例。(此 Makefile 通常由 selinux-policy-devel
或 selinux-policy
RPM 提供。)构建完成后,使用 semodule
命令安装此策略包,该命令将提供的策略包加载到内核中。如果包安装正确,
应该将 semodule
-lsepgsql-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
sepgsql.permissive
(boolean
) #此参数使 sepgsql
能够在宽容模式下运行,而不管系统设置如何。默认值为关闭。此参数只能在 postgresql.conf
文件中或在服务器命令行上设置。
当此参数打开时,即使 SELinux 通常在强制模式下工作,sepgsql
也在宽容模式下运行。此参数主要用于测试目的。
sepgsql.debug_audit
(boolean
) #此参数启用审计消息的打印,而不管系统策略设置如何。默认值为关闭,这意味着将根据系统设置打印消息。
SELinux 的安全策略还具有控制是否记录特定访问的规则。默认情况下,会记录访问冲突,但不记录允许的访问。
此参数强制打开所有可能的日志记录,而不管系统策略如何。
SELinux 的安全模型将所有访问控制规则描述为主体实体(通常是数据库的客户端)和对象实体(例如数据库对象)之间的关系,每个实体都由安全标签标识。如果尝试访问未标记的对象,则该对象将被视为已分配标签 unlabeled_t
。
目前,sepgsql
允许将安全标签分配给模式、表、列、序列、视图和函数。当使用 sepgsql
时,安全标签会在创建时自动分配给受支持的数据库对象。此标签称为默认安全标签,并根据系统安全策略决定,该策略将创建者的标签、分配给新对象父对象的标签以及可选的构造对象名称作为输入。
新的数据库对象基本上继承父对象的安全标签,除非安全策略具有称为类型转换规则的特殊规则,在这种情况下可能会应用不同的标签。对于模式,父对象是当前数据库;对于表、序列、视图和函数,它是包含它们的模式;对于列,它是包含它们的表。
对于表,会根据语句的类型检查所有引用的目标表的 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 = 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
时,禁止这些操作。
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
。由于实现限制,目前没有这样做。)
受信任的过程类似于安全定义者函数或 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
允许用户打印部分数字被屏蔽的客户的信用卡号。
如果安全策略允许,可以使用 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.30 显示了可用的函数。
表 F.30. Sepgsql 函数
函数 描述 |
---|
返回客户端域,即客户端的当前安全标签。 |
如果安全策略允许,则将当前会话的客户端域切换到新域。它也接受 |
如果 mcstrans 守护进程正在运行,则将给定的限定 MLS/MCS 范围转换为原始格式。 |
如果 mcstrans 守护进程正在运行,则将给定的原始 MLS/MCS 范围转换为限定格式。 |
为当前数据库中的所有对象设置初始安全标签。参数可以是 |
由于实现限制,某些 DDL 操作不检查权限。
由于实现限制,DCL 操作不检查权限。
PostgreSQL 支持行级访问,但 sepgsql
不支持。
sepgsql
不会试图隐藏某个对象的存在,即使用户不允许引用它。 例如,我们可以推断出不可见对象的存在,例如主键冲突、外键违反等的结果,即使我们无法获取对象的内容。 最高机密的表格的存在无法隐藏;我们只希望隐藏其内容。
此 Wiki 页面提供了简要概述、安全设计、体系结构、管理和即将推出的功能。
本文档提供了在您的系统上管理 SELinux 的广泛知识。它主要侧重于 Red Hat 操作系统,但不限于这些系统。
本文档回答了有关 SELinux 的常见问题。它主要侧重于 Fedora,但不限于 Fedora。
KaiGai Kohei <[email protected]>
如果您在文档中看到任何不正确、与您的特定功能体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。