ESP

From PostgreSQL wiki
Jump to navigationJump to search

External Security Provider

This page is for discussion of ESP in PostgreSQL

Overview

ESP (External Security Provider) is an idea to support an additional access control feature in PostgreSQL.

It tries to reorganize existing (the default PG) access control into well structured security functions, and modify the main logic to call the security functions on access controls.

Primarily, it intends to separate how permissions are checked from what permissions are checked.

For example, the default PG model applies the following checks to create a new table.

  • ACL_CREATE on the namespace of the new table.
  • ACL_CREATE on the tablespace of the new table, if explicitly given.
  • Ownership of the parent tables, if the new table inherits them.

Currently, these checks are inlined within in DefineRelation() and MergeAttributes() individually. The ESP tries to moves them into a separate security function, and replace invocations of pg_xxx_aclcheck() and pg_xxx_ownercheck() by the new security function.

Example:

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)));
    }
}

In this example, the main logic (DefineRelation()) calls check_relation_create() with all the needed information to make access control decision, then check_relation_create() checks user's permissions according to the specifications.

It means the check_relation_create() encapsulates how permissions are checked from the caller. The caller knows only result of the series of permission checks whether the creation of new table is allowed, or not.

Benefits

The new security functions shall perform as entrypoints of optional security providers.

In our community, people who are good at various kind of security models are not majority. So, if we put hooks of the external security providers on the main logic directly, it may cause bugs when we reworks the main logic.

However, as long as these external security features are invoked from well frameworked security functions, its meanings are clear. So, we can avoid matters in source code management.

Leading examples

We already knows a few OSS software which support well frameworked security functions.

  • Linux - LSM (Linux Security Modules)
    • available at v2.6.x series
    • Known security provides
      • Root capability
      • SELinux
      • Smack
      • TOMOYO Linux
      • AppArmor (not merged yet)
  • Xorg - XACE (X Access Control Extension)
    • available at X11R7.2 or later
    • Known security providers
      • SELinux

LSM is designed to host an optional MAC security feature, but it does not integrate existing DAC permission checks. So, it works just stubs, when no MAC security feature is available.

XACE is designed to host both of the default DAC security feature and an optional MAC security feature. It shares common security hooks.

Steps to upstream

Step.1 Access control reworks

In this phase, we reworks existing PG access control facilities into well structured security functions, without any external security providers.

In most cases, it will be simple one-to-one replacement.

In the case when multiple PG permissions are checked on the operation to a certain database object, we will call the new security functions as soon as possible after we can resolve all the needed information.

Issues

  • Patch size
    • If we try to rework all the access control at once, the patch scale will growth too large to review.
    • The patch should be divided per object class basis. E.g) Reworks for schema, relation, types, ...
  • What parameters should be delivered to ESP routines?
    • All the needed information to make access control decision.
    • The number of parameters will increase infinitely? When a new security provider is proposed, we can make advice if it requires too strange parameters.

Step.2 Security label support

To host label based MAC features, it is necessary PostgreSQL to provide a capability to assign a label on database objects. The label is similar to owner-id and database-acls used in the default PG security. It is used to identify the security properties of the database object, and label based MAC feature makes decision based on the label. In SELinux, we call label security context. But label is more neutral name in generall.

Example)

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)

Issues

  • During row-level access control is not available, the system column does not need to be writable.

Step.3 Add external security providers

We shall add entrypoint of external security providers on the security functions reworked at step.1.

Issues

  • Which is preferable way to implement? built-in? or loadable-module?