github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/docs/RFCS/20171220_sql_role_based_access_control.md (about)

     1  - Feature Name: SQL Role-based access control
     2  - Status: in-progress
     3  - Start Date: 2017-11-18
     4  - Authors: Marc Berhault
     5  - RFC PR: [#20149](https://github.com/cockroachdb/cockroach/pull/20149)
     6  - Cockroach Issue: [#20371](https://github.com/cockroachdb/cockroach/issues/20371)
     7  
     8  Table of Contents
     9  =================
    10  
    11     * [Summary](#summary)
    12     * [Motivation](#motivation)
    13     * [Related resources](#related-resources)
    14     * [Out of scope](#out-of-scope)
    15     * [Guide-level explanation](#guide-level-explanation)
    16        * [Terminology](#terminology)
    17        * [User-level explanation](#user-level-explanation)
    18           * [Role basics](#role-basics)
    19           * [Creating a role](#creating-a-role)
    20           * [Granting and revoking privileges for a role](#granting-and-revoking-privileges-for-a-role)
    21           * [Manipulating role membership](#manipulating-role-membership)
    22           * [Dropping a role](#dropping-a-role)
    23           * [Listing roles](#listing-roles)
    24           * [Listing role memberships](#listing-role-memberships)
    25           * [Administrators](#administrators)
    26           * [Non-enterprise users](#non-enterprise-users)
    27        * [Contributor impact](#contributor-impact)
    28     * [Reference-level explanation](#reference-level-explanation)
    29        * [Detailed design](#detailed-design)
    30           * [Roles system table](#roles-system-table)
    31           * [New SQL statements](#new-sql-statements)
    32           * [Modifying role memberships](#modifying-role-memberships)
    33           * [Expanding role memberships](#expanding-role-memberships)
    34           * [Checking permissions](#checking-permissions)
    35           * [Admin role](#admin-role)
    36           * [Migrations and backwards compatibility](#migrations-and-backwards-compatibility)
    37           * [Non-enterprise functionality](#non-enterprise-functionality)
    38           * [Virtual tables](#virtual-tables)
    39        * [Drawbacks](#drawbacks)
    40           * [Use of leases to signal role changes](#use-of-leases-to-signal-role-changes)
    41           * [Code location](#code-location)
    42        * [Rationale and Alternatives](#rationale-and-alternatives)
    43           * [Internal representation of memberships](#internal-representation-of-memberships)
    44        * [Future improvements](#future-improvements)
    45  
    46  # Summary
    47  
    48  Role-based access control is an enterprise feature.
    49  
    50  We propose the addition of SQL roles to facilitate user management.
    51  
    52  A role can be seen as a group containing any number of "entities" as members. An entity can be a user or
    53  another role.
    54  
    55  Roles can have privileges on SQL objects. Any member of the role (directly a member,
    56  or indirectly by being a member-of-a-member) inherits all privileges of the role.
    57  
    58  A new `admin` role will replace the current `root` user, with `root` being a member of `admin`.
    59  Non-enterprise users will not be able to manipulate roles (create/delete/change membership), but
    60  will retain all roles created using an enterprise license.
    61  
    62  This will be implemented through the addition of a new `role_members` system table containing role-role and
    63  user-role relationships. Role memberships are synchronized through descriptor versions, a new versions indicating
    64  that a node should refresh role information.
    65  
    66  # Motivation
    67  
    68  Roles simplify the task of user management on a large database.
    69  
    70  By granting database/table privileges to a role, users of a team can be more
    71  easily added to the system and granted all necessary privileges by simply adding them as members
    72  of the corresponding roles. The alternative would be granting privileges for all necessary objects,
    73  making it likely to forget some.
    74  
    75  Managing privileges on a given object becomes easier: by changing the privileges granted to the role,
    76  all members of the role are updated implicitly.
    77  
    78  # Related resources
    79  
    80  We follow the postgresql use of roles:
    81  * [PostgreSQL user management](https://www.postgresql.org/docs/current/static/user-manag.html)
    82  * [PostgreSQL CREATE ROLE](https://www.postgresql.org/docs/10/static/sql-createrole.html)
    83  * [PostgreSQL DROP ROLE](https://www.postgresql.org/docs/10/static/sql-droprole.html)
    84  * [PostgreSQL GRANT on ROLES](https://www.postgresql.org/docs/current/static/sql-grant.html#SQL-GRANT-DESCRIPTION-ROLES)
    85  * [PostgreSQL REVOKE](https://www.postgresql.org/docs/current/static/sql-revoke.html)
    86  
    87  # Out of scope
    88  
    89  The following are not in scope but should not be hindered by implementation of this RFC:
    90  * role attributes (see [PostgreSQL CREATE ROLE](https://www.postgresql.org/docs/10/static/sql-createrole.html) for full list)
    91  * `ALTER` command (modify role attributes, rename role)
    92  * role auditing
    93  * multiple "admin" (or superuser) roles
    94  * admin UI manipulation of roles
    95  * new privileges (eg: admin UI related)
    96  
    97  See [Future improvements](#future-improvements) for discussion of some of these.
    98  
    99  # Guide-level explanation
   100  
   101  ## Terminology
   102  
   103  Some terminology used in this RFC:
   104  * **role**: the focus point of this RFC. Please re-read the [summary](#summary)
   105  * **role admin**: a member of the role allowed to change role membership
   106  * **admin**: the special role allowed superuser operations, always exists
   107  * **root**: the special user existing by default as a member of the `admin` role
   108  * **inherit**: the behavior that grants a role's privileges to its members
   109  * **`A ∈ B`**: user or role `A` is a member of role `B`
   110  * **direct member**: A is a direct member of B if `A ∈ B`
   111  * **indirect member**: A is an indirect member of B if `A ∈ C ... ∈ B` where `...` is an arbitrary number of memberships
   112  
   113  ## User-level explanation
   114  
   115  ### Role basics
   116  
   117  A role can be thought of as a group with any number of members belonging to the group.
   118  Roles have privileges on objects in the same way that users do. All members of the role
   119  inherit the privileges held by the role. This is done recursively.
   120  
   121  For example:
   122  * role `employees` has `ALL` privileges on table `mydb.employee_data`
   123  * user `marc` is a member of `employees` (also written: `marc ∈ employees`)
   124  * without any extra privileges, `marc` can now perform any operations on table `mydb.employee_data`
   125  
   126  Roles and users follow a small set of rules:
   127  * roles cannot login (they do not have a password and cannot use certs)
   128  * roles and users use the same namespace (ie: if a user `marc` exists, we cannot create a role `marc`)
   129  * users and roles can be members of roles
   130  * membership loops are not allowed (direct: `A ∈ B ∈ A` or indirect: `A ∈ B ∈ C ... ∈ A`)
   131  * all privileges of a role are inherited by all its members
   132  * privileges on a table/database can be assigned to roles and users
   133  * only the admin role can create/drop roles
   134  * role admins (members with the `ADMIN OPTION`) can modify role memberships
   135  * a role cannot be dropped if it still has privileges
   136  * there is no limit (minimum or maximum) to the number of members of a role (except for the `admin` role)
   137  
   138  ### Creating a role
   139  
   140  Cockroach administrators can create a new role called `myrole` using:
   141  ```
   142  CREATE ROLE myrole
   143  ```
   144  
   145  This fails if `myrole` exists either as a role or a user.
   146  
   147  ### Granting and revoking privileges for a role
   148  
   149  Granting privileges to a role is the same a granting privileges to a user. This syntax has not changed.
   150  
   151  For example, granting `SELECT` privileges to the role `myrole` on a table consists of:
   152  ```
   153  GRANT SELECT ON TABLE mydb.mytable TO myrole
   154  ```
   155  
   156  Revoking privileges is also the same as before:
   157  ```
   158  REVOKE SELECT ON TABLE mydb.mytable FROM myrole
   159  ```
   160  
   161  ### Manipulating role membership
   162  
   163  Modification of role membership requires one of the following:
   164  * cockroach administrator (`admin` role)
   165  * role admin (added to the role using `WITH ADMIN OPTION`)
   166  
   167  A user `marc` can be added to the role `myrole` without role admin permissions using:
   168  ```
   169  GRANT myrole TO marc
   170  ```
   171  
   172  `marc` is now a "regular" member of the role, inheriting all role privileges. However, `marc`
   173  is not allowed to modify role membership.
   174  
   175  To allow a user to modify role membership, we can use `WITH ADMIN OPTION`:
   176  ```
   177  GRANT myrole TO marc WITH ADMIN OPTION
   178  ```
   179  
   180  `marc` is now a member of the role **and** is allowed to modify role membership.
   181  
   182  ### Dropping a role
   183  
   184  Cockroach administrators can delete a role called `myrole` using:
   185  ```
   186  DROP ROLE myrole
   187  ```
   188  
   189  This fails if `myrole` does not exist. We can instead use:
   190  ```
   191  DROP ROLE IF EXISTS myrole
   192  ```
   193  
   194  Dropping a role will fail if it still has direct privileges on database objects (privileges through membership
   195  in other roles does not trigger an error).
   196  
   197  Any role relationships involving this role will be removed automatically.
   198  
   199  This applies to dropping users as well: dropping user `A` when `A ∈ myrole` will automatically remove
   200  the membership.
   201  
   202  ### Listing roles
   203  
   204  We can get a simple list of all roles in the cluster by running:
   205  ```
   206  SHOW ROLES
   207  
   208  +--------------+
   209  | Role         |
   210  +--------------+
   211  | admin        |
   212  | myrole       |
   213  | myotherrole  |
   214  +--------------+
   215  ```
   216  
   217  ### Listing role memberships
   218  
   219  A list of members can be found using:
   220  ```
   221  SHOW GRANTS ON ROLE myrole
   222  
   223  +--------+----------- +-------+
   224  | Role   | User/Role  | Admin |
   225  +--------+------------+-------+
   226  | myrole | marc       | YES   |
   227  | myrole | other      | NO    |
   228  +--------+------------+-------+
   229  ```
   230  
   231  We will also allow the following variants:
   232  * lookup all role memberships: `SHOW GRANTS ON ROLE`
   233  * show all memberships for a user: `SHOW GRANTS ON ROLE FOR marc`
   234  * show all members of a role: `SHOW GRANTS ON ROLE myrole`
   235  * show user membership in a role: `SHOW GRANTS ON ROLE myrole FOR marc`
   236  
   237  ### Administrators
   238  
   239  Before this RFC, there is a single administrative user in a cockroach cluster: the user `root`.
   240  
   241  We propose to add a default role: `admin` with a single user: `root`.
   242  `root` will have admin privileges on the `admin` role, allowing addition/removal of other users.
   243  
   244  The `admin` role cannot be deleted, and cannot be empty. The special `root` user cannot be dropped or removed
   245  from the `admin` role.
   246  
   247  All operations that previously checked for the `root` user will now check for membership in the `admin` role.
   248  
   249  Clusters created before the existence of roles will have a new `admin` role created automatically and privileges
   250  for it added where `root` currently has privileges. `root` will keep its individual privileges to allow downgrades
   251  to older versions.
   252  
   253  ### Non-enterprise users
   254  
   255  Manipulation of roles is an enterprise feature.
   256  
   257  Without a valid enterprise license, the following are **not** allowed:
   258  * creating a role (`CREATE ROLE ...`)
   259  * dropping a role (`DROP ROLE ...`)
   260  * adding a member of a role (`GRANT myrole TO ...`)
   261  * removing a member from a role (`REVOKE myrole TO ...`)
   262  
   263  The following will function without an enterprise license:
   264  * listing roles
   265  * listing role memberships
   266  * granting privileges to a role
   267  * revoking privileges from a role
   268  
   269  This restriction leaves non-enterprise users with a fully-functioning product but without the
   270  ease of management provided by roles.
   271  
   272  ## Contributor impact
   273  
   274  Any modifications to the SQL code must keep in mind:
   275  * privileges can be applied to roles and users
   276  * roles and users share the same namespace
   277  
   278  # Reference-level explanation
   279  
   280  A number of concepts are detailed in the [Guide-level explanation](#guide-level-explanation) and not
   281  repeated in this section.
   282  
   283  ## Detailed design
   284  
   285  ### Roles system table
   286  
   287  We propose the modification of the users table to store roles, and the addition of a new table to store
   288  role memberships.
   289  
   290  #### Users table
   291  
   292  Since roles and users share the same namespace, it is simplest to alter the `system.users` table to
   293  include roles.
   294  
   295  The schema for the users table becomes:
   296  ```
   297  CREATE TABLE system.users (
   298    username         STRING PRIMARY KEY,
   299    "hashedPassword" BYTES,
   300    isRole           BOOL,
   301    (INDEX isRole)
   302  );`
   303  ```
   304  
   305  Depending on the complexity of migration, we may be able to rename the `username` field and even the table
   306  to `rolename` and `system.roles` to reflect the fact that users are really just roles.
   307  
   308  `isRole` denotes whether the corresponding name is a user or a role. Roles cannot log in or have passwords.
   309  
   310  #### Role members table
   311  
   312  The `role_members` stores the list of all role memberships. This only stores direct relationships:
   313  
   314  ```
   315  CREATE TABLE system.role_members (
   316    role          STRING,
   317    member        STRING,
   318    isAdmin       BOOL,
   319    PRIMARY KEY (role, member),
   320    INDEX (member)
   321  );
   322  ```
   323  
   324  For alternate representations [Internal representation of memberships](#internal-representation-of-memberships).
   325  
   326  ### New SQL statements
   327  
   328  We propose some new and some modified SQL statements, all mimicking the corresponding statements
   329  in PostgreSQL (see [Related resources](#related-resources)).
   330  
   331  The new statements all operate on the `system.users` and `system.role_members` tables.
   332  
   333  #### CREATE ROLE
   334  
   335  ```
   336  CREATE ROLE [ IF NOT EXISTS ] rolename
   337  ```
   338  
   339  * **Behavior**: creates a new role named `rolename`. Fails if a role or user by that name exists.
   340  * **Permissions**: caller must be an administrator.
   341  * **Enterprise requirement**: valid license required.
   342  
   343  #### DROP ROLE
   344  
   345  ```
   346  DROP ROLE [ IF EXISTS ] rolename
   347  ```
   348  
   349  * **Behavior**: drops the role named `rolename`. Fails if it does not exist, unless `IF EXISTS` is specified.
   350  * **Permissions**: caller must be an administrator.
   351  * **Enterprise requirement**: valid license required.
   352  
   353  #### Grant/revoke privileges to/from a role
   354  
   355  The `GRANT` and `REVOKE` statements used to grant privileges to a user will accept a role. No syntax
   356  changes are necessary.
   357  
   358  An enterprise license is not required.
   359  
   360  #### GRANT role
   361  
   362  ```
   363  GRANT rolename TO name [ WITH ADMIN OPTION ]
   364  ```
   365  
   366  * **Behavior**: adds `name` as a member of `rolename`. Member is a role admin if `WITH ADMIN OPTION` is specified.
   367    - Fails if either `rolename` or `name` does not exist, or if this creates a membership loop.
   368    - Existing memberships can have their `WITH ADMIN` option enabled, but never disabled.
   369    - The `ADMIN OPTION` is inherited. eg: if `A ∈ B ∈ C` and `B` has `ADMIN OPTION` on `C`, then `A` has `ADMIN OPTION` on `C` (but not necessarily on `B`).
   370  * **Permissions**: must be an administrator or role admin.
   371  * **Enterprise requirement**: valid license required.
   372  
   373  #### REVOKE role
   374  
   375  ```
   376  REVOKE [ ADMIN OPTION FOR ] rolename FROM name
   377  ```
   378  
   379  * **Behavior**: removes `name` as a member of `rolename`. Member admin setting is removed if `ADMIN OPTION FOR` is specified, but the membership remains.
   380  Fails if either `rolename` or `name` does not exist. Succeeds if the membership does not exist.
   381  * **Permissions**: must be an administrator or role admin.
   382  * **Enterprise requirement**: valid license required.
   383  
   384  #### SHOW ROLES
   385  
   386  ```
   387  SHOW ROLES
   388  ```
   389  
   390  * **Behavior**: lists all existing roles (role names only).
   391  * **Permissions**: none required.
   392  * **Enterprise requirement**: none required.
   393  
   394  #### SHOW GRANTS ON ROLE
   395  
   396  ```
   397  SHOW GRANTS ON ROLE [rolename] [ FOR name ]
   398  ```
   399  
   400  Where `rolename` can be one or more role and `name` can be one of more user or role. An unspecified `rolename`
   401  or `name` returns all roles or members.
   402  
   403  * **Behavior**: lists role memberships for matching roles/names.
   404  * **Permissions**: none required.
   405  * **Enterprise requirement**: none required.
   406  
   407  **TODO(mberhault)**: should we have an option to pick whether to show direct/indirect/all memberships?
   408  
   409  ### Modifying role memberships
   410  
   411  Modifying role memberships is done through normal operations on the system tables.
   412  
   413  However, we set `UpVersion` on the `role_members` table to trigger a descriptor version upgrade,
   414  notifying lease holders that a refresh is needed.
   415  
   416  ### Expanding role memberships
   417  
   418  Expanding role memberships is necessary to perform permission checks. Given how frequently these need to be
   419  done, we propose a per-node cache of role memberships with refreshes triggered by increases of the
   420  `role_members` table descriptor version.
   421  
   422  The process for a permission check is:
   423  * if the user's expanded roles is not cached, expand roles using the `role_members` table.
   424  * reads of the `role_members` table is performed at the table descriptor's `ModificationTime`
   425  * the cache holds a lease on the `role_members` table
   426  * when the `role_members` table descriptor version changes (indicating a change to role memberships), refresh the roles from the table
   427  
   428  This insures that we can keep role membership information reasonably current with refreshes being forced
   429  only when changes occur.
   430  
   431  The role cache can be a simple LRU cache with a maximum size of a few MB, but this limit should be configurable.
   432  Given the likely small size of the cached entries, we can expire them after some amount of inactivity rather than
   433  constantly refreshing them.
   434  
   435  Role membership expansion can be pre-computed (see [Internal representation of memberships](#internal-representation-of-memberships)) to allow for cheaper lookup at the time of permission checks.
   436  
   437  ### Checking permissions
   438  
   439  Permission checks currently consist of calls to one of:
   440  ```
   441  func (p *planner) CheckPrivilege(descriptor sqlbase.DescriptorProto, privilege privilege.Kind) error
   442  func (p *planner) CheckAnyPrivilege(descriptor sqlbase.DescriptorProto) error
   443  func (p *planner) RequireAdminRole(action string) error
   444  func (p *planner) HasAdminRole() (bool, error)
   445  func (p *planner) MemberOfWithAdminOption(member string) (map[string]bool, error)
   446  ```
   447  
   448  All methods operate on `p.session.User`.
   449  
   450  These functions check a number of things for the specified user:
   451  * has the required privileges in the descriptor
   452  * is the `root` or `node` user
   453  * has "any" privileges on the descriptor
   454  
   455  In a world with roles, permission checks are performed against the set of names consisting of:
   456  * the username
   457  * the expanded list of roles the user is a member of
   458  
   459  Checking permissions becomes checking that any of the names in the set have the required permissions.
   460  For `root` checks, this is hard-coded to checking that the expanded list includes the `admin` role.
   461  
   462  ### Admin role
   463  
   464  The `admin` role is a special role corresponding to the current `root` user.
   465  It is checked everywhere we currently check `if user == security.RootUser`.
   466  
   467  It is created at cluster-creation time (or migration) and initialized with the `root`
   468  user as a member.
   469  
   470  The `admin` role cannot be dropped and cannot be empty (member removal of the last member
   471  will fail).
   472  
   473  ### Migrations and backwards compatibility
   474  
   475  Migrations from older versions will perform the following tasks:
   476  * add the `isRole` column to the `system.users` table
   477  * add the `admin` role to the `system.users` table
   478  * create the `system.role_members` table
   479  * create the `root` user
   480  * add `root` as a member of `admin` with `isAdmin = true`
   481  * give admin the same privileges as the `root` user
   482  
   483  Notes:
   484  * we intentionally do not remove `root` privileges to allow for binary downgrade.
   485  * is a user named `admin` exists, `log.Fatal` the migration and ask the user to downgrade/drop the user/try again.
   486  
   487  ### Non-enterprise functionality
   488  
   489  See [Non-enterprise users](#non-enterprise-users) for actions requiring an enterprise license.
   490  
   491  All prohibited actions are in the "administrative" category of operations (role management), and not
   492  in the path of data-access SQL queries.
   493  
   494  This makes the enterprise license check relatively painless.
   495  
   496  It is currently possible to manipulate the system tables directly, bypassing role manipulation statements.
   497  Closing this loop-hole is out of scope for this document. See [tracking issue #19277](https://github.com/cockroachdb/cockroach/issues/19277).
   498  
   499  ### Virtual tables
   500  
   501  We must populate some virtual tables with role information.
   502  
   503  #### pg_catalog.pg_roles
   504  
   505  See [PostgresSQL doc](https://www.postgresql.org/docs/current/static/view-pg-roles.html)
   506  
   507  The existing `pg_roles` table is currently populated for all users:
   508  ```
   509  h.UserOid(username),         // oid
   510  tree.NewDName(username),     // rolname
   511  tree.MakeDBool(isRoot),      // rolsuper
   512  tree.MakeDBool(false),       // rolinherit
   513  tree.MakeDBool(isRoot),      // rolcreaterole
   514  tree.MakeDBool(isRoot),      // rolcreatedb
   515  tree.MakeDBool(false),       // rolcatupdate
   516  tree.MakeDBool(true),        // rolcanlogin
   517  negOneVal,                   // rolconnlimit
   518  tree.NewDString("********"), // rolpassword
   519  tree.DNull,                  // rolvaliduntil
   520  tree.NewDString("{}"),       // rolconfig
   521  ```
   522  
   523  A similar entry must be created for each existing role with the following changes:
   524  * `isRoot` is replaced with the condition `rolename == admin`
   525  * `rolcanlogin` is always false
   526  
   527  **TODO(mberhault)**: determine if members that inherit superuser roles are listed here with the inherited attributes
   528  (eg: if `marc ∈ admin`, does `marc` have `rolsuper` set to true?).
   529  
   530  #### pg_catalog.pg_auth_members
   531  
   532  See [PostgresSQL doc](https://www.postgresql.org/docs/current/static/catalog-pg-auth-members.html)
   533  
   534  The new virtual table `pg_auth_members` must be added. It describes role memberships:
   535  ```
   536  CREATE TABLE pg_catalog.pg_auth_members (
   537    roleid           OID,   ; ID of the role that has a member
   538    member           OID,   ; ID of the member
   539    grantor          OID,   ; ID of the role that granted this membership
   540    admin_options    BOOL   ; true if member can grant membership in roleid to others
   541  )
   542  ```
   543  
   544  The `grantor` may or may not be a bogus value.
   545  
   546  **TODO(mberhault)**: determine PostgreSQL logic for grantor (especially if original OID is dropped).
   547  
   548  #### pg_catalog.pg_authid
   549  
   550  See [PostgreSQL doc](https://www.postgresql.org/docs/current/static/catalog-pg-authid.html).
   551  
   552  The `pg_authid` virtual table is not currently implemented in Cockroach.
   553  It contains sensitive information (passwords) and PostgreSQL clearly states:
   554  ```
   555  Since this catalog contains passwords, it must not be publicly readable. pg_roles is a publicly readable view on pg_authid that blanks out the password field.
   556  ```
   557  
   558  We propose to keep in unimplemented, users should query `pg_roles` and `pg_auth_members` instead.
   559  
   560  #### information_schema
   561  
   562  There are multiple relevant tables in `information_schema` that must be changed or added.
   563  * `administrable_role_authorizations`: roles the current user has the `ADMIN OPTION` on.
   564  * `applicable_roles`: roles whose privileges the current user can use.
   565  * `enabled_roles`: roles the current use is a member of (direct or indirect).
   566  * `role_table_grants`: similar to the existing `table_privileges`.
   567  
   568  **TODO(mberhault)**: determine exactly which are needed and flesh out details.
   569  
   570  ## Drawbacks
   571  
   572  Roles themselves follow the PostgreSQL behavior and any drawbacks there are intended for compatibility.
   573  
   574  There are some minor drawbacks to this implementation.
   575  
   576  ### Use of leases to signal role changes
   577  
   578  While allowing for cheaper role expansions, the use of leases to signal role membership changes
   579  subverts the original purpose.
   580  
   581  If a more appropriate solution is found, it can replace the current mechanism at a later date.
   582  
   583  ### Code location
   584  
   585  The role manipulation code is very similar to user manipulation (it's just a field inside `system.users`), making
   586  it preferable to reuse most of the code. We also need the role logic (expand roles, check privileges, etc..) to
   587  keep working in non-enterprise mode.
   588  
   589  These make it tricky to place all the role-related code in `pkg/ccl`. We need to figure out exactly which code
   590  can be kept separate.
   591  
   592  ## Rationale and Alternatives
   593  
   594  ### Internal representation of memberships
   595  
   596  The current proposal requires an iterative lookup to discover all memberships for a user.
   597  This is the most naive way of representing memberships and maps well to the conceptual representation of roles.
   598  
   599  This makes role manipulation cheap, with role lookups bearing the brunt of the cost.
   600  
   601  Some alternatives include:
   602  
   603  Expanding role membership into the roles table (each role contains the list of all roles its a member of):
   604  * **Pros**: fast lookup of a user's memberships
   605  * **Cons**: more complex manipulation of roles, needs a concept of "direct" vs "indirect" membership
   606  
   607  Expanding role membership into database/table descriptors (descriptor contains all users with privileges):
   608  * **Pros**: regular SQL operations only require the user and descriptor
   609  * **Cons**: more complex manipulation of roles, increased cost for very large roles
   610  
   611  Dual tables: one for direct role membership information, one for expanded membership information:
   612  * the direct membership table would include the `ADMIN OPTION` field and would be queried for role manipulation
   613  * permission checking only requires lookups in the expanded table
   614  * the expanded table can use an index on the user or even an array type for the list of roles
   615  * **Pros**: fast lookup of a users's memberships
   616  * **Cons**: slightly more complex role manipulation
   617  
   618  ## Future improvements
   619  
   620  ### Move privileges to their own table
   621  
   622  Privileges are currently stored in database/table descriptors. To properly integrate with the
   623  role change control, they need to be moved to their own table.
   624  
   625  [Existing issue](https://github.com/cockroachdb/cockroach/issues/2939).
   626  
   627  ### Role attributes
   628  
   629  We do not currently have attributes on users or roles.
   630  
   631  While we do not propose to implement all of them, some of them would be useful. For instance:
   632  * `SUPERUSER`: database superuser
   633  * `CREATEDB`: can create databases
   634  * `CREATEROLE`: can manipulate all roles (except the superuser roles)
   635  * `INHERIT|NOINHERIT`: roles privileges are inherited (or not) 
   636  
   637  Implementing additional attributes is out of scope for this RFC. If added, this can be done for
   638  both users and roles by adding the corresponding columns to the `system.users` table.
   639  
   640  ### Convenience statements
   641  
   642  Some SQL statements can be enhanced to improve usability. For example:
   643  
   644  Adding members `firstmember` and `secondmember` when creating a new role `myrole`:
   645  ```
   646  CREATE ROLE myrole ROLE firstmember, secondmember
   647  ```
   648  
   649  Adding the new role `myrole` as a member of existing roles `existingrole1` `existingrole2:
   650  ```
   651  CREATE ROLE myrole IN ROLE existingrole1, existingrole2
   652  ```
   653  
   654  Adding members `firstadmin` and `secondadmin` to the new role `myrole` with the `ADMIN OPTION` set:
   655  ```
   656  CREATE ROLE myrole ADMIN firstadmin, secondadmin
   657  ```
   658  
   659  ### UI visibility and management
   660  
   661  At the very least, the admin UI should show role information (privileges on objects, memberships, etc...).
   662  Manipulation of roles may be a UI event.
   663  
   664  Changing roles through the admin UI should be possible, but is currently gated on admin UI authentication.
   665  
   666  ### Backup/restore of privileges/users/roles
   667  
   668  Backup/restore currently does not restore privileges or users.
   669  Should it start doing so, roles must be restored as well.