Skip to content
Snippets Groups Projects
authentication.rst 16.87 KiB

Access control

Understanding the details of security is primarily an issue for administrators, but ordinary users should at least skim this section so that they will have an idea of how Tarantool makes it possible for administrators to prevent unauthorized access to the database and to certain functions.

Briefly: there is a method to guarantee with password checks that users really are who they say they are ("authentication"). There is a _user space where user names and password-hashes are stored. There are functions for saying that certain users are allowed to do certain things ("privileges"). There is a _priv space where privileges are stored. Whenever a user tries to do an operation, there is a check whether the user has the privilege to do the operation ("access control").

Passwords

Each user may have a password. The password is any alphanumeric string. Administrators should advise users to choose long unobvious passwords, but it is ultimately up to the users to choose or change their own passwords.

Tarantool passwords are stored in the _user space with a Cryptographic hash function so that, if the password is 'x', the stored hashed-password is a long string like 'lL3OvhkIPOKh+Vn9Avlkx69M/Ck='. When a client connects to a Tarantool server, the server sends a random Salt Value which the client must mix with the hashed-password before sending to the server. Thus the original value 'x' is never stored anywhere except in the user's head, and the hashed value is never passed down a network wire except when mixed with a random salt. This system prevents malicious onlookers from finding passwords by snooping in the log files or snooping on the wire. It is the same system that MySQL introduced several years ago which has proved adequate for medium-security installations. Nevertheless administrators should warn users that no system is foolproof against determined long-term attacks, so passwords should be guarded and changed occasionally.

Notes: To get the hash-password of a string 'X', say box.schema.user.password('X'). To see more about the details of the algorithm for the purpose of writing a new client application, read the scramble.h header file.

Users and the _user space

The fields in the _user space are:

  • the numeric id of the tuple
  • the numeric id of the tuple's creator
  • the user name
  • the type
  • optional password

There are four special tuples in the _user space: 'guest', 'admin', 'public', and 'replication'.

Name ID Type Description
guest 0 user Default when connecting remotely. Usually an untrusted user with few privileges.
admin 1 user Default when using tarantool as a console. Usually an administrative user with all privileges.
public 2 role Not a user in the usual sense. Described later in section Roles.
replication 3 role Not a user in the usual sense. Described later in section Roles.

To select a row from the _user space, use box.space._user:select. For example, here is what happens with a select for user id = 0, which is the 'guest' user, which by default has no password:

tarantool> box.space._user:select{0}
---
- - [0, 1, 'guest', 'user']
...

To change tuples in the _user space, do not use ordinary box.space functions for insert or update or delete - the _user space is special so there are special functions which have appropriate error checking.

To create a new user, say:

box.schema.user.create(user-name)
box.schema.user.create(user-name, {if_not_exists = true})
box.schema.user.create(user-name, {password = password}).

The :samp:`password={password}` specification is good because in a :ref:`URI` (Uniform Resource Identifier) it is usually illegal to include a user-name without a password.

To change the user's password, say:

-- To change the current user's password
box.schema.user.passwd(password)

-- To change a different user's password
box.schema.user.passwd(user-name, password)

(Usually it is only the admin user who can change a different user's password.)

To drop a user, say:

box.schema.user.drop(user-name).

To check whether a user exists, say:

box.schema.user.exists(user-name)

which returns true or false.

To find what privileges a user has, say:

box.schema.user.info(user-name)

Example:

Here is a session which creates a new user with a strong password, selects a tuple in the _user space, and then drops the user.

tarantool> box.schema.user.create('JeanMartin', {password = 'Iwtso_6_os$$'})
---
...
tarantool> box.space._user.index.name:select{'JeanMartin'}
---
- - [17, 1, 'JeanMartin', 'user', {'chap-sha1': 't3xjUpQdrt857O+YRvGbMY5py8Q='}]
...
tarantool> box.schema.user.drop('JeanMartin')
---
...

Note

The maximum number of users is 32.

Privileges and the _priv space

The fields in the _priv space are:

  • the numeric id of the user who gave the privilege ("grantor_id"),
  • the numeric id of the user who received the privilege ("grantee_id"),
  • the type of object - "space" or "function" or "universe",
  • the numeric id of the object,
  • the type of operation - "read" = 1, or "write" = 2, or "execute" = 4, or a combination such as "read,write,execute".

The function for granting a privilege is:

box.schema.user.grant(grantee, operation, object-type, obejct-name*[, *options])
-- OR
box.schema.user.grant(grantee, operation, 'universe' [, nil, options])

where 'universe' means 'all objects', and the optional grant-option can be:

  • :samp:`grantor={grantor_name_or_id}` - string or number, for custom grantor
  • :samp:`if_not_exists=true|false` - bool, do not throw error if user already has the privilege

The function for revoking a privilege is:

box.schema.user.revoke(grantee, operation, object-type, object-name*[, *options])
box.schema.user.revoke(grantee, operation, 'universe'[, nil, options])

where 'universe' means 'all objects', and the optional grant-option can be:

  • :samp:`if_not_exists=true|false` - bool, do not throw error if user already lacks the privilege

For example, here is a session where the admin user gave the guest user the privilege to read from a space named space55, and then took the privilege away:

tarantool> box.schema.user.grant('guest', 'read', 'space', 'space55')
---
...
tarantool> box.schema.user.revoke('guest', 'read', 'space', 'space55')
---
...

Note

Generally privileges are granted or revoked by the owner of the object (the user who created it), or by the 'admin' user. Before dropping any objects or users, steps should be taken to ensure that all their associated privileges have been revoked.

Note

Only the 'admin' user can grant privileges for the 'universe'.

Note

Only the creator of a space can drop, alter, or truncate the space. Only the creator of a user can change a different user's password.

Functions and _func space

The fields in the _func space are:

  • the numeric function id, a number,
  • the function name
  • flag
  • possibly a language name.

The _func space does not include the function's body. One continues to create Lua functions in the usual way, by saying ":samp:`function {function_name} () ... end`", without adding anything in the _func space. The _func space only exists for storing function tuples so that their names can be used within grant/revoke functions.

The function for creating a _func tuple is:

box.schema.func.create(function-name [, options])

The possible options are:

  • :samp:`if_not_exists = {true|false}` - default = false,
  • :samp:`setuid = {true|false}` - default = false,
  • :samp:`language = {'LUA'|'C'}` - default = 'LUA'.

Example:

box.schema.func.create('f', {language = 'C', setuid = false})

Specifying if_not_exists=true would cause error: Function '...' already exists if the function already exists.

Specifying setuid=true would cause the setuid flag (the fourth field in the _func tuple) to have a value meaning "true", and the effect of that is that the function's caller is treated as the function's creator, with full privileges. The setuid behavior does not apply for users who connect via console.connect.

Specifying language='C' would cause the language field (the fifth field in the _func tuple) to have a value 'C', which means the function was written in C. Tarantool functions are normally written in Lua but can be written in C as well.

The function for dropping a _func tuple is:

box.schema.func.drop(function-name)

The function for checking whether a _func tuple exists is:

box.schema.func.exists(function-name)

In the following example, a function named 'f7' is created, then it is put in the _func space, then it is used in a box.schema.user.grant function, then it is dropped: