I have been using vRealize Operations to monitor the compliance of virtual machines against the DISA VMware vSphere Virtual Machine STIG for quite some time now. With the release of the new VMware vSphere 6.5 Virtual Machine STIG, I have discovered that vRealize Operations does not collect all the necessary information out of the box to verify compliance with the new STIG rules. Rather than waiting for VMware to provide an update to vRealize Operations, I decided to utilize vRealize Orchestrator to add custom properties to the virtual machines in vRealize Operations using the vRealize Operations REST API.
If you would like to skip right to implementing the code, you can download the vRealize Orchestrator package using the link at the bottom of this post. Otherwise, let us dig into how we accomplish this.
Before we begin looking at the code, let us review at a high level the process implemented in vRealize Orchestrator.
Before making any REST API calls to vRealize Operations, we first need to create a new REST host using the built-in “Add a REST host” workflow. Use the following values when running the workflow:
Name: <vROPS FQDN>
URL: https://<vROPS FQDN>/suite-api/
Connection timeout (seconds): 30
Operation timeout (seconds) 60
Host authentication type: NONE
When the workflow completes, verify that the HTTP REST host was created by reviewing the vRealize Orchestrator inventory.
The preferred method for working with the vRealize Operations REST API is to utilize a bearer token for authentication purposes. We obtain the token by sending an HTTP POST request containing a username and password to:
https://
Per the REST API documentation (found at https://
{
"username" : "<username>",
"authSource" : "<authentication source>",
"password" : "<password>",
"others" : \[ \],
"otherAttributes" : { }
}
The “authSource” will likely be “LOCAL” if using a local user account, otherwise, it will match the name of your vIDM/SSO, or Active Directory authentication source. If successful, vRealize Operations replies with a token and its associated expiration time. An example response would look like:
{
"username" : "<username>",
"authSource" : "<authentication source>",
"password" : "<password>",
"others" : \[ \],
"otherAttributes" : { }
}
We accomplish this in vRealize Orchestrator with the below code:
Inputs: restAuthPasswod, restAuthUsername, restAuthDataSource, restHost
//Define the JSON request body
var jsonBody = {
"username": "",
"authSource": "",
"password": "",
"others": \[\],
"otherAttributes": {}
};
//Fill in the values into the jsonBody
jsonBody.username = restAuthUsername;
jsonBody.password = restAuthPassword;
jsonBody.authSource = restAuthDataSource;
jsonRequestBody = JSON.stringify(jsonBody);
//Create a new HTTP REST Request object for the REST host that was provided
var request = restHost.createRequest("POST", "/suite-api/api/auth/token/acquire", jsonRequestBody);
request.contentType = "application/json";
request.setHeader("accept", "application/json");
//Attempt to execute the REST request
try {
response = request.execute();
jsonObject = JSON.parse(response.contentAsString);
var authData = new Properties();
//Return back the authentication token and validity period using a property set
if (jsonObject.token != "" && jsonObject.validity != "") {
authData.put("authToken", jsonObject.token);
authData.put("authTokenValidity", jsonObject.validity);
return authData;
}
else {
throw "There was an errror executing the REST call.";
}
}
catch (e) {
throw "There was an error executing the REST call:" + e;
}
Next up, we need to obtain a list of all of the managed VirtualMachine objects in the vRealize Operations inventory. To accomplish this, make a single GET request to the REST API using the following URL:
https://
We accomplish this in vRealize Orchestrator with the following code:
Inputs: restAuthData, restHost, resourceKind
//Request all objects from vROPs with a specified resourceKind
var request = restHost.createRequest("GET", "/suite-api/api/resources?resourceKind=" + resourceKind + ";pageSize=" + pageSize, null);
request.contentType = "application/json";
request.setHeader("accept", "application/json");
request.setHeader("Authorization", "vRealizeOpsToken " + restAuthData.get("authToken"));
try {
var restResponse = request.execute();
jsonResponse = JSON.parse(restResponse.contentAsString);
return jsonResponse;
}
catch (e) {
throw("Error executing the REST operation: " + e);
}
For us to query properties from the VC:VirtualMachine objects in vRealize Orchestrator, we need to match the vRealize Operations VirtualMachines to vRealize Orchestrator VC:VirtualMachines. To accomplish this, we will use the VMEntityVCID which tells us exactly what vCenter server to use, and VMEntityInstanceUUID which provides us a unique identifier for the VM within the vCenter server. This allows us to determine which vCenter server to search and then provides the VM’s instance UUID which is guaranteed to be unique within a vCenter server. To find the matching VC:VirtualMachines, we use the VcPlugin’s SdkConnection method findByUuid. Then we query the values that we wish to store in vRealize Operations and send those properties to vRealize Operations using REST requests. In this case, we are querying two properties from the VC:VirtualMachine: “guestAutoLockEnabled” and “migrateEncryption.” The following code records the current time value so that all properties added during this execution of the code will have the same time value. It then generates an array of Properties that will be sent to the custom action “addProperties” which executes the REST calls to vRealize Operations.
Inputs: jsonResponse
var vropsResources = jsonResponse.resourceList;
var currentEpochTime = Date.now();
var updateCount = 0;
//For each vROPs VirtualMachine, find the matching vCenter VM
for each(resource in vropsResources) {
try{
var resourceIdentifiers = resource.resourceKey.resourceIdentifiers;
var VMEntityInstanceUUID = null;
var VMEntityVCID = null;
var vm = null;
//Get the VMEntityInstanceUUID for the vRealize Ops VirtualMachine object
for each(resourceIdentifier in resourceIdentifiers) {
if(resourceIdentifier.identifierType.name== "VMEntityInstanceUUID") {
VMEntityInstanceUUID = resourceIdentifier.value;
}
if(resourceIdentifier.identifierType.name== "VMEntityVCID") {
VMEntityVCID = resourceIdentifier.value;
}
}
//Find the vCenter VM object by using the VMEntityInstanceUUID and VMEntityVCID returned by vROPs
var sdkConnection = VcPlugin.findSdkConnectionForUUID(VMEntityVCID);
if (!sdkConnection) {
throw "No vCenter found with UUID " + VMEntityVCID;
}
try {
vm = sdkConnection.searchIndex.findByUuid(null, VMEntityInstanceUUID, true, true);
}
catch(e) {
System.log("Unabled to find VM with instance UUID " + VMEntityInstanceUUID);
}
//Found matching VM
if(vm != null && VMEntityVCID != null && VMEntityInstanceUUID != null) {
//Variable to hold the JSON Update Body
var jsonBody = new Object();
var jsonProperties = new Array();
try {
if(vm.config.guestAutoLockEnabled != null)
jsonProperties.push(generateProp("config|security|guestAutoLockEnabled",currentEpochTime,vm.config.guestAutoLockEnabled));
} catch(e) {}
try {
if(vm.config.migrateEncryption != null)
jsonProperties.push(generateProp("config|security|migrateEncryption",currentEpochTime,vm.config.migrateEncryption));
} catch(e) {}
//Send properties to vRealize Ops
var responseCode = System.getModule("com.stevenbright.vrops.resources").addProperties(restHost, restAuthData.get("authToken"), resource.identifier, jsonProperties);
System.log("Submitted request to add " + jsonProperties.length + " properties to VM '" + vm.name + "'. Received the following HTTP response code: " +responseCode);
updateCount = updateCount + 1;
}
else {
System.log("vROPs VM " + resource.name + " not found matched with vCenter VM.");
}
}
catch(e) {}
}
System.log("Updated " + updateCount + " VMs with new properties.");
function generateProp(statKey, timestamps, values) {
if(statKey!=null && timestamps!=null && values!=null) {
var newProp = new Properties;
newProp.put("statKey", statKey);
newProp.put("timestamps", timestamps);
newProp.put("values", values);
return newProp;
} else {
return null;
}
}
The action "addProperties" that we use to send the properties to vRealize Operations using REST calls is:
//Variable to hold the JSON Update Body
var jsonBody = {
"property-content" : \[ \]
}
//Create and add stat-content entries
for each(newProperty in newProperties) {
var jsonProperty = {
"statKey" : "",
"timestamps" : \[ \],
"values" : \[ \],
"others" : \[ \],
"otherAttributes" : { }
}
try{
jsonProperty.statKey = newProperty.get("statKey");
jsonProperty.timestamps.push(newProperty.get("timestamps"));
jsonProperty.values.push(newProperty.get("values"));
jsonBody\["property-content"\].push(jsonProperty);
} catch(e){}
}
//Prepare to execute the REST request
var request = restHost.createRequest("POST", "/suite-api/api/resources/" + resourceId + "/properties", JSON.stringify(jsonBody));
request.contentType = "application/json";
request.setHeader("accept", "application/json");
request.setHeader("Authorization", "vRealizeOpsToken " + restAuthToken);
//Execute the HTTP REST request
try {
response = request.execute();
return response.statusCode;
}
catch (e) {
System.error("Error executing the REST operation: " + e);
}
When executed together, the code will add two new properties to our virtual machines in vRealize Operations. The new properties can then be used to create new Alert Symptoms to address the four missing VMware vSphere 6.5 Virtual Machine STIG checks as shown below.
Search
Get Notified of Future Posts
Recent Posts