Sorting bits into bytes...

NSX-v Security Tags in vRealize Operations

About a week ago I got a question from my customer if it was possible to get the NSX-v security tag information in vROPs. I thought this would be something that is already in vROPs natively. But to my surprise this is not the case. I know one can get data into vROPs using API calls. I haven’t done anything with API calls, so maybe this is a good excuse to check out what is possible with APIs. I would like to share the end result with you. A script that looks up the NSX-v security tags and sends them into vROPs. Even though I say it myself but… ehh… that’s pretty cool! Basically what the script does is get the security tags from NSX together with the managed object IDs. Then gets a list of all the VMs in vROPs, again with the MOIDs. Both the MOIDs are matched and the data is send into vROPs. The only flaw is that whenever the tag is removed from the VM and no new tag is applied to that VM, that results in an empty value and thus the tag information is not updated in vROPs.

A big thanks to my colleague Dennis Lefeber (https://twitter.com/vVikingNL) for helping me optimize my script! Please do check out his scripting corner; https://vviking.nl/category/scripting/

<#

Author: Kabir Ali - info@kablog.nl
Scriptname: Inject NSX-v Security Tag Data into vROPs
Version: 1.0 (Tested)
Date: April 21 2020
Why: Customer wants to have the NSX Security Tag information into vROPs (for alerting purposes)
Remark: Test setup
        vROPs Version 8.0.1.15331180
        NSX-v 6.4.6.14819921

#>

<#

The whole idea behind this script is to get the NSX-v security Tag information into vROPs. There is a 3rd party anti-virus program into play, that assigns a VM with a specific NSX-v security tag if a threat is found.
As a VM name is not unique enough (you can have the same VM name in multiple folders). I had to fall back to the managed object ID (MOID).

How it works:
1)
Convert Windows time to Linux Time.
2) 
Setup connections and connect.
3)
API call to get all the NSX-v Security Tags. Unfortunately the VMs attached to those tags are not listed.
4)
New API call with the NSX-v Security tags to get the VMs attached to them.
5)
One VM can have multiple NSX-v Security Tags. Lets group them together.
6)
API call to get all the VMs found in vROPs. The reply includes the MOID and vROPs own unique ID.
7)
Map MOIDs from NSX-v and vROPs and bundle the necessary data into an array.
8)
API call to push data into vROPs.

#>

# 1)
# In order to get the data in vROPs a Linux timestamp is needed.
function ConvertTo-UnixTimestamp {
            $epoch = Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0     
           $input | % {                   
                        $milliSeconds = [math]::truncate($_.ToUniversalTime().Subtract($epoch).TotalMilliSeconds)
                        Write-Output $milliSeconds
            }           
}

### Define Defaults ###
# 2)
#Define NSX Defaults. User needs RO permissions only
$NSXHost = "#############"
$NSXUser = "#############"
$NSXPass = "#############"

# Define vROPs Defaults. User need API permissions
$vROPsServer = "#############"
$vROPsUser = "#############"
$vROPsPass = "#############"


# Bypass SSL certificate verification
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy


### NSX API Connection ###

# Create authentication header with base64 encoding
$EncodedAuthorization = [System.Text.Encoding]::UTF8.GetBytes($NSXUser + ':' + $NSXPass)
$EncodedPassword = [System.Convert]::ToBase64String($EncodedAuthorization)

# Construct headers with authentication data + expected Accept header (xml / json)
$NSXheaders = @{"Authorization" = "Basic $EncodedPassword"}
$NSXheaders.Add("Accept", "application/json")

# Build NSX base URI
$NSXURL = "https://$NSXHost"


### vROPs API Connection ###

#Building vROPS API string & invoking REST API
$vROPsURL = "https://" + $vROPsServer + "/suite-api/api/"
$vROPsAuthURL = "https://" + $vROPsServer + "/suite-api/api/auth/token/acquire"
$Type = "application/json"
# Creating JSON for Auth Body
$AuthJSON =
"{
  ""username"": ""$vROPSUser"",
  ""password"": ""$vROPsPass""
}"
# Authenticating with API
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Try 
{
$vROPSSessionResponse = Invoke-RestMethod -Method POST -Uri $vROPsAuthURL -Body $AuthJSON -ContentType $Type
}
Catch 
{
$_.Exception.ToString()
$error[0] | Format-List -Force
}
# Extracting the session ID from the response
$vROPSSessionHeader = @{"Authorization"="vRealizeOpsToken "+$vROPSSessionResponse.'auth-token'.token
"Accept"="application/json"}


### NSX ###
# 3)
# Get all the NSX-v Security Tags. Once we have them we can search for the attached VMs to them
$NSXSecTagReply =  Invoke-RestMethod -Uri ($NSXURL+'/api/2.0/services/securitytags/tag') -Method GET -Headers $NSXheaders -ContentType $Type
# Creat array for easy filtering. ObjectID is required to later on build the vROPs API Uri. Name will be used as data 4 vROPs. VMCount will be used to filter out empty NSX-v Security Tags
[array]$NSXSecTagReplyArray = @()
    foreach($NSXSecTag in $NSXSecTagReply.securityTagDtoList){
        $NSXSecTag = New-Object PSObject -Property @{
        ObjectID = $NSXSecTag.objectID
        Name = $NSXSecTag.name
        VMCount = $NSXSecTag.vmCount
        }
    $NSXSecTagReplyArray += $NSXSecTag
    }

# Continue only with the non empty NSX-v Security Tags
$ClearOutEmptyNSXSecTag = $NSXSecTagReplyArray | where {$_.vmcount -gt 0}
# 4)
# Now with the non empty NSX-v Security Tags knows, grab all the VMs that have a security tag
[array]$NSXObjectID = @()
    foreach($NSXArrayObjectID in $ClearOutEmptyNSXSecTag.ObjectID){
        # Not really needed for the API call, but handy to be able to map human readable VM name to MOIDs
        $NSXTagName = $ClearOutEmptyNSXSecTag | where {$_.ObjectID -eq "$NSXArrayObjectID"}
        # Grab all the VM data matching the NSX Security Tag Object ID
        $getVMdata = Invoke-RestMethod -Uri ($NSXURL+'/api/2.0/services/securitytags/tag/'+$NSXArrayObjectID+'/vm') -Method GET -Headers $NSXheaders -ContentType $Type
        # Loop through the data and create an array for easy filtering. NSXVMName is the VM name as seen in vCenter. NSXObjectID is the MOID (very important). NSXSecTagName is the NSX-v Security Tag Name 
        foreach($vmdata in $getVMdata.basicDomainObjects){
                $NSXObjectIDRow = New-Object PSObject -Property @{
                NSXVMName =  $vmdata.name
                NSXObjectID =  $vmdata.objectId
                NSXSecTagName = $NSXTagName.name
                }
        $NSXObjectID += $NSXObjectIDRow
        }
    }
# 5)
# One VM can have multiple Security Tags. This next array collects all the security tags on a per VM bases
[array]$NSXMOIDs = @()
$line = @()
$NSXMOID = $NSXObjectID
# Loop through the data. $NSXObjectIDs are now NSXMOIDs (just renamed the variable). NSXSecTagNames will be the value which is used in the JSON 4 vROPs. NSXVMNames not really needed, its just the human readable VM name.
foreach($line in $NSXMOID.NSXObjectID){
    $line = New-Object PSObject -Property @{
    NSXMOIDs = $line
    NSXSecTagNames = ($NSXMOID | where {$_.NSXObjectID -eq "$line"}).NSXSecTagName -join "," #the join is used to join the NSX-v Security Tag names together.
    NSXVMNames = ($NSXMOID | where {$_.NSXObjectID -eq "$line"}).NSXVMName
    }
    $NSXMOIDs += $line
}


### vROPs ###
# 6)
# API call to collect all VM data found in vROPs.
$vROPsallVMresources = Invoke-RestMethod -Method GET -Uri ($vROPsURL+"adapterkinds/VMWARE/resourcekinds/virtualMachine/resources") -Headers $vROPSSessionHeader -ContentType $Type
# In order to get the MOID from vROPs a new API call is needed. The MOID is stored with the VM as a metric. Lets grab all the data of a VM for this the VM identifier is needed.
$VMidentifiers = $vROPsallVMresources.resourceList.identifier
[array]$vROPsMOIDs = @()
    # Loop through the data. Name just the human readable VM name. MOID is the MOID found in vROPs. vROPsID what is needed later to push data to vROPs.
    foreach($VMidentifier in $VMidentifiers) { 
        $oneresource = Invoke-RestMethod -Method GET -Uri ($vROPsURL+"resources/$VMidentifier/properties") -Headers $vROPSSessionHeader -ContentType $Type
        $vROPsMOIDArray = New-Object PSObject -Property @{
        Name = ($oneresource.property | where {$_.name -contains "config|name"}).value
        MOID = ($oneresource.property | where {$_.name -contains "summary|MOID"}).value
        vROPsID = ($oneresource).resourceId
        }
        $vROPsMOIDs += $vROPsMOIDArray
    }

### Generic ###
# 7)
# Merge the NSXMOID and vROPsMOID Array together with the MOID as the matching value.
[array]$combined = @()
$combined = foreach($obj in $vROPsMOIDs) {
    # Lookup MOID in NSXMOID for current MOID in vROPsMOIDs
    $other = $NSXMOIDs | Where{$_.NSXMOIDs -eq $obj.MOID}
    # Extra loop for the other data
    foreach ($subObj in @($other)) {
        # Create Array that will have all the data needed to push to vROPs
        $obj | 
        Select Name, vROPsID, MOID, @{Name='NSXSecTag';Expression={$subObj.NSXSecTagNames}}
    }              
}

# 8)
# Loop through the data and populate the required variables.
foreach ($vROPsData in ($combined | Sort-Object MOID -Unique)) {
# With all that is required collected, its time to push the data 2 vROPs
$TheTimeIsNow = (Get-Date | ConvertTo-UnixTimestamp)
    # Data is injected into vROPs using a JSON body. The NSX Security Tags are added as a custom property to the VMs.
    $jsondata='{
               "property-content": [ {
                "statKey": "CustomProperties|NSX Security Tag",
                "timestamps": [ ' +$TheTimeIsNow+ ' ],
                "values": [" ' +$vROPsData.NSXSecTag+ ' "],
                "others": [],
                "othersAttributes": {}
                } ]
                }'

    Try 
        {
        $TagJSONResponse = Invoke-RestMethod -Method POST -Body $jsondata -Uri ($vROPsURL+'resources/'+$vROPsData.vROPsID+'/properties') -TimeoutSec 100 -Headers $vROPSSessionHeader -ContentType $Type
        $TagDetailedInfo = $TagJSONResponse.value
        }
        Catch 
        {
        $_.Exception.ToString()
        $error[0] | Format-List -Force
        }
    sleep 0.2 # fix some timeout issues
}

 

 

NSXvSecTag2vROPs

If you lookup the VM in vROPs you will find the NSX-v security tag information under All Properties -> CustomProperties:

 

 

Happy API calling!

Leave a Reply