ESP

来自 PostgreSQL 维基
跳转到导航跳转到搜索

外部安全提供者

此页面用于讨论 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 中重构的安全函数上添加外部安全提供者的入口点。

问题

  • 哪种实现方式更可取?内置?还是可加载模块?