Configuring Security

Kuzzle provides a full set of functionalities to configure fine-grained permissions to your data.


Initial Setup

When Kuzzle is first installed there is no administrator account and anonymous users (i.e. unauthenticated users) have administrative privileges.

To secure your Kuzzle installation you will need to create an administrator account by using the Kuzzle Admin Console.

Once the administrator account is created, you can remove anonymous access rights and properly secure your installation. You can then use the Kuzzle Admin Console or Kuzzle API to create new users and assign them permissions.


Whitelist strategy

In Kuzzle, permissions follow the Whitelist strategy, which means that an action must be explicitly allowed by at least one role of the user profile.

This means that:

  • If a role allows it, the action is authorized, even if another role denies it.
  • If no role explicitly allows it, the action is denied, even if no role explicitly denies it.

User Permissions

User-level permissions control what API actions can be executed and, optionally, restrict those to targeted data indexes and collections.

Users, Profiles and Roles

Kuzzle's security layer links users to one or more profiles. You can think of a profile as a group of users that share the same permissions.

The profiles themselves are made up of different groups of permissions, these groups are called roles.

A profile is linked to a set of roles, and each role defines a set of permissions. For example, in the diagram below, the editor profile is has all permissions, the contributor has a subset of the permissions, and the default profile has only default permissions:

Users, Profiles and Roles

All roles and profiles can be edited in the Kuzzle Admin Console.


Defining Roles

A role can be defined using a hierarchical JSON object where permissions are outlined by controller and action.

The role definition is represented as a JSON object where each key at the root of the object identifies a controller by name.

Copied to clipboard!
{
  "controllers": {
    "<controller name|*>": {
      "actions": {
        "<action name|*>": true,
        "<action name|*>": false,
        // ...
      }
    }
  }
}

The controllers and actions properties can be set to a specific value or to the wildcard value "*".

When controller is declared within a Plugin, its name must be prefixed with the name of the Plugin, like < plugin-name/controller-name >.

The action permission value is a boolean. If true, the role allows the given action.

As an example, below is the role definition that Kuzzle uses to request authorization from the anonymous user once the administrator account is created and anonymous access is blocked.

Copied to clipboard!
{
  "controllers": {
    "auth": {
      "actions": {
        "login": true,
        "checkToken": true,
        "getCurrentUser": true,
        "getMyRights": true
      }
    }
  }
}

In the above role definition, anonymous users can perform the login, checkToken, getCurrentUser and getMyRights actions of the auth controller.

For a list of available controllers and actions from Kuzzle's API by sending a GET request as follows:

Copied to clipboard!
curl -X GET 'http://localhost:7512/?pretty'

Defining Profiles

A profile definition is a JSON object that contains an optional rate limit parameter, and an array of policies.

Rate limit

Available since 2.1.0

The rate limit parameter controls how many API requests a user can send, per second and per node. Further requests made by a user that exceed the limit are rejected with a 429 Too Many Requests error.

If no rate limit is defined, or if it is set to 0, then no limit is applied. If a user has several profiles with rate limits, the most permissive limit applies.

Since unauthenticated users share the same user identifier, a rate limit set on the anonymous profile is applied to all anonymous requests cumulated, per second and per node. Except for the auth:login route, which is statically controlled in Kuzzle's configuration files.

Example:

Copied to clipboard!
{
  "rateLimit": 20,
  "policies": [ /* ...role policies, see below ... */ ]
}

Policies

Each policy is composed of a roleId and an array of restrictions:

Copied to clipboard!
{
  "policies": [
    {
      // Applied to all indexes and collections
      "roleId": "<role identifier>"
    },
    {
      // Restricted to a list of indexes or to a list of collections
      "roleId": "<another role identifier>",
      "restrictedTo": [
        {
          // All collections of this index are allowed
          "index": "<another index name>"
        },
        {
          // Only the specified list of collections are allowed
          "index": "<an authorized index name>",
          "collections": [
            "<authorized collection 1>",
            "<authorized collection 2>",
            "<...>"
          ]
        }
      ]
    }
  ]
};

When adding a role to a profile, by default, it impacts all indexes and collections. For more precise control, roles can be restricted to specific indexes or collections.

For example, consider a "publisher" role allowing any action on the document controller:

Copied to clipboard!
{
  "controllers": {
    "document": {
      "actions": {
        "*": true
      }
    }
  }
}

Three different profiles can be created using that same role, each with varying index/collections restrictions:

  • Applies the publisher role to all indexes and collections
Copied to clipboard!
{
  "policies": [
    {"roleId": "publisherRole"}
  ]
}
  • Applies the publisher role only to the index "index1", and to all its collections
Copied to clipboard!
{
  "policies": [
    {
      "roleId": "publisherRole",
      "restrictedTo": [{"index": "index1"}]
    }
  ]
}
  • Applies the publisher role only to the collections "foo" and "bar" in the index "index1", and then to the index "index2" and all its collections
Copied to clipboard!
{
  "policies": [
    {
      "roleId": "publisherRole",
      "restrictedTo": [
        {"index": "index1", "collections": ["foo", "bar"]},
        {"index": "index2"}
      ]
    }
  ]
}

Writing complex permission rules

So far, we've seen how to set permissions to API routes, using user roles and profiles.

But this is rarely enough to secure an application, as it's commonplace to reject queries or data depending on business rules. For instance, suppose you have a chat application and you want the users to only be able to edit & delete their own messages: this type of rules cannot be expressed as a simple boolean.

There are multiple ways of adding a business logic layer on top of the standard Kuzzle security one:

  • With a Pipe Plugin, you can listen to one or multiple API events, and decide whether you accept a query or document according to your business rules (you can see an example on Github)
  • If all you need is to make sure that submitted documents follow a strict set of formatting rules, you can add document validators