# RBAC: Users, Roles & Policies

Starting at version 7.2.0, CloudAPI supports Role Based Access Control (RBAC), which means that [accounts](https://apidocs.joyent.com/cloudapi/#account) can have multiple users and roles associated with them.

While the behaviour of the [main account](https://apidocs.joyent.com/cloudapi/#GetAccount) remains the same, including the [SSH keys](https://apidocs.joyent.com/cloudapi/#keys) associated with it, it's now possible to have multiple [Users](https://apidocs.joyent.com/cloudapi/#users) subordinate to the main account. Each of these users have a different set of [SSH Keys](https://apidocs.joyent.com/cloudapi/#sshKeys). Both the users and their associated SSH keys have the same format as the main account object (and the keys associated with it).

It's worth mentioning that the `login` for an account's users must be different only between the users of that account, not globally. We could have an account with login *"mark"*, another account "exampleOne" with a user with login "mark", another account "exampleTwo" with another user with login "mark", and so forth.

These account users can additionally be organized using [Roles](https://apidocs.joyent.com/cloudapi/#roles):

```
{
  "id": "ff578c1f-bad5-4d3c-8880-2f76745f2511",
  "name": "devs",
  "members": [
    {
      "type": "subuser",
      "id": "985e0ed4-9994-4303-8c43-6c92b7988167",
      "login": "bob",
      "default": true
    },
    {
      "type": "subuser",
      "id": "0cc38461-787a-4c05-a3f3-352a4d55541f",
      "login": "fred",
      "default": false
    }
  ],
  "policies": [
    {
      "id": "2104c53f-2e33-4393-9320-a6521d5ef2dc",
      "name": "createMachine"
    },
    {
      "id": "e8bdd555-eef0-4c1c-83be-93c443b59e3e",
      "name": "restart instances"
    }
  ]
}
```

Each role can have an arbitrary set of [Policies](https://apidocs.joyent.com/cloudapi/#policies):

```
{
  "name": "restart instances",
  "id": "e8bdd555-eef0-4c1c-83be-93c443b59e3e",
  "rules": [
    "CAN rebootmachine if requesttime::time > 07:30:00 and requesttime::time < 18:30:00 and requesttime::day in (Mon, Tue, Wed, THu, Fri)",
    "CAN stopmachine",
    "CAN startmachine"
  ],
  "description": "This is completely optional"
}
```

The `rules` in policies are used for the access control of an account's users. These rules use [Aperture](https://github.com/joyent/node-aperture) as the policy language, and are described in detail in the next section.

Our recommendation is to limit each policy's set of rules to a very scoped collection, and then add one or more of these policies to each group. This aids easily reusing existing policies for one or more roles, allowing fine-grained definition of each role's abilities.

### Rules definition for access control <a href="#rules-definition-for-access-control" id="rules-definition-for-access-control"></a>

As mentioned earlier, the policies' rules use [Aperture Policy Language](https://github.com/joyent/node-aperture#policy-language), with the following *basic format*:

`<principals> CAN <actions> <resources> WHEN <conditions>`.

You should refer to the [Aperture documentation](https://github.com/joyent/node-aperture) for the complete details about the different possibilities when defining new rules. This section will only cover a limited set strictly related to CloudAPI's usage.

In the case of CloudAPI, `<principal>` will be always the user performing the HTTP request. Likewise, `<resource>` will always be the URL of such request, for example `/:account/machines/:instance_id`.

We add one or more roles to a resource to explicitly define the active roles a user trying to access a given resource must have. Therefore, we don't need to specify `<principal>` in our rules, since it'll always be defined by the role-tags of the resource the user is trying to get access to. For the same reason, we don't need to specify `<resource>` in our rules.

Therefore, CloudAPI's Aperture rules have the format:

```
    CAN <actions> WHEN <conditions>
```

By default, the access policy will `DENY` any attempt made by any account user to access a given resource, unless:

* that resource is tagged with a role
* that role is active
* that role has a policy
* that policy contains a rule which explicity `GRANTS` access to that resource

For example, a user with an active role `read`, which includes a policy rule like `CAN listmachines and getmachines` will not get access to resources like `/:account/machines` or `/:account/machines/:instance_id` unless these resources are *role-tagged* with the role `read` too.

Additionally, given that the `<actions>` included in the policy rule are just `listmachines` and `getmachine`, the user will be able to retrieve an instance's details provided by the [GetMachine](https://apidocs.joyent.com/cloudapi/#GetMachine) action, but will not be able to perform any other instance actions (like [StopMachine](https://apidocs.joyent.com/cloudapi/#StopMachine)). However, if the role has a rule including that `<action>` (like StopMachine), or the user has an additional role which includes that rule, then the user can invoke that action too.

As an aside, the active roles of a user are set by the `default_members` attribute in a role. If three different roles contain the "john" user (amongst others) in their default-members list, then the "john" user will have those three roles as active roles by default. This can be overridden by passing in `?as-role=<comma-separated list of role names>` as part of the URL, or adding a --role flag when using a node-smartdc command; provided that each role contains that user in their `members` list, then those roles are set as the currently-active roles for a request instead.

For more details on how Access Control works for both CloudAPI and Manta, please refer to [Role Based Access Control](https://docs.joyent.com/jpc/rbac/) documentation.

#### An important note about RBAC and certain reads after writes <a href="#an-important-note-about-rbac-and-certain-reads-after-writes" id="an-important-note-about-rbac-and-certain-reads-after-writes"></a>

CloudAPI uses replication and caching behind the scenes for user, role and policy data. This implies that API reads after a write on these particular objects can be up to several seconds out of date.

For example, when a user is created, CloudAPI returns both a user object (which is up to date), and a location header indicating where that new user object actually lives. Following that location header may result in a 404 for a short period.

As another example, if a policy is updated, the API call will return a policy object (which is up to date), but GETing that URL again may temporarily return a outdated object with old object details.

For the time being, please keep in mind that user, role and policy creation/updates/deletion may potentially take several seconds to settle. They have eventual consistency, not read-after-write.<br>
