Extending vRealize Automation Permission Model

Problem statement

vRealize Automation already has quite a flexible permission model:

source: vmware.com

This model is an ideal fit for a company in which an internal IT-department is managing the complete IT of a company. The growing demand for customer self-service requires every IT department or even more the service providers to continuously push the limits. We want to provide a virtual private cloud with maximal capabilities to our customers – but on shared infrastructure at minimal costs. That’s why we need to extend the permission model with at least an additional layer of permissions:

source: vmware.com (modified)

This new middle layer would enable the customer to do the administration within his tenant as if he had a private and dedicated installation. Without this layer a  lot of the built-in roles are too powerful and not suited for customers given they are not limited to the scope of a tenant.  Look at the recommendations for service providers from the VMware vCloud Air team:

source: vmware.com

Pushing the limits

I had to explore the possibilities to extend the permission model at least to manage Access to our own custom functionality. At a first glance some API calls in the package /identity drew my attention. It looked like it is possible to create custom roles and permissions:

PUT /api/authorization/permissions/{id}
PUT /api/authorization/roles/{roleId}/permissions/assigned/{permissionId}

I was a little bit disappointed that some calls are documented but not implemented – That said, I did not manage to create valid requests for some of them. If you have some hints for me, please leave a comment.

In the next step I checked out the database and found some tables that could do the trick:

INSERT INTO "role" ("type", "id", "description", "name", "status") VALUES ('tenant', 'SCS_TENANT_ADMINISTRATOR_NSX_ACCESS', 'NSX Firewall Administrator', 'Permission to manage firewall rules', null);
INSERT INTO "permission" ("id", "description", "name", "status") VALUES ('SCS_GUI_NSX_ACCESS', 'Permission for GUI access to firewall admin tab in portal', 'Permission for GUI access to firewall admin tab in portal', null);
INSERT INTO "permission" ("id", "description", "name", "status") VALUES ('SCS_API_NSX_ACCESS', 'Permission for API access to NSX security proxy', 'Permission for API access to NSX security proxy', null);
INSERT INTO "role_assignedpermission" ("role_id", "permission_id") VALUES ('SCS_TENANT_ADMINISTRATOR_NSX_ACCESS', 'SCS_API_NSX_ACCESS');
INSERT INTO "role_assignedpermission" ("role_id", "permission_id") VALUES ('SCS_TENANT_ADMINISTRATOR_NSX_ACCESS', 'SCS_GUI_NSX_ACCESS');

INSERT INTO "role" ("type", "id", "description", "name", "status") VALUES ('system', 'SCS_SUPER_FUCTIONS_ADMINISTRATOR', 'Execute Super Functions', 'Permission to execute Super Functions', null);
INSERT INTO "permission" ("id", "description", "name", "status") VALUES ('SCS_SUPER_FUNCTION_EXECUTE', 'Permission to execute super functions for ESC', 'Permission to execute super functions for ESC', null);
INSERT INTO "role_assignedpermission" ("role_id", "permission_id") VALUES ('SCS_SUPER_FUCTIONS_ADMINISTRATOR', 'SCS_SUPER_FUNCTION_EXECUTE');

Wait, what have I done?

Manipulating the database directly is not recommended in a productive environment. I did this in a dedicated lab environment for research purpose only!

(And it is not needed at all if you take the vCACCAFE scripting classes in a vRO workflow, see below).

The first insert is a new role record. It is of the type “tenant” and the new role has the ID ‚SCS_TENANT_ADMINISTRATOR_NSX_ACCESS‘. The second record is a new permission, ‘SCS_GUI_NSX_ACCESS’, the third is the same permission for API access. The fourth and fifth inserted records are entries in the link table that associate roles and permissions (many-to-many relation). Please note: The out of the box vRA or vRO functionality won’t be able to react on these custom roles and permissions, because these values have to be considered either explicitly in the program or by declaration (i.e., spring configuration). As a result, we can only use these custom roles and permissions for our own workflows or code and they are not visible or assignable within the vRA portal UI.

Hint: I tested all the possible scopes (types), system, tenant and subtenant. „subtenant“ is not usable at all because saving the permission in a business group is validating the roles and does not accept custom roles without errors. I got an „invalid argument“ message on the frontend and after checking the return values of the REST call if found: „HTTP 400, „Subtenant roles allowed are MANAGER, SUPPORT, CONSUMER_WITH_SHARED_ACCESS and CONSUMER“.
The tenant roles are properly displayed as any other tenant role and fully functional in the frontend, the system roles are completely hidden.

After inserting these records I could finally use my custom roles and permissions:

PUT /identity/api/authorization/tenants/{tenantId}/principals/{principalId}/roles/{roleId}

With this API call a role can be granted to a user (principal). The needed parameter can be retrieved by the following request:

GET /identity/api/authorization/roles/

Now you need to get the principals assigned to this business groups:

GET /identity/api/tenants/<tenantId>/principals

Checking permission by API

As  I already stated, we need to explicitly query these new roles and permissions if we want to use them in the system. This can be achieved with the following two calls:

Get the current user:

GET /component-registry/api/wizardstates/current/
{
    "id": "2f5a98bd-e7cd-47e6-a701-3a64f760b63c",
    "userId": "daniele@vsphere.local",
    "tenantId": "orc2",
    "goalId": null
}

With the userId you will be able to query all the roles of this user:

GET /identity/api/authorization/tenants/<tenantId>/principals/<userId>/roles/

{
    "links": [],
    "content": [
        {
            "@type": "ScopeRole",
            "id": "CSP_CONSUMER",
            "name": "Basic User",
            "description": "CSP Basic User",
            "assignedPermissions": [
                {
                    "id": "GUI_ITEMS",
                    "name": "Items User Interface",
                    "description": "Access the provisioned items GUI.",
                    "prereqAdminPermissions": null
                },
                {
                    "id": "CATALOG_CONSUME_SELF",
                    "name": "Catalog Consume Requests and Resources requested by self",
                    "description": "Consume services and resources for one's self and manage one's own requests",
                    "prereqAdminPermissions": null
                },
                {
                    "id": "GUI_REQUESTS",
                    "name": "Requests User Interface",
                    "description": "Access the requests GUI.",
                    "prereqAdminPermissions": null
                },
                {
                    "id": "GUI_CATALOG",
                    "name": "Catalog User Interface",
                    "description": "Access the catalog GUI.",
                    "prereqAdminPermissions": null
                }
            ],
            "scopeType": {
                "id": "CSP_SUBTENANT",
                "name": "CSP Business Group",
                "description": "CSP Business Group scope type",
                "prereqAdminPermissions": null
            }
        },
        {
            "@type": "ScopeRole",
            "id": "SCS_TENANT_ADMINISTRATOR_NSX_ACCESS",
            "name": "Tenant NSX Administrator",
            "description": "Tenant NSX Administrator",
            "assignedPermissions": [
                {
                    "id": "SCS_API_NSX_ACCESS",
                    "name": "SCS NSX API Access",
                    "description": "SCS NSX API Access",
                    "prereqAdminPermissions": null
                },
                {
                    "id": "SCS_GUI_NSX_ACCESS",
                    "name": "SCS NSX GUI Access",
                    "description": "SCS NSX GUI Access",
                    "prereqAdminPermissions": null
                }
            ]
        }
    ],
    "metadata": {
        "size": 20,
        "totalElements": 2,
        "totalPages": 1,
        "number": 1,
        "offset": 0
    }
}

Checking permissions in vRO workflows

I thought it should be possible to get the permissions directly from the execution context but I haven’t found a suitable method. I ended  up with the following solution for a role with scope subtenant (I leave it up to you to figure out how to query for roles of the other scopes):

var principals = scopeService.getPrincipals(tenant,bgId,"SCS_ADMINISTRATOR_NSX_ACCESS",null,null);
for each (var p in principals.getContent()) {
    System.debug(p);
	if (p.getName()+"@"+p.getDomain() == user) {
		System.log("found!");
	}
}

Here you  can download the full script: queryPermission.

Creating roles and permissions in vRO workflows

After having solved the main Problem, I checked what additional features the vCACCAFE scripting framework in vRO has to offer. Obviously, I would like to prefer not inserting records manually in the database! So I was very surprised to find the necessary functions:

roleService.createOrUpdateRole(newRole);
roleService.addPermission(newRole.getId(),newPermission.getId());

I repeat my warning: do not add subtenant roles (ScopeRoles), the scripting classes are allowing to perform this but the vRA runtime does not accept it. System and tenant scoped roles, however, could be successfully tested on my lab installation.

Check out the full script: createAndAssignRoleAndPermission.

I would be very grateful for reviews of my coding; I assume that there must be some easier way to do the task.

Stay tuned, I will share my learnings with you. See you at VMworld Barcelona and discuss „How to Win over App Developers and End Shadow IT“ with us!