Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

Ticket to track the feature implementation: https://issues.apache.org/jira/browse/CLOUDSTACK-5920

Note: IAM feature cannot be put in to current 4.5 codebase due to API gap and limitations found and documented here: https://cwiki.apache.org/confluence/display/CLOUDSTACK/API+changes

Architecture and Design description

...

Other than that, customer should be able to define customized policies by grant or deny permission to customize permissions for the group. So far, for cross-account permission grant, we are currently supporting the following 3 types of granting/denying:

  • Grant by Domain and Resource Entity Type: grant permissions to all resources of the given resource entity type under the given domain.
  • Grant by Account and Resource Entity Type: grant permissions to all resources of the given resource entity type under the given account.
  • Grant by individual resource: grant permission to an individual resource.

Permission

Entity Type

Here are list of entity types supported by IAM model:

  • VirtualMachine
  • Volume
  • ResourceTag
  • Account
  • AffinityGroup
  • AutoScalePolicy
  • AutoScaleVmProfile
  • AutoScaleVmGroup
  • Condition
  • Vpc
  • VpcGateway
  • VMSnapshot
  • VirtualMachineTemplate
  • StaticRoute
  • Snapshot
  • Site2SiteVpnGateway
  • Site2SiteCustomerGateway
  • Site2SiteVpnConnection
  • SecurityGroup
  • RemoteAccessVpn
  • ProjectInvitation
  • Network
  • IPAddress
  • InstanceGroup
  • GlobalLoadBalancerRule
  • FirewallRule
  • PortForwardingRule
  • Event

Permission

A policy consists of set of Permissions. A Permission is a A policy consists of set of Permissions. A Permission is a way of defining access control.
Using Permission, customer defines what actions are allowed or denied, on what resources, under which account or domain.

...

  • createVPC
  • listVPCs
  • updateVPC

IAM Schema

Image Removed

For APIs not listed above, response will be the same for all the users(root admin, domain admin, normal user) as usual, by default, it is full response view.

IAM Schema

Image Added

IAM IAM API

New API's

  • createIAMGroup
    1. String name - name of the IAM group. Required
    2. String description - short decsription
    3. String domainId - UUID of the domain of the account owning the IAM group

...

  • removeIAMPolicyFromIAMGroup
    1. String id - UUID of the IAM group. Required
    2. List<String> policies- comma separated list of policy ids that are going to be revoked from the IAM group
  • attachIAMPolicyToAccountcreateIAMPermission
    1. String action id - name UUID of the API allowed/deniedIAM policy. Required
    2. List<String> accounts - comma separated list of account id that the policy will attach to

  • removeIAMPolicyFromAccount
    1. String id - UUID of the IAM group. Required
    2. List<String> accounts- comma separated list of account ids 
  • addIAMPermissionToIAMPolicy
    1. String id - UUID of the IAM policy. Required
    2. String action - name of the API allowed/denied. Required
    3. String entityType
    4. String scope-
    5. String permission - "Allow"/ "Deny"
    6. String scope- ("Account" / "Domain" / "Resource")
    7. String scope id - UUID of the Scope
    8. String resourceType
    addIAMPermissionToIAMPolicy
  • removeIAMPermissionFromIAMPolicy
    1. String id - UUID of the IAM policy. Required
    2. List<String> permissionIds - comma separated list of permission ids that are going to be added to the IAM policy
    removeIAMPermissionFromIAMPolicy
    1. String action - name of the API allowed/denied. Required
    2. String entityType
    3. String scope- ("Account" / "Domain" / "Resource")
    4. String scope
    5. String id - UUID of the IAM policy. RequiredList<String> permission Ids - comma separated list of permission ids that are going to be removed from the IAM policyScope

 

In Phase1, these new IAM APIs are only limited to root admin.

IAM Interface

IAM Interface to check Entity Access

...

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;

....
}

The implementation will check if a given user is permitted to invoke the given 'action' on the given resource by looking at the account's groups and the associated policies of those groups.

For given user, resource and given api name, default permission is 'deny', then run through this:

...



/**
* Enumeration type for AccessType
*/
public enum AccessType {
	ModifyProject,
    OperateEntry,
    UseEntry,
	ListEntry
 }
AccessType
  • Until 4.4, CloudStack did not distinguish between a read-only access Vs read-and-use access Vs operate access. 
  • CloudStack access control layer always checked if the caller is owner of the entity and granted all types of access based on that. 
  • With IAM feature following are the types of entity access one can specify:
    1. ListEntry  (read only access)
    2. UseEntry  (read and use access)
    3. OperateEntry (operate/execute access)

Example: A domainAdmin registers a template T and allows a regular user of the domain to launch a VM using that template.

Entity: TemplateT
Principal1:  domainAdmin, Access allowed: OperateEntry   (operate access since he can invoke delete/updatepermissions operations on the template)
Principal2: normal domain user, Access allowed: UseEntry  (the user can only list the template and use it for launching VM)

 

 

The IAM implementation will check if a given user is permitted to invoke the given 'action' / 'accesstype' on the given resource by looking at the account's groups and the associated policies of those groups.

In phase I, all the permissions attached to any policy are by default explicit 'Allow' permissions. As of now 'Deny' permissions cannot be added.

Thus For given user, resource and given api name/accessType, default permission is 'deny', then run through this:

  • Find all groups the user belongs too.
  • Find all 'effective' policies the groups are associated to. Effective includes:
    1. All policy associations in the DB for the given account Id
    2. All policy associations in the DB for the groups that the given account Id is associated to
    3. All 'recursive= true' policy associations in the DB for the parent groups of the groups the  given account Id is associated to. Parent group is found out form the 'path' property of a group.
  • If any policy has a permission attached that 'Allows' the API, grant permission to make this call
  • Else, if no Allow entry is found for any policy for this API, deny the permission
What is 'recursive = true' permission?
  • This flag indicates a permission to an entity which is accessible in a group hierarchy downwards upto the 'leaf' group. The hierarchy is defined using the 'path' property of the group.
  • This design is used to map the 'domain' hierarchy of CloudStack and facilitate access check for entities that span the domain tree like Network, AffinityGroup.
  • This property 'recursive' is not exposed in IAM APIs, but only used by CloudStack orchestration when such domain-wide resources are created in the system through normal CS APIs.

...

IAM Interface to check API Access

...

Code Block
/**
* QuerySelector returns granted domain, or account or resources for caller.
*/
public interface QuerySelector extends Adapter {

...

/**
* List granted domains for the caller, given a specific entity type.
*
* @param caller account to check against.
* @param entityType entity type
* @param accessType access type
* @return list of domain Ids granted to the caller account.
*/
List<Long> getAuthorizedDomains(Account caller, String entityType, AccessType accessType);

/**
* List granted accounts for the caller, given a specific entity type.
*
* @param caller account to check against. against.
* @param entityType entity type
* @param entityTypeaccessType entityaccess type
* @return list of domainaccount Ids granted to the caller account.
*/
List<Long> getAuthorizedAccounts(Account caller, String entityType, AccessType accessType);


/**
* List granted resources for the caller, given a specific entity type.
*
* @param caller account to check against.
* @param entityType entity type
* @param accessType access type
* @return list of domainresource Ids granted to the caller account.
*/
List<Long> getAuthorizedResources(Account caller, String entityType, AccessType accessType);

/**
 * Check if this account is associated with a policy with scope of ALL
 * @param caller account to check
 * @param action action.
 * @param accessType access type
 * @return true if this account is attached with a policy for the given action of ALL scope.
 */
boolean isGrantedAll(Account caller, String action, AccessType accessType);

/**
 * List of IAM group the given account belongs to
 * @param accountId account id.
 * @return IAM group names
 */
List<String> listIAMGroupsByAccount(long accountId); 

...

Currently CloudStack provides different response views for Root admin and non-root user, some response fields are only visible to root admin. Basically we have provided two static response views (Full view and Restricted view), domain admin will also have a User view. With new IAM service introduced, we should ideally also allow customers to be able to specify what view should be applied to the new IAM group each API when they are creating a new customized IAM group, for example, customer care groupgranting each API action to an IAM policy. To achieve that, we will implement as follows:

  1. For those APIs listed in previous Response View (Column Filter) section, when user grants them to a policy, we should allow them to pick one of two static response views (Full view and Restricted view) that are pre-defined. Note that We will have a column in IAMGroup db table to record what view to be used for this group. From IAM group creation UI, user can pick which view to be associated with this group. Note that in this release, we are not going to support full-fledged column filter (that is, allowing users to pick arbitrary columns to be see for each API) . We are and only supporting support static view association at the IAM group levelAPI level. In this release, support for granting with response view is not supported, and we still maintain the current cloudstack behavior where only root admin can see the Full view. This step will be delayed to Phase II.
  2. 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, 
    entityType = { IAMEntityType.VirtualMachine })
    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.

...

  1. Parse all API command classes to check if they are annotated with "authorized" attribute. If so, populate a permission entry for that API for the default policy mapped to that authorized roleto that authorized role.
    1. "authorized" attribute is an already existing attribute of our API's that is used to override the default access permissions defined in commands.properties file.
  2. Parse commands.property, create or override permission entries for each API for default policy mapped to API authorized roles.

...

id

name

description

uuid

path

removed

created

policy_type

1

REGULAR_USER

Domain user role

d2838dce-31f0-11e3-ad37-80f85ce25918

/

NULL

2013-10-10 14:13:34

Static

2

ADMIN

Root admin role

d2839c56-31f0-11e3-ad37-80f85ce25918

/

NULL

2013-10-10 14:13:34

Static

3

DOMAIN_ADMIN

Domain admin role

d283a7f0-31f0-11e3-ad37-80f85ce25918

/

NULL

2013-10-10 14:13:34

Static

6

RESOURCE_OWNER

Resource owner role

d283c794-31f0-11e3-ad37-80f85ce25918

/

NULL

2013-10-10 14:13:34

Dynamic

iam_group_policy_map

id

group_id

policy_id

removed

created

1

1

1

NULL

2013-10-10 14:13:34

2

2

2

NULL

2013-10-10 14:13:34

3

3

3

NULL

2013-10-10 14:13:34

...

id

policy_id

permission_id

removed

created

1

61

3

NULL

2013-10-10 14:13:34

2

2

1

NULL

2013-10-10 14:13:34

3

3

2

NULL

2013-10-10 14:13:34

...

  • Find all groups the user belongs to: groupIDs = 1
  • Find all 'Effective' policies the groups are associated to: policies = 1, 6
  • If any policy 'Allows' the startVirtualMachine API for this Vm Id, grant permission to make this call: Policy Id 6 1 and Permission Id 3 allow the API to be invoked for this user.
  • In this case, since this is a regular user and the user is the owner the VM belongs to the "ACCOUNT" scope of the VMuser, then he is granted access using policy Id 61.

A Domain Admin 'domainAdmin' calls this command for a VM in his domain:

...

  • Find all groups the user belongs to: groupIDs = 2
  • Find all 'Effective' policies the groups are associated to: policies = 2
  • Policy Id 3 2 and Permission Id 1 allow 'startVirtualMachine' access for ALL VMs .

...

For this release, creating a custom policy/group 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/group creation.

Presentation at CloudStack Collaboration Conference

ApachIAM.pptx