Access control | Tarantool
Administration Access control

Access control

Tarantool enables flexible management of access to various database resources. The main concepts of Tarantool access control system are as follows:

  • A user is a person or program that interacts with a Tarantool instance.
  • An object is an entity to which access can be granted, for example, a space, an index, or a function.
  • A privilege allows a user to perform certain operations on specific objects, for example, creating spaces, reading or updating data.
  • A role is a named collection of privileges that can be granted to a user.

A user identifies a person or program that interacts with a Tarantool instance. There might be different types of users, for example:

  • A database administrator responsible for the overall management and administration of a database. An administrator can create other users and grant them specified privileges.
  • A user with limited access to certain data and stored functions. Such users can get their privileges from the database administrator.
  • Users used in communications between Tarantool instances. For example, such users can be created to maintain replication and sharding in a Tarantool cluster.

There are two built-in users in Tarantool:

  • admin is a user with all available administrative privileges. If the connection uses an admin-console port, the current user is admin. For example, admin is used when connecting to an instance using tt connect locally using the instance name:

    $ tt connect app:instance001
    

    To allow remote binary port connections using the admin user, you need to set a password.

  • guest is a user with minimum privileges used by default for remote binary port connections. For example, guest is used when connecting to an instance using tt connect using the IP address and port without specifying the name of a user:

    $ tt connect 192.168.10.10:3301
    

    Warning

    Given that the guest user allows unauthenticated access to Tarantool instances, it is not recommended to grant additional privileges to this user. For example, granting the execute access to universe allows remote code execution on instances.

Note

Information about users is stored in the _user space.

Any user (except guest) may have a password. If a password is not set, a user cannot connect to Tarantool instances.

Tarantool password hashes are stored in the _user system space. By default, Tarantool uses the CHAP protocol to authenticate users and applies SHA-1 hashing to passwords. So, if the password is ‘123456’, the stored hash is a string like ‘a7SDfrdDKRBe5FaN2n3GftLKKtk=’. In the Enterprise Edition, you can enable PAP authentication with the SHA256 hashing algorithm.

Tarantool Enterprise Edition allows you to improve database security by enforcing the use of strong passwords, setting up a maximum password age, and so on. Learn more from the Authentication topic.

An object is a securable entity to which access can be granted. Tarantool has a number of objects that enable flexible management of access to data, stored functions, specific actions, and so on.

Below are a few examples of objects:

  • universe represents a database (box.schema) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. Granting privileges to universe gives a user access to any object in a database.
  • space enables granting privileges to user-created or system spaces.
  • function enables granting privileges to functions.

Note

The full list of object types is available in the Object types section.

The privileges granted to a user determine which operations the user can perform, for example:

  • The read and write permissions granted to the space object allow a user to read or modify data in the specified space.
  • The create permission granted to the space object allows a user to create new spaces.
  • The execute permission granted to the function object allows a user to execute the specified function.
  • The session permission granted to a user allows connecting to an instance over IPROTO.

Note that some privileges might require read and write access to certain system spaces. For example, the create permission granted to the space object requires read and write permissions to the _space system space. Similarly, granting the ability to create functions requires read and write access to the _func space.

Note

Information about privileges is stored in the _priv space.

A role is a container for privileges that can be granted to users. Roles can also be assigned to other roles, creating a role hierarchy.

There are the following built-in roles in Tarantool:

  • super has all available administrative permissions.

  • public has certain read permissions. This role is automatically granted to new users when they are created.

  • replication can be granted to a user used to maintain replication in a cluster.

  • sharding can be granted to a user used to maintain sharding in a cluster.

    Note

    The sharding role is created only if an instance is managed using YAML configuration.

Below are a few diagrams that demonstrate how privileges can be granted to a user without and with using roles.

  • In this example, a user gets privileges directly without using roles.

    user1 ── privilege1
        ├─── privilege2
        └─── privilege3
    
  • In this example, a user gets all privileges provided by role1 and specific privileges assigned directly.

    user1 ── role1 ── privilege1
        │        └─── privilege2
        ├─── privilege3
        └─── privilege4
    
  • In this example, role2 is granted to role1. This means that a user with role1 subsequently gets all privileges from both roles role1 and role2.

    user1 ── role1 ── privilege1
        │        ├─── privilege2
        │        └─── role2
        │                 ├─── privilege3
        │                 └─── privilege4
        ├─── privilege5
        └─── privilege6
    

Note

Information about roles is stored in the _user space.

An owner of a database object is the user who created it. The owner of the database and the owner of objects that are created initially (the system spaces and the default users) is the admin user.

Owners automatically have privileges for objects they create. They can share these privileges with other users or roles using box.schema.user.grant() and box.schema.role.grant().

Note

Information about users who gave the specified privileges is stored in the _priv space.

A session is the state of a connection to Tarantool. The session contains:

  • An integer ID identifying the connection.
  • The current user associated with the connection.
  • The text description of the connected peer.
  • A session’s local state, such as Lua variables and functions.

In Tarantool, a single session can execute multiple concurrent transactions. Each transaction is identified by a unique integer ID, which can be queried at the start of the transaction using box.session.sync().

Note

To track all connects and disconnects, you can use connection and authentication triggers.

To create a new user, call box.schema.user.create(). In the example below, a user is created without a password:

box.schema.user.create('testuser')

In this example, the password is specified in the options parameter:

box.schema.user.create('testuser', { password = 'foobar' })

To set or change a user’s password, use box.schema.user.passwd(). In the example below, a user password is set for a currently logged-in user:

box.schema.user.passwd('foobar')

To set the password for the specified user, pass a username and password as shown below:

box.schema.user.passwd('testuser', 'foobar')

Note

box.schema.user.password() returns a hash of the specified password.

To grant the specified privileges to a user, use the box.schema.user.grant() function. In the example below, testuser gets read permissions to the writers space and read/write permissions to the books space:

box.schema.user.grant('testuser', 'read', 'space', 'writers')
box.schema.user.grant('testuser', 'read,write', 'space', 'books')

Learn more about granting privileges to different types of objects from Granting privileges.

To check whether the specified user exists, call box.schema.user.exists():

box.schema.user.exists('testuser')
--[[
- true
--]]

To get information about privileges granted to a user, call box.schema.user.info():

box.schema.user.info('testuser')
--[[
- - - execute
    - role
    - public
  - - read
    - space
    - writers
  - - read,write
    - space
    - books
  - - session,usage
    - universe
    -
  - - alter
    - user
    - testuser
--]]

In the example above, testuser has the following privileges:

  • The execute permission to the public role means that this role is assigned to the user.
  • The read permission to the writers space means that the user can read data from this space.
  • The read,write permissions to the books space mean that the user can read and modify data in this space.
  • The session,usage permissions to universe mean the following:
    • session: the user can authenticate over an IPROTO connection.
    • usage: lets the user use their privileges on database objects (for example, read and modify data in a space).
  • The alter permission lets testuser modify its own settings, for example, a password.

To revoke the specified privileges, use the box.schema.user.revoke() function. In the example below, write access to the books space is revoked:

box.schema.user.revoke('testuser', 'write', 'space', 'books')

Revoking the session permission to universe can be used to disallow a user to connect to a Tarantool instance:

box.schema.user.revoke('testuser', 'session', 'universe')

The current user name can be found using box.session.user().

box.session.user()
--[[
- admin
--]]

The current user can be changed:

  • For an admin-console connection: using box.session.su():

    box.session.su('testuser')
    box.session.user()
    --[[
    - testuser
    --]]
    
  • For a binary port connection: using the AUTH protocol command, supported by most clients.

  • For a binary-port connection invoking a stored function with the CALL command: if the SETUID property is enabled for the function, Tarantool temporarily replaces the current user with the function’s creator, with all the creator’s privileges, during function execution.

To drop the specified user, call box.schema.user.drop():

box.schema.user.drop('testuser')

To create a new role, call box.schema.role.create(). In the example below, two roles are created:

box.schema.role.create('books_space_manager')
box.schema.role.create('writers_space_reader')

To grant the specified privileges to a role, use the box.schema.role.grant() function. In the example below, the books_space_manager role gets read and write permissions to the books space:

box.schema.role.grant('books_space_manager', 'read,write', 'space', 'books')

The writers_space_reader role gets read permissions to the writers space:

box.schema.role.grant('writers_space_reader', 'read', 'space', 'writers')

Learn more about granting privileges to different types of objects from Granting privileges.

Note

Not all privileges can be granted to roles. Learn more from Permissions.

Roles can be assigned to other roles. In the example below, the newly created all_spaces_manager role gets all privileges granted to books_space_manager and writers_space_reader:

box.schema.role.create('all_spaces_manager')
box.schema.role.grant('all_spaces_manager', 'books_space_manager')
box.schema.role.grant('all_spaces_manager', 'writers_space_reader')

To grant the specified role to a user, use the box.schema.user.grant() function. In the example below, testuser gets privileges granted to the books_space_manager and writers_space_reader roles:

box.schema.user.grant('testuser', 'books_space_manager')
box.schema.user.grant('testuser', 'writers_space_reader')

To check whether the specified role exists, call box.schema.role.exists():

box.schema.role.exists('books_space_manager')
--[[
- true
--]]

To get information about privileges granted to a role, call box.schema.role.info():

box.schema.role.info('books_space_manager')
--[[
- - - read,write
    - space
    - books
--]]

If a role has the execute permission to other roles, this means that these roles are granted to this parent role:

box.schema.role.info('all_spaces_manager')
--[[
- - - execute
    - role
    - books_space_manager
  - - execute
    - role
    - writers_space_reader
--]]

To revoke the specified role from a user, revoke the execute privilege for this role using the box.schema.user.revoke() function. In the example below, the books_space_reader role is revoked from testuser:

box.schema.user.revoke('testuser', 'execute', 'role', 'writers_space_reader')

To revoke role’s privileges, use box.schema.role.revoke().

To drop the specified role, call box.schema.role.drop():

box.schema.role.drop('writers_space_reader')

To grant the specified privileges to a user or role, use the box.schema.user.grant() and box.schema.role.grant() functions, which have similar signatures and accept the same set of arguments. For example, the box.schema.user.grant() signature looks as follows:

box.schema.user.grant(username, permissions, object-type, object-name[, {options}])
  • username: the name of the user that gets the specified privileges.

  • permissions: a string value that represents permissions granted to the user. If there are several permissions, they should be separated by commas without a space.

  • object-type: a type of object to which permissions are granted.

  • object-name: the name of the object to which permissions are granted. An empty string ("") or nil provided instead of object-name grants the specified permissions to all objects of the specified type.

    Note

    object-name is ignored for the following combinations of permissions and object types:

    • Any permission granted to universe.
    • The create and drop permissions for the following object types: user, role, space, function, sequence.
    • The execute permission for the following object types: lua_eval, lua_call, sql.

In the example below, testuser gets privileges allowing them to create any object of any type:

box.schema.user.grant('testuser','read,write,create','universe')

In this example, testuser can grant access to objects that testuser created:

box.schema.user.grant('testuser','write','space','_priv')

In the example below, testuser gets privileges allowing them to create spaces:

box.schema.user.grant('testuser','create','space')
box.schema.user.grant('testuser','write', 'space', '_schema')
box.schema.user.grant('testuser','write', 'space', '_space')

As you can see, the ability to create spaces also requires write access to certain system spaces.

To allow testuser to drop a space that has associated objects, add the following privileges:

box.schema.user.grant('testuser','create,drop','space')
box.schema.user.grant('testuser','write','space','_schema')
box.schema.user.grant('testuser','write','space','_space')
box.schema.user.grant('testuser','write','space','_space_sequence')
box.schema.user.grant('testuser','read','space','_trigger')
box.schema.user.grant('testuser','read','space','_fk_constraint')
box.schema.user.grant('testuser','read','space','_ck_constraint')
box.schema.user.grant('testuser','read','space','_func_index')

In the example below, testuser gets privileges allowing them to create indexes in the ‘writers’ space:

box.schema.user.grant('testuser','create,read','space','writers')
box.schema.user.grant('testuser','read,write','space','_space_sequence')
box.schema.user.grant('testuser','write', 'space', '_index')

To allow testuser to alter indexes in the writers space, grant the privileges below. This example assumes that indexes in the writers space are not created by testuser.

box.schema.user.grant('testuser','alter','space','writers')
box.schema.user.grant('testuser','read','space','_space')
box.schema.user.grant('testuser','read','space','_index')
box.schema.user.grant('testuser','read','space','_space_sequence')
box.schema.user.grant('testuser','write','space','_index')

If testuser created indexes in the writers space, granting the following privileges is enough to alter indexes:

box.schema.user.grant('testuser','read','space','_space_sequence')
box.schema.user.grant('testuser','read,write','space','_index')

In this example, testuser gets privileges allowing them to select data from the ‘writers’ space:

box.schema.user.grant('testuser','read','space','writers')

In this example, testuser is allowed to read and modify data in the ‘books’ space:

box.schema.user.grant('testuser','read,write','space','books')

In this example, testuser gets privileges to create sequence generators:

box.schema.user.grant('testuser','create','sequence')
box.schema.user.grant('testuser', 'read,write', 'space', '_sequence')

To let testuser drop a sequence, grant them the following privileges:

box.schema.user.grant('testuser','drop','sequence')
box.schema.user.grant('testuser','write','space','_sequence_data')
box.schema.user.grant('testuser','write','space','_sequence')

In this example, testuser is allowed to use the id_seq:next() function with a sequence named ‘id_seq’:

box.schema.user.grant('testuser','read,write','sequence','id_seq')

In the next example, testuser is allowed to use the id_seq:set() or id_seq:reset() functions with a sequence named ‘id_seq’:

box.schema.user.grant('testuser','write','sequence','id_seq')

In this example, testuser gets privileges to create functions:

box.schema.user.grant('testuser','create','function')
box.schema.user.grant('testuser','read,write','space','_func')

To let testuser drop a function, grant them the following privileges:

box.schema.user.grant('testuser','drop','function')
box.schema.user.grant('testuser','write','space','_func')

To give the ability to execute a function named ‘sum’, grant the following privileges:

box.schema.user.grant('testuser','execute','function','sum')

In this example, testuser gets privileges to create other users:

box.schema.user.grant('testuser','create','user')
box.schema.user.grant('testuser', 'read,write', 'space', '_user')
box.schema.user.grant('testuser', 'write', 'space', '_priv')

To let testuser create new roles, grant the following privileges:

box.schema.user.grant('testuser','create','role')
box.schema.user.grant('testuser', 'read,write', 'space', '_user')
box.schema.user.grant('testuser', 'write', 'space', '_priv')

To let testuser execute Lua code, grant the execute privilege to the lua_eval object:

box.schema.user.grant('testuser','execute','lua_eval')

Similarly, executing an arbitrary SQL expression requires the execute privilege to the sql object:

box.schema.user.grant('testuser','execute','sql')

In the example below, the created Lua function is executed on behalf of its creator, even if called by another user.

First, the two spaces (space1 and space2) are created, and a no-password user (private_user) is granted full access to them. Then read_and_modify is defined and private_user becomes this function’s creator. Finally, another user (public_user) is granted access to execute Lua functions created by private_user.

box.schema.space.create('space1')
box.schema.space.create('space2')
box.space.space1:create_index('pk')
box.space.space2:create_index('pk')

box.schema.user.create('private_user')

box.schema.user.grant('private_user', 'read,write', 'space', 'space1')
box.schema.user.grant('private_user', 'read,write', 'space', 'space2')
box.schema.user.grant('private_user', 'create', 'universe')
box.schema.user.grant('private_user', 'read,write', 'space', '_func')

function read_and_modify(key)
  local space1 = box.space.space1
  local space2 = box.space.space2
  local fiber = require('fiber')
  local t = space1:get{key}
  if t ~= nil then
    space1:put{key, box.session.uid()}
    space2:put{key, fiber.time()}
  end
end

box.session.su('private_user')
box.schema.func.create('read_and_modify', {setuid= true})
box.session.su('admin')
box.schema.user.create('public_user', {password = 'secret'})
box.schema.user.grant('public_user', 'execute', 'function', 'read_and_modify')

Whenever public_user calls the function, it is executed on behalf of its creator, private_user.

Object type Description
universe A database (box.schema) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. Granting privileges to universe gives a user access to any object in the database.
user A user.
role A role.
space A space.
function A function.
sequence A sequence.
lua_eval Executing arbitrary Lua code.
lua_call Calling any global user-defined Lua function.
sql Executing an arbitrary SQL expression.

Permission Object type Granted to roles Description
read All Yes Allows reading data of the specified object. For example, this permission can be used to allow a user to select data from the specified space.
write All Yes Allows updating data of the specified object. For example, this permission can be used to allow a user to modify data in the specified space.
create All Yes

Allows creating objects of the specified type. For example, this permission can be used to allow a user to create new spaces.

Note that this permission requires read and write access to certain system spaces.

alter All Yes

Allows altering objects of the specified type.

Note that this permission requires read and write access to certain system spaces.

drop All Yes

Allows dropping objects of the specified type.

Note that this permission requires read and write access to certain system spaces.

execute role, universe, function, lua_eval, lua_call, sql Yes For role, allows using the specified role. For other object types, allows calling a function.
session universe No Allows a user to connect to an instance over IPROTO.
usage universe No Allows a user to use their privileges on database objects (for example, read, write, and alter spaces).

Object type Details
universe
  • read: Allows reading any object types, including all spaces or sequence objects.
  • write: Allows modifying any object types, including all spaces or sequence objects.
  • execute: Allows execute functions, Lua code, or SQL expressions, including IPROTO calls.
  • session: Allows a user to connect to an instance over IPROTO.
  • usage: Allows a user to use their privileges on database objects (for example, read, write, and alter space).
  • create: Allows creating users, roles, functions, spaces, and sequences. This permission requires read and write access to certain system spaces.
  • drop: Allows creating users, roles, functions, spaces, and sequences. This permission requires read and write access to certain system spaces.
  • alter: Allows altering user settings or space objects.
user
  • alter: Allows modifying a user description, for example, change the password.
  • create: Allows creating new users. This permission requires read and write access to the _user system space.
  • drop: Allows dropping users. This permission requires read and write access to the _user system space.
role
  • execute: Indicates that a role is assigned to the user or another role.
  • create: Allows creating new roles. This permission requires read and write access to the _user system space.
  • drop: Allows dropping roles. This permission requires read and write access to the _user system space.
space
  • read: Allows selecting data from a space.

  • write: Allows modifying data in a space.

  • create: Allows creating new spaces. This permission requires read and write access to the _space system space.

  • drop: Allows dropping spaces. This permission requires read and write access to the _space system space.

  • alter: Allows modifying spaces. This permission requires read and write access to the _space system space.

    If a space is created by a user, they can read and write it without granting explicit permission.

function
  • execute: Allows calling a function.

  • create: Allows creating a function. This permission requires read and write access to the _func system space.

    If a function is created by a user, they can execute it without granting explicit permission.

  • drop: Allows dropping a function. This permission requires read and write access to the _func system space.

sequence
  • read: Allows using sequences in space_obj:create_index().

  • write: Allows all operations for a sequence object.

    seq_obj:drop() requires a write permission to the _priv system space.

  • create: Allows creating sequences. This permission requires read and write access to the _sequence system space.

    If a sequence is created by a user, they can read/write it without explicit permission.

  • drop: Allows dropping sequences. This permission requires read and write access to the _sequence system space.

  • alter: Has no effect. seq_obj:alter() and other methods require the write permission.

lua_eval
  • execute: Allows executing arbitrary Lua code using the IPROTO_EVAL request.
lua_call
  • execute: Allows executing any user-defined function using the IPROTO_CALL request. This permission doesn’t allow a user to call built-in Lua functions (for example, loadstring() or box.session.su()) and functions defined in the _func system space.
sql
  • execute: Allows executing arbitrary SQL expression using the IPROTO_PREPARE and IPROTO_EXECUTE requests.
Found what you were looking for?
Feedback