ESP
外部安全提供者
此页面用于讨论 PostgreSQL 中的 ESP
概述
ESP(外部安全提供者)是支持 PostgreSQL 中的附加访问控制功能的想法。
它试图将现有的(默认 PG)访问控制重新组织为结构良好的安全函数,并将主要逻辑修改为在访问控制上调用安全函数。
主要而言,它旨在将 **如何** 检查权限与 **什么** 被检查权限分开。
例如,默认 PG 模型对创建新表应用以下检查。
- ACL_CREATE在新建表的命名空间上。
- ACL_CREATE在新表的表空间上,如果明确给出。
- 如果新建表继承了父表,则拥有父表的权限。
目前,这些检查内嵌在DefineRelation()和MergeAttributes()中,分别进行。ESP 试图将它们移到一个单独的安全函数中,并用新的安全函数替换对pg_xxx_aclcheck()和pg_xxx_ownercheck()的调用。
示例
void check_relation_create(....) { /* * Check ACL_CREATE of the namespace of the new relation */ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresul != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); /* * Check ACL_CREATE of the tablespace, if explicitly given */ if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace) { aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_TABLESPACE, get_tablespace_name(tablespaceId)); } /* * Check ownership of the parent table, if inherited */ foreach (l, inheritOids) { if (!pg_class_ownercheck(lfirst_oid(l), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, get_rel_name(lfirst_oid(l))); } }
在本例中,主要逻辑 (DefineRelation()) 调用check_relation_create(),并提供所有必要的创建表的信息以做出访问控制决策,然后check_relation_create()根据规范检查用户的权限。
这意味着check_relation_create()将如何检查权限从调用者中封装起来。调用者只知道一系列权限检查的结果,即创建新表是否被允许。
优势
新的安全函数将充当可选安全提供者的入口点。
在我们的社区中,精通各种安全模型的人并不占多数。因此,如果我们直接在主逻辑上放置外部安全提供者的挂钩,当我们重构主逻辑时可能会导致错误。
然而,只要这些外部安全功能是从结构良好的安全函数中调用的,其含义就清晰明了。因此,我们可以避免源代码管理中的问题。
主要示例
我们已经知道一些支持结构良好的安全函数的开源软件。
- Linux - LSM(Linux 安全模块)
- 适用于 v2.6.x 系列
- 已知安全提供者
- Root 能力
- SELinux
- Smack
- TOMOYO Linux
- AppArmor(尚未合并)
- Xorg - XACE(X 访问控制扩展)
- 适用于 X11R7.2 或更高版本
- 已知安全提供者
- SELinux
LSM 旨在承载可选的 MAC 安全功能,但它不整合现有的 DAC 权限检查。因此,如果没有 MAC 安全功能可用,它将只是存根。
XACE 旨在承载默认的 DAC 安全功能和可选的 MAC 安全功能。它共享通用的安全挂钩。
上游步骤
步骤 1:访问控制重构
在此阶段,我们将现有的 PG 访问控制功能重构为结构良好的安全函数,没有外部安全提供者。
在大多数情况下,这将是一个简单的逐一替换。
如果在对某个数据库对象进行操作时检查了多个 PG 权限,我们将尽快调用新的安全函数,只要我们能够解决所有必要的信息。
问题
- 补丁大小
- 如果我们试图一次重构所有访问控制,补丁规模将变得过大,难以审查。
- 补丁应该按对象类进行划分。例如)对模式、关系、类型等的重构。
- 应该传递哪些参数给 ESP 例程?
- 做出访问控制决策所需的所有信息。
- 参数的数量会无限增加吗?当提出新的安全提供者时,如果它需要过于奇怪的参数,我们可以提出建议。
步骤 2:安全标签支持
为了承载基于标签的 MAC 功能,PostgreSQL 需要提供在数据库对象上分配标签的功能。标签类似于默认 PG 安全中使用的 owner-id 和数据库 ACL。它用于标识数据库对象的安全性属性,基于标签的 MAC 功能根据标签做出决策。在 SELinux 中,我们称标签为安全上下文。但标签在一般情况下是一个更中性的名称。
示例)
postgres=# SELECT security_label, relname, relkind FROM pg_class WHERE relname = 't1'; security_label | relname | relkind ------------------------------------------+---------+--------- unconfined_u:object_r:sepgsql_table_t:s0 | t1 | r (1 row)
问题
- 在行级访问控制不可用时,系统列不需要可写。
步骤 3:添加外部安全提供者
我们应该在步骤 1 中重构的安全函数上添加外部安全提供者的入口点。
问题
- 哪种实现方式更可取?内置?还是可加载模块?