Contents

VMware NSX v2t DFW Migration Script - Create IPsets in NSX-v

A quick PowerShell script to add IPsets to NSX-v DFW (Distributed Firewall) Rules and Security Groups.

Reason

I recently had a request from a client on a recent engagement, who was migrating from NSX-v to NSX-T. After running the VMware NSX-T Data Center Migration Coordinator assessment, the in-pace upgrade was not for them, due to their existing topology, resulting in us looking into the “Lift and Shift” methodology. The customer has over 1000 DFW (Distributed Firewall) Rules in each region, re-creating them manually would be painful! Luckily, VMware has got you covered, DFW-Only Migration! The VMware NSX-T Data Center Migration Coordinator can migrate the DFW rules to the NSX-T environment, however, the migrated security groups and rules would be using IPsets, since you can only have a Virtual Machine (VM) in the environment for it to be present within a DFW object.

What is the need for this script then? Well, the Migration Coordinator creates the IPset in the NSX-T environment, so when the VM workloads have been migrated they will be protected by the migrated rules. In most cases, this is acceptable since customers migrate their workload in a single change window with expected downtime. What if the customer has mission-critical live workloads and requires to spread the migration over several change windows, days even? This could cause some issues. Let’s take the following example.

Scenario Example 1

A DFW Rule has allowed traffic, where the source VM1 (Windows Jumpbox), can communicate with the destination VM2 (Web Server) on ports 80/tcp and 443/tcp. There is a default DFW rule, which denies all incoming and outgoing traffic. So it is imperative, that all allowed traffic is captured above this rule. If at any point a VM is either deleted, migrated or no longer present within the inventory, it would drop out of the DFW rule. The business has decided that VM1 and VM2 cannot be migrated within the same change window due to commercial reasons, however, this carries some risk, as the example allowed traffic would be denied once workloads migrated between the two change windows.

Workaround

Similar to VMware’s methodology, the PowerShell script provided below would add IPsets to all existing DFW rules and security groups in NSX-v, therefore traffic will always be protected using IPs rather than VM objects.

Script

The script is available to download from my GitHub Repo, here.

A couple of prerequisites, you would need both PowerCli and PowerNSX modules, which will interface with your vSphere and NSX environment. There is a big caveat, the script relies on guest VM tools running on the VM. It requires the vCenter for the reported IPs for that particular VM.

Disclaimer
Ensure to test the script before running in production if you choose to do so.

The script will be split into five sections.

The first part of the script allows you to input the hostname and credentials for both vCenter and NSX-v. These could be parsed in as parameters when running the script, you have a choice of excluding the password to avoid them being visible in plain text, which then would prompt for a secure string.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
param($VcIP, $VcUser, $VcPass, $NSXvIP, $NSXvUser, $NSXvPass)

Import-Module -Name powernsx

if (-not $VcPass) {
    $VcPass = Read-Host 'VC Password' -AsSecureString
    $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($VcPass)
    $VcPassValue = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
    Connect-VIServer $VcIP -User $VcUser -Password $VcPassValue
    Connect-NsxServer -vCenterServer $VcIP -ValidateCertificate:$false -Username $VcUser -Password $VcPassValue
} else {
    Connect-VIServer $VcIP -User $VcUser -Password $VcPass
    Connect-NsxServer -vCenterServer $VcIP -ValidateCertificate:$false -Username $VcUser -Password $VcPass
    
}

Here, in the second part of the script, we are storing a few variables with rules, security groups, ipsets and VMs, also declaring empty arrays which soon will be populated.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$firewallRules = Get-NsxFirewallRule
$ruleMemberArray = @()

$securityGroups = Get-NsxSecurityGroup
$secuityGroupsArray = @()

$ipSets = Get-NsxIpSet

$VMs = Get-VM

$vmNoIpFoundArray = @()

Now getting into the interesting part, the third part of the script. We are iterating through each firewall rule, first the source, and then the destination. If a VM object is identified in the rule, a lookup will be done against vCenter, and the IPs reported by vmtools will be stored within an object, then added to an array, ruleMemberArray. If an IP is not reported for the VM, then the VM name will be stored in another array, vmNoIpFoundObject.

The ruleMemberArray array is later called in line 48, where it is then used to apply the newly updated DFW rules containing both the VM objects and IPsets.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
foreach ($rule in $firewallRules) {
    foreach ($destination in ($rule.destinations.destination | where type -eq "VirtualMachine")) {
        $vm = Get-VM -Name $destination.name
        if ($vm.Guest.IPAddress.where{($_ -match ".")}.count -eq 0){
            $vmNoIpFoundObject = [PSCustomObject]@{
                vm_name = $vm.name
                vm_state = $vm.PowerState
            }
            $vmNoIpFoundArray += $vmNoIpFoundObject
        }
        foreach ($ip in $vm.guest.IPAddress) {
            if ($ip.contains(".") -AND -not ($rule.destinations.destination.value).contains($ip)) {
                $ruleMemberObject = [PSCustomObject]@{
                    rule_name = $rule.name
                    rule_id = $rule.id
                    direction = "destination"
                    vm_name = $vm.name
                    member = $ip
                }
                $ruleMemberArray += $ruleMemberObject
            }
        }     
    }
    foreach ($source in $rule.sources.source | where type -eq "VirtualMachine") {
        $vm = Get-VM -Name $source.name
        if ($vm.Guest.IPAddress.where{($_ -match ".")}.count -eq 0){
            $vmNoIpFoundObject = [PSCustomObject]@{
                vm_name = $vm.name
                vm_state = $vm.PowerState
            }
            $vmNoIpFoundArray += $vmNoIpFoundObject
        }        
        foreach ($ip in $vm.guest.IPAddress) {
            if ($ip.contains(".") -AND -not ($rule.sources.source.value).contains($ip)) {
                $ruleMemberObject = [PSCustomObject]@{
                    rule_name = $rule.name
                    rule_id = $rule.id
                    direction = "source"
                    vm_name = $vm.name
                    member = $ip
                }
                $ruleMemberArray += $ruleMemberObject
            }
        }     
    }    
}

foreach ($ruleMember in $ruleMemberArray) {
    try {
        Get-NsxFirewallRule -RuleId $ruleMember.rule_id  | Add-NsxFirewallRuleMember -MemberType $ruleMember.direction -Member $ruleMember.member | Out-Null
        Write-Host -ForegroundColor Green 'SUCCESS: Added '$ruleMember.vm_name ' - ' $ruleMember.member ' to rule ' $ruleMember.rule_id ' - ' $ruleMember.rule_name ' - ' $ruleMember.direction
    } catch {
        Write-Host -ForegroundColor Red 'ERROR: Failed to add ' $ruleMember.vm_name ' - ' $ruleMember.member ' to rule ' $ruleMember.rule_id ' - ' $ruleMember.rule_name ' - ' $ruleMember.direction
        Write-Output ("FAILED")
        $ruleMember.name
        $ruleMember.rule_id
        $ruleMember.direction
        $ruleMember.member
        Write-Output ("")
    }
}

The above identifies VM objects within DFW rules, not capturing VMs within security groups. The fourth part of the script iterates through every security object and captures the effective IP addresses, a lovely feature that we can take advantage of. Using the captured output, an IPset is then created and then added to the same Security Group, therefore spans across all DFW rules, where they are being used.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
foreach ($securityGroup in $securityGroups){
    $effectiveIpAddresses = Get-NsxSecurityGroupEffectiveIpAddress -SecurityGroup $securityGroup
    
    $ipv4name = "ipsv4-" + $securityGroup.name

    if($ipSets.where{($_.name -eq $ipv4name)}.count -eq 0) {
        $ipSetv4 = New-NsxIpSet -name $ipv4name
    } else {
        $ipSetv4 = Get-NsxIpSet -name $ipv4name
    }

    foreach ($ip in $EffectiveipAddresses.IpAddress) {
        if ($ip -match "/" -OR $ip -match "-") {
            #Skip IPSet Ipaddresses
            continue
        }
        $checkifip = [IPAddress] $ip
        if ($checkifip.AddressFamily.ToString() -eq "InterNetwork") {
            Get-NsxIpSet -objectId $ipSetv4.objectId | Add-NsxIpSetMember -IPAddress ($ip.ToString() + "/32")
        }
    }

    Get-NsxSecurityGroup -objectId $securityGroup.objectID |  Add-NsxSecurityGroupMember -Member $ipSetv4
}

Finally, earlier we captured the VMs which did not report any IP addresses. Here, we are simply informing the end user at the end of the script which VMs require looking into.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
foreach ($vm in $VMs) {
    if ($vm.Guest.IPAddress.where{($_ -match ".")}.count -eq 0){
        $vmNoIpFoundObject = [PSCustomObject]@{
            vm_name = $vm.name
            vm_state = $vm.PowerState
        }
        $vmNoIpFoundArray += $vmNoIpFoundObject
    }
}

if ($vmNoIpFoundArray.count -gt 0) {
    Write-Output ("")
    Write-Host -ForegroundColor Red "ERROR: No IPs can be found for the following VMs:"
    $vmNoIpFoundArray | Format-Table
}

Summary

In this article, we have discussed a scenario where this script may be required, the script to some level of detail.

There are other scripts that I have created for the VMWare NSX v2t DFW Migration, this may be a start to another blog series.

Harry Roshan Thambi
VMware Senior Consultant
@ Xtravirt Ltd
Interested virtualisation, cloud and anything that can be automated.