Table of Contents | ||||
---|---|---|---|---|
|
Currently CloudStack provides very limited IAM services and there are several drawbacks within those services:
...
Gliffy Diagram | ||||
---|---|---|---|---|
|
Group contains a number of CloudStack accounts. Customers should be able to Create, Edit, List and Delete Groups. Editing includes adding or removing accounts to or from a group. For backwards compatibility, out of box, CloudStack will provide 3 default groups:
...
The IAM plugin will provide another implementation 'PolicyBasedAccessChecker' of the SecurityChecker interface. We will also have to add to this interface some more methods or change some signatures to facilitate group, policy and api name (action) based access control.
Code Block |
---|
/**
* SecurityChecker checks the ownership and access control to objects within
*/
public interface SecurityChecker extends Adapter {
...
/**
* Checks if the account can access the object.
*
* @param caller
* account to check against.
* @param entity
* object that the account is trying to access.
* @param accessType
*
* @param action
*
* @return true if access allowed. false if this adapter cannot provide permission.
* @throws PermissionDeniedException
* if this adapter is suppose to authenticate ownership and the check failed.
*/
boolean checkAccess(Account caller, ControlledEntity entity, AccessType accessType, String action) throws PermissionDeniedException;
....
}
|
...
IAM Plugin 'PolicyBasedAccessChecker' will implement the APIChecker interface.
Code Block |
---|
// APIChecker checks the ownership and access control to API requests
public interface APIChecker extends Adapter {
// Interface for checking access for a role using apiname
// If true, apiChecker has checked the operation
// If false, apiChecker is unable to handle the operation or not implemented
// On exception, checkAccess failed don't allow
boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException;
}
|
...
Besides SecurityChecker and APIChecker interface, IAM plugin will also implement another QueryChecker interface to allow CloudStack to do proper row filter in ListAPI based on caller's policy. In this phase, we only support explicitly grant permission, not deny permission.
Code Block |
---|
/**
* QueryChecker returns granted domain, or account or resources for caller.
*/
public interface QueryChecker extends Adapter {
...
/**
* List granted domains for the caller, given a specific entity type.
*
* @param caller account to check against.
* @param entityType entity type
* @return list of domain Ids granted to the caller account.
*/
List<Long> getAuthorizedDomains(Account caller, String entityType);
/**
* List granted accounts for the caller, given a specific entity type.
*
* @param caller account to check against.
* @param entityType entity type
* @return list of domain Ids granted to the caller account.
*/
List<Long> getAuthorizedAccounts(Account caller, String entityType);
/**
* List granted resources for the caller, given a specific entity type.
*
* @param caller account to check against.
* @param entityType entity type
* @return list of domain Ids granted to the caller account.
*/
List<Long> getAuthorizedResources(Account caller, String entityType);
|
...
We will separate all current both admin and user allowed API commands to two classes: API for admin and API for user. For example, previous ListVMsCmd will be splitted into two classes: ListVMsCmdByAdmin and ListVMsCmd.
Code Block |
---|
@APICommand(name = "listVirtualMachines", description = "List the virtual machines owned by the account.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted)
public class ListVMsCmd extends BaseListTaggedResourcesCmd {
......
}
@APICommand(name = "listVirtualMachines", description = "List the virtual machines owned by the account.", responseObject = UserVmResponse.class, responseView = ResponseView.Full)
public class ListVMsCmdByAdmin extends ListVMsCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.HOST_ID, type=CommandType.UUID, entityType=HostResponse.class,
description="the host ID")
private Long hostId;
@Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class,
description="the pod ID")
private Long podId;
@Parameter(name=ApiConstants.STORAGE_ID, type=CommandType.UUID, entityType=StoragePoolResponse.class,
description="the storage ID where vm's volumes belong to")
private Long storageId;
}
|
Note that ListVMsCmdByAdmin and ListVMsCmd are sharing the same API name "listVirtualMachines". From client perspective, this is transparent to them, CloudStack API client will still just invoke previous listVirtualMachine API, and CloudStack API server will internally consult with IAM plugin to determine the group associated with the invoking user and then determine which internal Cmd class to be invoked. There is a new attribute "responseView" introduced for @APICommand annoation, which can be used to instruct CloudStack to generate different response view. By separating the command class into admin cmd class and user cmd class, we can also restrict valid input parameters for different account. For example, in this case, when Admin invokes listVirtualMachine api, he/she can pass hostId, podId and storageId, which parameters are not applicable for end user.
...
The StartVMCmd will contain an annotation on the field that needs to be checked for access:
Code Block |
---|
@APICommand(name = "startVirtualMachine", responseObject = UserVmResponse.class, description = "Starts a virtual machine.")
public class StartVMCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(StartVMCmd.class.getName());
private static final String s_name = "startvirtualmachineresponse";
// ///////////////////////////////////////////////////
// ////////////// API parameters /////////////////////
// ///////////////////////////////////////////////////
@ACL(action="startVirtualMachine")
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType=UserVmResponse.class,
required = true, description = "The ID of the virtual machine")
private Long id;
|
...
What should be the method of ‘creating a custom Policy/Role’?
For this release, creating a custom policy is supported through API only.
For further releases, we can provide either a UI or a config file + policy language mechanism to facilitate the custom policy creation.
IAM feature will be making use of CloudStack's plugin framework and will be implemented as a separate plugin. The end goal is to be able to host the IAM server as an independent service listening at an endpoint which the CS API service calls to do access checks.
IAM plugin will be developed under cloudstack-services project so that in future it can be easily separated as a service.
Following is the code base structure for the IAM feature:
cloud-iam service will be having two parts:
...
Following component diagram illustrates these boundaries:
Gliffy Diagram | ||
---|---|---|
|