RBAC: Users, Roles & Policies

Starting at version 7.2.0, CloudAPI supports Role Based Access Control (RBAC), which means that accounts can have multiple users and roles associated with them.

While the behaviour of the main account remains the same, including the SSH keys associated with it, it's now possible to have multiple Users subordinate to the main account. Each of these users have a different set of SSH Keys. 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:

{
  "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:

{
  "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 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

As mentioned earlier, the policies' rules use Aperture Policy Language, with the following basic format:

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

You should refer to the Aperture documentation 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 action, but will not be able to perform any other instance actions (like 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 documentation.

An important note about RBAC and certain reads after writes

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.

Last updated