Using the vRNI API through PowerShell

I've been plugging away with vRNI and the NSX Distributed firewall a lot, but that hasn't generally leant itself well to writing blog posts... until recently!  We are working on an auditing process to help us decommission NSX firewall rules in favor of policies.  Typically, when retiring a firewall rule, you would just change its priority so that it's below the newer Allow rules but still above the Deny rules, then wait a while and see if it still gets any hits.  In this situation, we're looking to retire some manually created firewall rules in favor of our new set of policy-driven rules, and you can't put manual rules in the middle of your policy rules... so the typical firewall procedure won't work here!

So, we've been working on a process to use vRNI to look at all traffic that's hitting a given firewall rule, then check on the policy-based rules and ensure that it will all be allowed by those rules.  The process itself is pretty simple, and looks like this:

1) Get all of the network traffic that is hitting the rule that needs to be retired:
flows where firewall rule id = <rule to be retired>

2) For each of those flows, find a policy-based rule that matches its source/destination/port:
firewall rule where source vm = <source> and destination vm = <destination> and port = <port> and Appliedto != DISTRIBUTED_FIREWALL and action = allow
The challenge there being that little "for each" part of step 2, since each firewall rule is likely to return dozens or hundreds of flows.  Of course, we all know an easy way to deal with "for each" situations, which just means that we need a programmatic way of talking to vRNI... and fortunately, there's an API!

I've never used an API directly before though, so there's a bit of a learning curve.  There's really good documentation about how to use the API, but sometimes I need a bit of a "dummy's guide" for these things.  And, since I wasn't able to find a simple set of instructions, I figured that I'd better put that together as I figure things out!

So, using the API basically requires two parts.  First, you need to authenticate to vRNI, and then you can actually do stuff with the API.  When you authenticate to vRNI, the system will give you back an authentication token that'll be good for several hours.  You'll then need to use that token every time you want to do something with the API.  So, let's look at how that works.

First, I want to prep some variables to make my life easier (I'm using local authentication on our system here, so if you're using this snippet, make sure that you do too!):
$numResults = 10000 #the max the system supports is 10000
$vrniServer = "my VRNI Server"
$creds = get-credential

Then, I want to use that stuff to make the web request and store the results in a variable:
$auth = Invoke-WebRequest -Method Post -Uri "https://$vrniServer/api/ni/auth/token" -ContentType "application/json" -body "{
 ""username"": ""$($creds.username)"",
 ""password"": ""$($creds.GetNetworkCredential().password)"",
 ""domain"": {
 ""domain_type"": ""LOCAL""
 }
}"

Yeah, that's a lot of quotes.  When you use two sets of double-quotes in a row, that's basically telling PowerShell to ignore the special meaning of those quotes, so that you can have quotes show up inside the string of the body.  Importantly, notice that the results of that web request are getting stored in the $auth variable, which we'll now use to build out an authenticated header that we can use in future api calls:
$token = ($auth.content | ConvertFrom-Json).token
$headers = @{Authorization = "NetworkInsight $token"}

And that's authentication, congrats!  Of course, that doesn't do us much good without a query to run, so let's look at that, too.  Let's put together a request for all network flows from the past 30 days that come from a specific source IP address.  First, let's prep some more variables:
$startTime =[Math]::Floor([decimal](Get-Date((Get-Date).adddays(-30)).ToUniversalTime()-uformat "%s"))
$endTime = [Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))
$entity_type = "flow"
$sourceIP = "IP Address of Interest"

Make sure that you put something valid in that $sourceIP variable!  The rest of that should be pretty static - it's just getting the current date and the date 30 days ago (in decimal seconds) and setting up the kind of objects that we expect vRNI to give us (flow in this case).

Next, we get to use those variables to build the body of our API request!  Here's how that looks:
$body = "{
 ""entity_type"": ""$entity_type"",
 ""size"": $numResults,
 ""filter"": ""((source_ip.ip_address = '$sourceIP'))"",
 ""time_range"": {
 ""start_time"": $startTime,
 ""end_time"": $endTime
 }
}"

So, at this point, we've put together a set of headers with our authentication token and a body with our actual request.  That means that we're ready to invoke the API (I feel a bit like I'm shouting "release the Kraken!" whenever I say that):
$theseIDs = (invoke-restmethod -method Post -uri "https://$vrniServer/api/ni/search" -ContentType "application/json" -body $body -headers $headers).results.entity_id

So, there's some stuff in there besides the normal invoke-restMethod junk.  That's because vRNI's search is going to give you back a bunch of internal entity IDs, rather than usable flow results.  So, we're then going to need to go through those IDs and get each one of them so that we can actually get the data that we want:
$objDetails = foreach ($thisID in $theseIDs){
invoke-restmethod -method Get -uri "https://$vrniServer/api/ni/entities/flows/$thisID" -ContentType "application/json" -headers $headers
}

Now, $objDetails has the actual results from our query, which we can browse through by using:
$objDetails | out-gridView

And there's the basics of running a query in vRNI!  If you want to get other data from the system, you'll need to consult the documentation for details about how to change the $body request around (and especially for creating complex filters), but these are the precise steps that I had to go through to get started accessing the vRNI API.  I hope you find this useful (I expect that I will, the next time I have to do this and am wondering, "now how did I do that back at the end of 2019...")!


Comments

Popular posts from this blog

vCenter Server Appliance Crash due to Full /Storage/SEAT Partition

Deleting Orphaned (AKA Zombie) VMDK Files

PowerShell Sorting by Multiple Columns