...
Currently, the APIChecker interface defines the mechanism to enforce role-based access controls on API calls. This interface is implemented by API plugins to provide alternative permission storage and enforcement schemes. To support this enhancement a new plugin will implement a DynamicRoleBasedAPIAccessChecker that will store the permission definitions in the management server database. This plugin will also contain API endpoints and user interface extensions to support the run time modification of the available roles, as well as, their API permission mappings.
When upgrading, CloudStack will continue to use the StaticRoleBasedAPIChecker, but will provide the ability to switch to DynamicRoleBasedAPIAccessChecker using a global setting. All new installations though will default to the DynamicRoleBasedAPIAccessChecker with a goal to deprecate the current StaticRoleBasedAPIChecker with future releases. For insuring the root admin is not locked out of the system, user/account that are root admin (of role type Admin and role id:1) will be allowed to access all APIs.
The client UI will only be modified to determine the user’s role type dynamically. It will not be modified to enable/disable elements based on a user’s permissions. Therefore, all actions would be rendered in the UI, say for a read-only admin. If a user attempts to invoke actions for which they do have access, an error message will be displayed. Finally, the plugin will be built assuming that all management servers in a cluster use the same APIChecker plugin implementation (e.g. StaticRoleBaseAPIChecker, DynamicRoleBasedAPIAccessChecker, etc).
CloudStack UI and management server have assumptions around role types. Therefore, to support this all dynamic roles will resolve to one of the four role types: Admin, ResourceAdmin, DomainAdmin and User. To maintain this semantic, the system will ensure that four default roles always exist tied to these four role types.
Both roles and role-permissions related APIs can only be allowed for and executed by root admins.
Role Management Related
listRoles Lists dynamic roles in CloudStack
Parameters
==========
id = (uuid) List role by role ID.
type = (string) List role by role type, valid options are: Admin, ResourceAdmin, DomainAdmin, User.
name = (string) List role by role name.
createRole Creates a role
Required params are type name
Parameters
==========
name = (string) creates a role with this unique name
type = (string) The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User
description = (string) The description of the role
updateRole Updates a role
Required params are id
Parameters
==========
id = (uuid) ID of the role
name = (string) creates a role with this unique name
type = (string) The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User
description = (string) The description of the role
deleteRole Deletes a role
Required params are id
Parameters
==========
id = (uuid) ID of the role
Role Permissions Related
listRolePermissions Lists role permissions
Parameters
==========
roleid = (uuid) ID of the role
createRolePermission Adds a API permission to a role
Required params are rule permission roleid
Parameters
==========
rule = (string) The API name or wildcard rule such as list*
permission = (string) The rule permission, allow or deny. Default: deny.
roleid = (uuid) ID of the role
updateRolePermission Updates a role permission
Required params are id
Parameters
==========
rule = (string) The name of the API or wildcard rule such as list*
id = (uuid) ID of the role permission
description = (string) The description of the role permission
permission = (string) The rule permission, allow or deny. Default: deny.
deleteRolePermission Deletes a role permission
Required params are id
Parameters
==========
id = (uuid) ID of the role permission
Note: A role permission rule can be a string with a wildcard (*) which will be expanded as \w* to do regex based matching against requested API's name.
Account Creation Changes
Implement DynamicRoleBasedAPIAccessChecker that implements checkAccess() based on whether the user's role was allowed to request an API by querying the database.
The process of checking user account access for a request API will be as follows:
A PermissionDeniedException will be thrown when API needs to be denied for a caller user account.
Example - to create a read-only role, such a role need to first allow all list operation, i.e. list*-allow rule and then explicitly say a *-deny rule to avoid any API that may be allowed/enabled due to annotation rules.
A. Table for Dynamic roles
roles:
id (bigint, auto increment),
uuid (varchar, unique),
name (varchar, unique),
role_type (enum/string),
description (text),
removed (datetime)
B. Table for mappings between roles and enabled apis
role_permissions:
id (bigint, auto increment),
role_id (bigint),
rule (varchar),
permission (allow or deny, enum/string),
description (text)
C. Changes to existing tables
Introduce new column in cloud.accounts table: role_id
The getRoleType() method for Accounts will use the dynamic roles table to translate the account to a role type.
Introduction of the role_id column in accounts table would also require us to make rebuild view with the column: account_view and user_view.
D. Data migration and Upgrade Strategy
Older installations can migrate to the new DynamicRoleBasedAPIAccessChecker, for this the old rules from commands.properties will need to be migrated to the role_permissions table. This can be done in a Java based upgrade path.
As an example, this python script shows how we can read rules from the commands.properties file and insert the enabled APIs in the role_permissions table: https://gist.github.com/bhaisaab/646f9bf27ab2198f8b2d
DB upgrade path process:
E. Upgrade recommendations for future API/Plugin author
New APIs can be enabled by default by setting list of allowed roletypes in @ApiCommand authroized field to set default rules. So, after upgrading CloudStack when new plugins will bring in new APIs; if those APIs don't match any pre-defined allow/deny rules, their annotations will be used to check against calling user account's role type to determine API access. Alternatively, for a given set of roles by listing roles of a given type (admin, resource admin, domain admin or user) and they can add upgrade path which will add permission to allow their new apis for a set of roles in role_permissions table. Set of new APIs per release can be listed in all future release notes and after an upgrade the root admins can choose to add/remove API permissions for roles at their discretion.
The purpose of the API doc is to share information about an API to its users. With this feature, there might be various roles with various API permissions. Also the previous API docs for root admin, domain admin and user were based on the default commands.properties file, which could be different in different deployments. It is proposed that with this feature, we can remove commands.properties file and fix the ApiXmlDocWriter such that it outputs a unified API doc covering all the APIs available in a release irrespective of available user type or roles (root domain, domain or user etc).
List of available roles to shown in dropdown, in ui/scripts/accounts.js, so that admin define roles can be selected when an account is created. Role and role-rule management from UI.