RethinkDB controls access to clusters through a system based around users, permissions, and scopes. Together, these allow you to specify fine grained control for reading, writing and administrative access down to a per-table level.
A user in RethinkDB is similar to users in most other database systems; a database administrator may have a user account, and client applications may be given user accounts. These are unrelated to user accounts that may be implemented within the application.
Users are created by inserting documents into the users
system table. Every user has an account name in the id
field, and an optional password.
r.db('rethinkdb').table('users').insert({id: 'bob', password: 'secret'})
If you read this document back, you’ll get this:
{
"id": "bob",
"password": true
}
The password
field is simply a boolean indicating whether a password is set or not. There is no way to read a password from the database.
You can update the password to a new value, or remove it by setting it to false
.
r.db('rethinkdb').table('users').get('bob').update({password: false})
You cannot change a username once it’s been created. You can, however, delete users from the table.
By default, RethinkDB will use 4096 iterations for hashing passwords during the connection handshake between client drivers and the server. There is an option to set iterations on a per-account basis by setting passwords to an object of the form {password: "password", iterations: 4096}
. If you wished to use only 1024 iterations, you could set a password like so:
r.db('rethinkdb').table('users').insert({id: 'bob', password: {password: 'secret', iterations: 1024}})
Note that you will not be able to read the iterations
value for an account; as it’s stored in the password field, it remains read-only.
The value for iterations
is a tradeoff between performance and security against brute force attacks. If connections are slow, consider lowering the number of iterations. Raising the number of iterations will make it harder to use a brute force attack, but will increase the CPU usage on clients while establishing a connection.
A new RethinkDB cluster always has one user named admin
; this user always has all permissions at a global scope, and the user cannot be deleted. By default, the admin
user has no password. You can change this by updating the admin
user document, or by specifying the --initial-password
command line option on startup.
The web administration UI always connects as if it were the admin
user, and skips the authentication process (i.e., the password is not used for this connection). While the web UI cannot be password-protected, you can limit the addresses it will accept connections on using the --bind-http
command line option. For more details on this, review Secure your cluster.
If you forget the admin password, it can be changed from the Data Explorer using update
as described above.
There are four different permissions that can be granted to a user:
read
allows reading the data in tables.write
allows modifying data, including inserting, replacing/updating, and deleting.connect
allows a user to open HTTP connections via the http command. Restricting this offers security against an exploit in your code being used to circumvent firewall restrictions.config
allows users different abilities, depending on its scope:
reconfigure
and rebalance
).config
permissions for the tables within a database to drop them, which might not be the case if their config
permissions are overridden at a table level; see Scopes below.)Permissions are stored in the permissions
system table. While you can change permissions by modifying documents within that table, it’s far more convenient to use the grant command; see below.
The read
, write
and config
permissions can be specified on three scopes, from most granular to least:
Permissions specified at a lower level will override permissions set at a higher level: a user could be granted read and write access to the field_notes
database, but denied the ability to write to the calendar
table and to either read or write to the supervisor_only
table.
User: notesapp
database "field_notes" { read: true, write: true, config: false }
table "calendar" { write: false }
table "supervisor_only" { read: false, write: false }
The calendar
table inherits read: true
from the database level, but specifies write: false
to make the table ready-only for notesapp
. The supervisor_only
table overrides both read and write access. The notesapp
account has read and write access to all other tables in the field_notes
database, but no ability to create and drop indexes or change any table’s cluster configuration.
The ReQL grant command is used to grant and revoke permissions for users. The scope is selected by chaining grant
after db
(for database scope), table
(for table scope), or calling it directly (for global scope).
r.grant("user", {permissions}) → object
table.grant("user", {permissions}) → object
db.grant("user", {permissions}) → object
To specify the permissions described above for Bob, you would execute the following ReQL commands:
// set database scope
r.db('field_notes').grant('bob', {read: true, write: true, config: false});
// set table scopes
r.db('field_notes').table('calendar').grant('bob', {write: false});
r.db('field_notes').table('supervisor_only').grant('bob', {read: false, write: false});
API documentation for grant
:
Also, read about: