Security
This page covers FaunaDB’s administrative security and application security:
Beginning with FaunaDB 2.11.0, the FaunaDB access control logic has been changed to use attribute-based access control (ABAC) roles, or the key-based permission system, but never both. If a resource is a member of an ABAC role, the ABAC role specifies all privileges for that resource. Otherwise, the key-based permission system determines whether read/write/execute privileges are enabled. For example, when an ABAC role includes a user-defined function as a
member, that function cannot be called unless the ABAC privileges permit
the |
FaunaDB key system
Access to the FaunaDB API uses secrets that correspond to access keys, which authenticate connections as having particular permissions. The access key system applies both to administrator- and server-level connections, as well as to object- and user-level connections.
Keys are defined as documents within the keys collection. Like databases, keys exist within the system-global root database context.
Keys are tied to a specific database and allow access to its contents. If no database is specified, the key grants access to the database in which it was created. The level of access a key provides depends on its role.
You must copy the key’s secret
out of the key when it is first created
and store it securely. Only a BCrypt hash of the key is stored on disk.
It is impossible to recover the key’s secret if it is discarded.
Field name | Value type | Description |
---|---|---|
|
String |
The key’s role. Either |
|
String |
The key’s authentication secret. Only present on creation. |
|
String |
The key’s hashed authentication secret. |
|
Number |
A priority between 1 and 500, inclusive. Defaults to 1. |
|
Database ref |
The database associated with this key. Optional. |
|
Object |
A JSON object. Optional. |
Access keys
Keys belong to one of four built-in roles, either admin
, server
,
server-readonly
, or client
, or to one or more used-defined roles.
Admin keys
Keys with the admin
role are used for managing databases, keys, and
user-defined roles. An admin key can be used to create and destroy
databases and keys. They should be very well protected.
Admin keys for FaunaDB accounts are managed in the FaunaDB Console.
Server keys
Keys with the server
role bypass all permission checks within the
database they’re assigned to. Because they provide unrestricted access,
they should be well protected and only used in trusted or server-side
environments.
Server read-only keys
Keys with the server-readonly
role allow read-only access to all data
within the database that they are assigned to. Because they provide
unrestricted read access, they should be well protected and only used in
trusted or server-side environments.
Client keys
Keys with the client
role are restricted to actions and resources that
are specifically marked with the public
permission. Because their
access is controlled, they are suitable for embedding in untrusted
environments, such as mobile clients.
Typically they are used as part of an application’s user authentication flow, or to access public data, such as an application’s logged-out view.
User-defined roles
User-defined roles provide configurable, domain-specific, security
rules. Roles are created with the CreateRole
function, and have the
following structure:
Field name | Value type | Description |
---|---|---|
|
String |
The role’s name. |
|
VarArgs |
One or more privilege configuration objects. |
|
VarArgs |
Optional. One or more membership configuration objects. |
User-defined roles can only be managed with an admin key. |
Privilege configuration object
A privilege configuration object defines, for a given resource, what actions are permitted.
Field name | Value type | Description |
---|---|---|
|
Reference |
A reference to a collection, index, set, or user-defined function. |
|
Object |
An object containing key-value pairs, where the keys are action names, and the values are either a boolean value to indicate whether access is permitted, or a predicate function that can compute whether access is permitted. |
The available actions are:
-
create
: permits the create of new documents, collections, or set. -
delete
: permits the deletion of existing documents, collections, or sets. -
read
: permits the reading of documents, collections, sets, or indexes. -
write
: permits writing to existing documents within a collection. -
history_read
: permits reading historical versions of a document, collection, or set. -
history_write
: permits inserting events into the history for an existing document or set. -
unrestricted_read
: permits the reading of an index without considering any otherread
permissions. -
call
: permits the calling of user-defined functions.
When configuring read access to an index, both the read
and
unrestricted_read
actions are permitted. The read
action grants access
to the index’s data. However, an additional read
permission check is
performed before allowing access to the indexed document, which filters
out references that the user cannot read. The unrestricted_read
action
disables the additional check, returning all of the documents associated
with the index.
An action’s value can be a boolean, to indicate whether the action is
permitted or not, or a read-only lambda predicate function. Lambda
predicate functions must be created using a
query, using the same format that the
CreateFunction
function
accepts. The predicate function takes different parameters depending on
the configured action. Predicates must return a boolean value where
true
grants the action, and false
denies it.
The parameters to a predicate function are:
Action | Argument(s) | Description |
---|---|---|
|
Object |
An object containing the new document’s data. |
|
Reference |
The reference to the document to be deleted. |
|
Reference, or index terms |
A reference to the document to be read, or one or more terms to be matched against the target index. |
|
Object, Object |
Two objects, one containing the original document data, and the second containing the new document data to be written. |
|
Reference |
The reference to the document to be read. |
|
Reference, Timestamp, String, Object |
The reference to the document to be written, the timestamp to write to (which may create or update an event depending on existence of a matching timestamp), the action string, and an object containing the new document data. |
|
Index terms |
The terms matched against the target index. |
|
Parameters |
The parameters that are to be passed to the user-defined function. |
Membership configuration object
A membership configuration object dynamically defines which authenticated resources are members of a given role. Tokens are covered in the next section.
Field name | Value type | Description |
---|---|---|
|
Reference |
A reference to a collection in which its documents are members of the configured role. |
|
Query |
Optional. A read-only lambda predicate function that takes the reference of the authenticated resource and returns a boolean value that indicates whether the referenced resource is a member of the configured role. |
Tokens
Tokens, like keys, allow direct access to FaunaDB. Their use is
optional. Each token is created by calling the
Login
function with a
reference to a document that has
credentials defined, and a password.
Once a token has been created, it can be used to connect to FaunaDB and execute queries in the same database as the credentialed document. Queries executed with a token have Attributed-based access control (ABAC) permissions applied. When a document is a member of a user-defined role, that role is used to evaluate that the query privileges available to that document.
Permissions
FaunaDB has a built-in permissions system that allows for fine-grained control over access to data.
Access is controlled by a resource’s permissions object. The identity of a request’s key is checked against the value of the permission field corresponding to the resource and action being taken.
Permission fields may be set to one of the following values:
Value | Access Allowed |
---|---|
empty |
Only server keys are allowed. |
"public" |
Any key is allowed. |
document ref |
Only tokens belonging to the specified document are allowed. |
collection ref |
Only tokens belonging to documents in the specified collection are allowed. |
Collection permissions
Creating, reading, and modifying a document in a collection is controlled by the collection’s permissions. Applicable fields on a collection are:
Permission Field | Action Allowed |
---|---|
|
Creating a document in the collection. |
|
Reading documents in the collection. |
|
Writing to document in the collection. |
A document also has permissions, which are applied in addition to permissions defined on its collection. The permissions on a document may contain these fields:
Permission Field | Action Allowed |
---|---|
|
Reading this document. |
|
Writing to this document. |
User-defined function permissions
Calling a function is controlled by its permissions. Applicable fields are:
Permission Field | Action Allowed |
---|---|
|
Calling the function. |
Index permissions
Query access to an index is controlled by its permissions. Applicable fields are:
Permission Field | Action Allowed |
---|---|
|
Querying the index. |
Delegates
A document may delegate access on its behalf to other documents by
adding the other documents' refs to its delegates
list. Any tokens
belonging to a member of delegates
is granted access as though they
were tokens belonging to the delegating document.
For example, if a user (with id 1) has read access to the "spells" collection, but another user (with id 2) does not, the first user may grant access via delegation to the second user with the following query:
curl https://db.fauna.com/ \
-d '{
"update": { "ref": { "collection": "users" }, "id": 1 },
"params": {
"object": {
"delegates": [ { "ref": { "collection": "users" }, "id": 2 } ]
}
}
}'
client.Query(
Update(
Ref(Collection("users"), 1),
Obj("delegates", Arr(Ref(Collection("users"), 2)))));
client.query(
Update(
Ref(Collection(Value("users")), Value(1)),
Obj("delegates", Arr(Ref(Collection(Value("users")), Value(2))))));
result, _ := client.Query(
f.Update(
f.RefCollection(f.Collection("users"), "1"),
f.Obj{"delegates": f.Arr{f.RefCollection(f.Collection("users"), "2")}},
),
)
fmt.Println(result)
client.query(
Update(
Ref(Collection("users"), 1),
Obj("delegates" -> Arr(Ref(Collection("users"), 2)))))
client.query(
q.update(
Ref(q.collection("users"), 1),
{"delegates": [Ref(q.collection("users"), 2)]}
))
$client.query do
update ref(collection_('users'), 1),
delegates: [ref(collection_('users'), 2)]
end
client.query(
Update(
ref: Ref(collection: Collection("users"), id: 1),
to: Obj(
"delegates" => Arr(Ref(collection: Collection("users"), id: 2))
)
)
)
client.query(
q.Update(
q.Ref(q.Collection('users'), 1),
{ delegates: [q.Ref(q.Collection('users'), 2)] },
)
)
.then((ret) => console.log(ret))
map[ref:{1 0xc420118d80 <nil>} ts:1527631398281881 delegates:[{2 0xc420119000 <nil>}]]
{ ref: Ref(id=1, collection=Ref(id=users, collection=Ref(id=collections))),
ts: 1527631398281881,
delegates: [ Ref(id=2, collection=Ref(id=users, collection=Ref(id=collections))) ] }
Now, when the second user attempts to read from the "spells" collection, they are granted the same level of access as the first user.
Delegates are not transitive — in the example above, the second user may not delegate the first user’s permissions to another user.
Was this article helpful?
We're sorry to hear that.
Tell us how we can improve!
documentation@fauna.com
Thank you for your feedback!