rbactool.py

Role-based access control (RBAC) is only available in SciDB Enterprise Edition.

Use the rbactool.py script for saving and restoring SciDB access control information, independently of any save or restore of SciDB array data.  By default this script is located in /opt/scidb/<version>/bin/rbactool.py .

The scidb_backup.py script incorporates the functionality of rbactool.py.  If you use scidb_backup.py, you may not need to use rbactool.py.

Usage

rbactool.py [-h] [-A AUTHFILE] [-H HOST] [-f {afl,raw-json,json}] [-i INPUT]
                     [-p PORT] [-r] [-U USERNAME] [-v]
                     [dbname]

OptionExplanation
-A/--auth-file AUTHFILESciDB authentication file.  Only needed if the -r/--restore option is used.  See Using iquery in Security Mode.
-h/--helpPrint usage and help information.
-H/--host HOSTHost where the SciDB system catalog resides, usually the coordinator host.  Default is 127.0.0.1.
-f/--format FORMATDesired output format.  Default is JSON.
-i/--input FILEInput file, assumed to be in JSON format.
-p/--port PORTSystem catalog port.  Default is 5432.
-r/--restoreLoad the input data into Postgres. Requires both -i/--input and dbname arguments. Skips pre-existing entities to avoid accidental privilege escalation.
-U/--username USERPostgres role name for reading or modifying the system catalog.
-v/--verbosePrint more debugging information.
dbnameName of the Postgres database being used as the system catalog.

Operation Modes

Rbactool.py takes different actions depending on the presence or absence of the -i/--input, -r/--restore, and dbname  options.  The table below summarizes these operation modes.

--input ?dbname ?--restore ?Action
YN--Print the input file on stdout, in the format specified by -f/--format .
NY--Print the contents of the system catalog access control tables in the format specified by -f/--format .
YYN

Compare the input file against the contents of the system catalog, and print only the access control information present in the input file but not in the system catalog.  That is, print the access control information that would be created if we were restoring this input file, or if we were using scidb_backup.py to restore a backup archive with %rbac.json equivalent to the input file.

 This "dry run" mode shows what access control would have been restored had the -r/--restore option been given.

YYYCompare the input file against the contents of the system catalog, compute the access control information present in the input file but not in the system catalog, and execute AFL queries to add that access control information to the system catalog.  Your SciDB account must have sufficient privileges to execute the generated AFL.

The first three modes are display modes, printing access control information from a file or from the system catalog, or printing the difference between the two.  The last mode is restore mode, and actually updates the system catalog with access control information from a file.  The scidb_backup.py script uses the same code path as rbactool.py's restore mode when restoring access control information from a backup archive's %rbac.json metadata file.

Restore Mode Avoids Privilege Escalation

In restore mode, not all of the input file's contents are injected into the catalog.  Instead, restore mode  takes a conservative approach to avoid accidental privilege escalation.  In particular:

  1. If a role, user, role membership, or namespace in the input file is already in the catalog, it will not be restored.  This avoids "already exists" or "already belongs to role" errors for those entities.
  2. If a user was not restored because the user already exists in the catalog, then none of the user's role memberships will be restored from the input file.  Restore mode assumes that if a user exists in the catalog, that user's access permissions are correct as-is and should not be modified.
  3. If a role was not restored because the role already exists in the catalog, then none of the role's permission entries for pre-existing namespaces will be restored from the input file.  Restore mode assumes that if a role exists in the catalog, that role's access permissions are correct as-is and should not be modified.  The role's permissions for any namespaces restored from backup will be restored, however.
  4. Permissions (that is, <namespace, role, rights> triples) in the input file are not restored if the catalog already contains a permission for that <namespace, role> combination.  For example, if user bob had crlud permissions on namespace customer1 at the time a backup was taken, and in the meantime bob's access to customer1 has been reduced to rl, then when the backup is restored bob's access will remain rl.  He will not regain his crlud access rights just because a backup was restored.

These rules are intended to be general enough for most purposes while preventing accidental security problems.  If your installation has special requirements, you can use one of the display modes and the --format afl option to generate an AFL script suitable for use with iquery.  You can use a text editor to modify the JSON input file, the AFL output file, or both.

Removing Users vs. Suspending Users

A consequence of item 1 above is that, if user andrew's account was removed using drop_user but later on a backup is restored that contains an entry for andrew in its metadata, the andrew user account will be recreated.  To avoid this, use the spaam.py script to suspend accounts rather than removing them with drop_user.

$ spaam.py --suspend andrew
Suspended user andrew
$

This prevents future logins, but leaves the account record in the catalog.

Examples

The output of some of these examples has been edited to keep the listings short.

  1. With just the cluster name "kif" as argument, rbactool.py shows the existing access control data for the cluster.

    $ rbactool.py kif > kif-rbac-snapshot-2019-04-17.json
    $ cat kif-rbac-snapshot-2019-04-17.json 
    {
      "is_canonical": true,
      "metadata_version": "5",
      "perms": [
        {
          "namespace": "beta",
          "permissions": "cu",
          "role": "uploader"
        },
        {
          "namespace": "beta",
          "permissions": "lr",
          "role": "paulo"
        },
        {
          "namespace": "public",
          "permissions": "clrud",
          "role": "paulo"
        },
        {
          "namespace": "public",
          "permissions": "cu",
          "role": "uploader"
        },
        {
          "namespace": "public",
          "permissions": "rl",
          "role": "alice"
        }
      ],
      "role_members": [
        {
          "role": "admin",
          "user": "alice"
        },
        {
          "role": "operator",
          "user": "paulo"
        }
      ],
      "roles": [
        "admin",
        "operator",
        "uploader"
      ],
      "spaces": [
        "beta",
        "public"
      ],
      "users": [
        {
          "method": "raw",
          "name": "alice",
          "password": "66gd/3H+SS8Xb+nwsz67SBeYoFbLULJlgucuS1aSUPU8PSmFQurO9yG21CXWzyRxW4HpK+7vNFBkVw6V2PLx7A==",
          "salt": ""
        },
        {
          "method": "raw",
          "name": "paulo",
          "password": "x1nClCH+U4kKrcFTEDyMg5l/EnaVWCBwdNCg/9pn3aBQGEIEaTUyXVLZ1oqfKhfGv+IALry8KTYZ8w026xUl2w==",
          "salt": ""
        },
        {
          "method": "raw",
          "name": "scidbadmin",
          "password": "eUCUk3B57IVO9ZfJB6CIEHl/0lxrWg/7PV8KytUNY6kPLhTX2db48GHGHoizKyH+uGkCfNTYZrJgKzjWOhjuvg==",
          "salt": ""
        }
      ]
    }
    $ 
  2. Use the -f/--format option to show the AFL commands necessary to recreate the current kif access control from scratch.

    $ rbactool.py -f afl kif
    create_user('alice', '66gd/3H+SS8Xb+nwsz67SBeYoFbLULJlgucuS1aSUPU8PSmFQurO9yG21CXWzyRxW4HpK+7vNFBkVw6V2PLx7A==', _method:'raw', _salt:'');
    create_user('paulo', 'x1nClCH+U4kKrcFTEDyMg5l/EnaVWCBwdNCg/9pn3aBQGEIEaTUyXVLZ1oqfKhfGv+IALry8KTYZ8w026xUl2w==', _method:'raw', _salt:'');
    create_namespace(beta);
    create_role('admin');
    create_role('operator');
    create_role('uploader');
    add_user_to_role('alice', 'admin');
    add_user_to_role('paulo', 'operator');
    set_role_permissions('uploader', beta, 'cu');
    set_role_permissions('paulo', beta, 'lr');
    set_role_permissions('paulo', public, 'clrud');
    set_role_permissions('uploader', public, 'cu');
    set_role_permissions('alice', public, 'rl');
    $ 
  3. Show the access control data recorded in a recent backup of the cluster.

    $ ls -l /tmp/Bkp
    total 56
    -rw-rw-r-- 1 scidb scidb  627 Apr 16 18:26 ARROW
    -rw-rw-r-- 1 scidb scidb  621 Apr 16 18:26 ARROW.alpha
    -rw-rw-r-- 1 scidb scidb  618 Apr 16 18:26 ARROW.beta
    -rw-rw-r-- 1 scidb scidb  631 Apr 16 18:26 BOTTLE
    -rw-rw-r-- 1 scidb scidb  625 Apr 16 18:26 BOTTLE.alpha
    -rw-rw-r-- 1 scidb scidb  623 Apr 16 18:26 BOTTLE.beta
    -rw-rw-r-- 1 scidb scidb  627 Apr 16 18:26 GLOVE
    -rw-rw-r-- 1 scidb scidb  621 Apr 16 18:26 GLOVE.alpha
    -rw-rw-r-- 1 scidb scidb  619 Apr 16 18:26 GLOVE.beta
    -rw------- 1 scidb scidb  931 Apr 16 18:26 %manifest
    -rw-rw-r-- 1 scidb scidb  619 Apr 16 18:26 PEN
    -rw-rw-r-- 1 scidb scidb  610 Apr 16 18:26 PEN.alpha
    -rw-rw-r-- 1 scidb scidb  608 Apr 16 18:26 PEN.beta
    -rw------- 1 scidb scidb 1991 Apr 16 18:26 %rbac.json
    $ 
    $ rbactool.py -i /tmp/Bkp/%rbac.json
    {
      "is_canonical": true,
      "metadata_version": "5",
      "perms": [
        {
          "namespace": "alpha",
          "permissions": "clrud",
          "role": "alice"
        },
        {
          "namespace": "alpha",
          "permissions": "cu",
          "role": "uploader"
        },
        ...LOTS OF JSON DELETED, BUT SEE NEXT EXAMPLE...
    }
    $
  4. Show the same access control information from the backup archive, formatted as AFL commands.

    $ rbactool.py -i /tmp/Bkp/%rbac.json -f afl
    create_user('alice', '66gd/3H+SS8Xb+nwsz67SBeYoFbLULJlgucuS1aSUPU8PSmFQurO9yG21CXWzyRxW4HpK+7vNFBkVw6V2PLx7A==', _method:'raw', _salt:'');
    create_user('betty', 'u1eT+bBSZB4n/7VWyurhoxyNtoIfmU8XPcYhdpwgn3z/Kb/5hqGBUnaF5O/k3zq7QidDPw0lqvBXLaQcva8vQw==', _method:'raw', _salt:'');
    create_user('paulo', 'x1nClCH+U4kKrcFTEDyMg5l/EnaVWCBwdNCg/9pn3aBQGEIEaTUyXVLZ1oqfKhfGv+IALry8KTYZ8w026xUl2w==', _method:'raw', _salt:'');
    create_namespace(alpha);
    create_namespace(beta);
    create_role('admin');
    create_role('operator');
    create_role('uploader');
    add_user_to_role('alice', 'admin');
    add_user_to_role('paulo', 'operator');
    add_user_to_role('betty', 'uploader');
    set_role_permissions('alice', alpha, 'clrud');
    set_role_permissions('uploader', alpha, 'cu');
    set_role_permissions('betty', alpha, 'rl');
    set_role_permissions('betty', beta, 'clrud');
    set_role_permissions('paulo', beta, 'clrud');
    set_role_permissions('uploader', beta, 'cu');
    set_role_permissions('paulo', public, 'clrud');
    set_role_permissions('uploader', public, 'cu');
    set_role_permissions('alice', public, 'rl');
    $
  5. When both the -i/--input option and the cluster name are given, rbactool.py shows the access control that would be added to the cluster if the backup archive were restored.  This example uses -f afl for brevity.  Some warnings ("scidb_rbac: ...") are printed on stderr, since some of the access control records from the backup are already present in the running cluster.

    $ rbactool.py -i /tmp/Bkp/%rbac.json -f afl kif
    scidb_rbac: Skipping users who already exist:
     [u'alice', u'paulo']
    scidb_rbac: Skipping roles that already exist:
     [u'admin', u'operator', u'uploader']
    scidb_rbac: Skipping namespaces that already exist:
     [u'beta']
    scidb_rbac: Skipping role memberships for pre-existing users:
     [{u'role': u'admin', u'user': u'alice'},
     {u'role': u'operator', u'user': u'paulo'}]
    scidb_rbac: Skipping permissions that would overwrite an existing entry:
     [{u'namespace': u'beta', u'permissions': u'clrud', u'role': u'paulo'},
     {u'namespace': u'beta', u'permissions': u'cu', u'role': u'uploader'},
     {u'namespace': u'public', u'permissions': u'clrud', u'role': u'paulo'},
     {u'namespace': u'public', u'permissions': u'cu', u'role': u'uploader'},
     {u'namespace': u'public', u'permissions': u'rl', u'role': u'alice'}]
    create_user('betty', 'u1eT+bBSZB4n/7VWyurhoxyNtoIfmU8XPcYhdpwgn3z/Kb/5hqGBUnaF5O/k3zq7QidDPw0lqvBXLaQcva8vQw==', _method:'raw', _salt:'');
    create_namespace(alpha);
    add_user_to_role('betty', 'uploader');
    set_role_permissions('alice', alpha, 'clrud');
    set_role_permissions('uploader', alpha, 'cu');
    set_role_permissions('betty', alpha, 'rl');
    set_role_permissions('betty', beta, 'clrud');
    $

When this backup is restored:

  • The namespace  alpha will be re-created.
  • User betty will be re-created, since she was removed and not suspended.  She will regain her old access rights to namespaces alpha and beta, and her role as an uploader.
  • The existing user alice will regain her old access rights to alpha.
  • The existing role uploader will regain its old access rights to alpha.
  • The existing user paulo will not regain his old access rights to beta, since in the interim his access rights have been changed to rl (read, lookup).