Using Access Control with CloudAPI

Stability: Stable

You can use role based access control to limit the users who can work with instances and other objects in your Joyent Cloud account by assigning roles to CloudAPI endpoints.

Resources in CloudAPI

In Manta resources are Manta objects. For CloudAPI, resources are CloudAPI endpoints that look like this:

Resource CloudAPI Documentation Section
/:account/machines/ Machines
/:account/users/ Users
/:account/roles/ Roles
/:account/packages/ Packages
/:account/images/ Images
/:account/policies/ Policies
/:account/keys/ Keys
/:account/datacenters/ Datacenters
/:account/analytics/ Analytics
/:account/fwrules/ Fwrules
/:account/networks/ Networks
/:account/instrumentations/ Instrumentations

The :account element can be either the literal my or it can be an account name. The literal my means the account name specified in the the --account option of a CloudAPI CLI command, or, if missing, the account name specified by the SDC_ACCOUNT environment variable.

In Manta, objects inherit roles from its parent directory. In CloudAPI roles are never inherited. You must provide a role to each resource that requires one.

If a user in an account creates an object, such as an instance, the new object is tagged with that user's default roles, and any role the user assumed when the object was created. You can see an example of this in the section Writing a Role for Instance Creation later in this page.

Working with CloudAPI and Access Control

Assume we have some instances running in the datacenter.

$ sdc-listmachines | json -a id name
db1186a7-e908-632e-d609-ed960ed8bac1 first
dbdd81f1-43a7-4adb-a5cd-d18655c4b682 second
ad4c95dc-c813-6b63-b3b4-fc4515d36951 third

Maria can't do this because there's no default role that lets her list machines.

$ sdc-listmachines --user=maria --keyId=$MARIA_KEY
sdc-listmachines: error (NotAuthorized): You do not have permission to access /philip/machines (listmachines)

But we can user sdc-user get --membership and see that she's an administrator.

$ sdc-user get 8e9fcc58-3240-4e33-d145-fad9d92c6822 --membership
{
  "id": "8e9fcc58-3240-4e33-d145-fad9d92c6822",
  "login": "maria",
  "email": "maria@example.com",
  "city": "Boston",
  "roles": [
    "contractor",
    "support",
    "administrator",
    "listing"
  ],
  "default_roles": [],
  "updated": "2014-07-21T22:54:34.586Z",
  "created": "2014-07-17T15:32:48.029Z"
}

If Maria assumes the administrator role, she's able to list the machines in the datacenter.

$ sdc-listmachines --user=maria --keyId=$MARIA_KEY --role=administrator| json -a id name
db1186a7-e908-632e-d609-ed960ed8bac1 first
dbdd81f1-43a7-4adb-a5cd-d18655c4b682 second
ad4c95dc-c813-6b63-b3b4-fc4515d36951 third

Creating a List-Only Role

Let's make a role, listing, that allows someone to list all the instances, images, and packages available to the account. The listonly role has a single policy called canlist.

First, let's create the policy.

$ sdc-policy create --name=canlist \
                    --rules='CAN listmachines' \
                    --rules='CAN listimages' \
                    --rules='CAN listpacakges'
{
  "name": "canlist",
  "id": "ef21ba5c-ea15-4690-a074-d24cade9b9f6",
  "rules": [
    "CAN listimages",
    "CAN listmachines",
    "CAN listpackages"
  ]
}

The actions in the rules say that members of the role who use this policy, can list images, list instances (machines), and list packages. You an see a full list of valid CloudAPI actions here.

Now let's create the role listing.

$ sdc-role create --name=listing \
                  --members=maria \
                  --members=bob \
                  --default-members=bob \
                  --policies=canlist
{
  "name": "listing",
  "id": "0596598a-8bb6-6c11-edd2-ccd2dfc4437f",
  "members": [
    "bob",
    "maria"
  ],
  "default_members": [
    "bob"
  ],
  "policies": [
    "canlist"
  ]
}

Tagging CloudAPI Resources with Roles

Before we can use those roles, however, we have to associate them with a resource. In CloudAPI resources are REST endpoints.

Use the sdc-chmod command to tag the corresponding endpoints for the listimages, listmachines, and listpackages actions with the listing role:

$ sdc-chmod -- +listing /my/machines
["listing"]
$ sdc-chmod -- +listing /my/packages
["listing"]
$ sdc-chmod -- +listing /my/images
["listing"]

Bob is a default member, so he can list instances (machines), images, and packages without assuming a role.

$ sdc-listmachines --user=bob --keyId=10:d0:59:ef:4f:71:3b:8b:4b:6a:05:d2:57:24:28:27 | json -a id
db1186a7-e908-632e-d609-ed960ed8bac1
dbdd81f1-43a7-4adb-a5cd-d18655c4b682
ad4c95dc-c813-6b63-b3b4-fc4515d36951

$ sdc-listimages --user=bob --keyId=10:d0:59:ef:4f:71:3b:8b:4b:6a:05:d2:57:24:28:27
[
  {
    "id": "2b683a82-a066-11e3-97ab-2faa44701c5a",
    "name": "base",
    "version": "13.4.0",
    "os": "smartos",
. . .
]

But Bob cannot create new instances:

$ sdc-createmachine --user=bob \
                    --keyId=10:d0:59:ef:4f:71:3b:8b:4b:6a:05:d2:57:24:28:27 \
                    --image=bae9b95e-10c0-11e4-89d4-9fb9155d8bda \
                    --package=2eac03a7-ea7f-4215-fb66-e2ef510f2cde
sdc-createmachine: error (NotAuthorized): You do not have permission to access /philip/machines (createmachine)

Writing a Role for Instance Creation

To allow Bob to create new instances, we need a new policy and a new role.

The basicmachineops policy allows a user to do some basic things with instances, but not others. For example, the policy allows a user to provision an instance but not to delete or rename it.

$ sdc-policy create --name=basicmachineops
                    --rules='CAN listmachines' \
                    --rules='CAN createmachine' \
                    --rules='CAN getmachine' \
                    --rules='CAN stopmachine' \
                    --rules='CAN restartmachine'
{
  "name": "basicmachineops",
  "id": "15d05417-1edc-4f80-9946-bf288d8a58ae",
  "rules": [
    "CAN listmachines",
    "CAN createmachine",
    "CAN getmachine",
    "CAN stopmachine",
    "CAN restartmachine"
  ]
}

The role `basicmachine` will allow Bob
to perform basic instance-related tasks.

$ sdc-role create --name="basicmachine" \
                  --members=bob \
                  --default-members=bob \
                  --policies=basicmachineops
{
  "name": "basicmachine",
  "id": "2e7ec1ed-6b33-69d2-c5ea-b8df1657e90f",
  "members": [
    "bob"
  ],
  "default_members": [
    "bob"
  ],
  "policies": [
    "basicmachineops"
  ]
}

Now tag the /my/machines resource with the new role:

$ sdc-chmod -- +basicmachine /my/machines
["listing","basicmachine"]

Now Bob can create a machine:

$ sdc-createmachine --user=bob \
                    --keyId=10:d0:59:ef:4f:71:3b:8b:4b:6a:05:d2:57:24:28:27 \
                    --image=bae9b95e-10c0-11e4-89d4-9fb9155d8bda \
                    --package=2eac03a7-ea7f-4215-fb66-e2ef510f2cde
{
  "id": "e571f3ab-2f2b-6b9d-8098-be5d2c39c1ee",
  "name": "e306e5e",
  "type": "smartmachine",
  "state": "provisioning",
  "image": "bae9b95e-10c0-11e4-89d4-9fb9155d8bda",
  "ips": [],
  "memory": 128,
  "disk": 1280,
  "metadata": {
    "root_authorized_keys": "ssh-rsa AAAAB3NzaC1yc2...M384hFfS4PQ== \n"
  },
  "tags": {},
  "created": "2014-08-05T03:20:37.319Z",
  "updated": "2014-08-05T03:20:37.319Z",
  "networks": [],
  "dataset": "sdc:sdc:base:14.2.0",
  "firewall_enabled": false,
  "compute_node": null,
  "package": "test_128"
}

Note that since bob created the machine, that resource is tagged with all of Bob's active roles. These are all of Bob's default roles as well as any role he assumed when creating the machine.

$ sdc-info /my/machines/e571f3ab-2f2b-6b9d-8098-be5d2c39c1ee
[
  "manager",
  "listing",
  "basicmachine"
]

Writing Roles and Policies for Individual Resources

You can use roles to apply to individual instances (machines). This policy allows a user to start, stop, and reboot an instance:

$ sdc-policy create --name=startstop \
                    --rules='CAN rebootmachine' \
                    --rules='CAN stopmachine' \
                    --rules='CAN startmachine'
{
  "name": "startstop",
  "id": "6544f677-58b1-4c8d-e701-f7b6a61ab4b0",
  "rules": [
    "CAN rebootmachine",
    "CAN stopmachine",
    "CAN startmachine"
  ]
}

And this role allows jill to start, stop, and restart instances:

$ sdc-role create --name=startstop \
                  --members=jill \
                  --default-members=jill \
                  --policies=startstop
{
  "name": "startstop",
  "id": "73a39ab7-4192-6636-a8d9-9a981cc4fb79",
  "members": [
    "jill"
  ],
  "default_members": [
    "jill"
  ],
  "policies": [
    "startstop"
  ]
}

You can assign the startstop role to a specific instance:

$ sdc-chmod -- +startstop /my/machines/db1186a7-e908-632e-d609-ed960ed8bac1
["startstop"]

Now jill can stop that machine:

$ sdc-stopmachine db1186a7-e908-632e-d609-ed960ed8bac1 \
                  --user=jill --keyId=10:d0:59:ef:4f:71:3b:8b:4b:6a:05:d2:57:24:28:27
{}
$ sdc-getmachine db1186a7-e908-632e-d609-ed960ed8bac1 | json state
stopped

But Jill cannot stop other machines:

$ sdc-stopmachine ad4c95dc-c813-6b63-b3b4-fc4515d36951 \
                  --user=jill --keyId=10:d0:59:ef:4f:71:3b:8b:4b:6a:05:d2:57:24:28:27
sdc-stopmachine: error (NotAuthorized): You do not have permission to access /philip/machines/ad4c95dc-c813-6b63-b3b4-fc4515d36951 (stopmachine)