ESXi Custom Firewall Rule – Automation using Powercli and PLINK

Introduction

It’s been a long time using Nagios to monitor our vSphere infrastructure and found the new plug-in we’ve upgraded requires a custom firewall rule to be opened on ESXi servers to monitor NTP status. By default, when NTP is enabled, outgoing port 123 in UDP is opened but Nagios required incoming port 123 in UDP to connect to ESXi and check for the NTP status.

As there are hundreds of ESXi servers to configure, decided to write a script to automate the process.

There is an excellent blog by William Lam that goes through how to create a custom firewall rule and it can be found here. Please make sure you read this blog before going through this post.

Pre-requisites

  1. SSH is enabled across all ESXi servers
  2. VMFS volumes are shared across ESXi servers in a cluster
  3. Download plink.exe , it can be found here
  4. Create a custom firewall XML file, follow William’s post
  5. Create an input .csv file, detail will be explained below
  6. Locate above files in the same directory as the script

ntpd.xml

The following is the XML file I used for creating a custom firewall rule. The bold and underline, “ntpd” is the name of the custom rule which will be shown under Security Profile. Change the name that fits your naming convention.

<ConfigRoot>
  <service>
    <id>ntpd</id>
    <rule id='0000'>
      <direction>inbound</direction>
      <protocol>udp</protocol>
      <porttype>dst</porttype>
      <port>123</port>
    </rule>
    <enabled>true</enabled>
    <required>false</required>
  </service>
</ConfigRoot>

Input

PLINK is required to copy the .xml file to /etc/vmware/firewall folder. To do this, it is a must to provide root password. In our case, each cluster has different root password so I’ve decided to create an input file like the following:

cluster,password
cluster_1,123456
cluster_2,123457
cluster_3,123458
...
...

Script

The following is the script I wrote. It’s a simple script that does:

  • Import the password.csv file
  • For each cluster:
    • Find the datastore that has the largest freespace
    • Copy the .xml file to the datastore found above
    • For each ESXi server:
      • Check if the inbound port 123 is already opened
      • If it’s opened, skip this ESXi server
      • If not, copy the .xml file from the datastore above to /etc/vmware/firewall directory via PLINK
      • Refresh the firewall rule using esxcli network firewall refresh
      • Present the result
$input = Import-Csv C:\script\input\password.csv

foreach ($cluster in (Get-Cluster | sort Name)) {
  $datacenter = Get-Datacenter -Cluster $cluster | %{$_.Name}
  $datastore = (Get-VMHost -Location $cluster | Get-Datastore | Sort-Object FreespaceGB -Descending)[0]
  Write-Host "Copying ntpd.xml file to $datastore"
  Write-Host ""
  Copy-DatastoreItem "ntpd.xml" -Destination "vmstore:\$datacenter\$datastore" 

  foreach ($esxi in (Get-VMHost -Location $cluster | Sort Name)) { 
    $esxcli = Get-Esxcli -VMHost $esxi
    $ntp_rule = $esxcli.network.firewall.ruleset.rule.list() | where {$_.PortBegin -eq 123 -and $_.PortEnd -eq 123 -and $_.Direction -eq "Inbound"}
    if ($ntp_rule) { 
      Write-Warning "$esxi already has inbound NTP Daemon running"
      Write-Host ""
    } else {
      $password = $input | where {$_.cluster -match $cluster.Name} | %{$_.password}
      echo y | .\plink.exe -pw $password "root@$esxi" "cp /vmfs/volumes/$datastore/ntpd.xml /etc/vmware/firewall;"

      Write-Host "Refreshing Firewall Rule"
      $esxcli.network.firewall.refresh()
      Write-Host ""

      Write-Host "The modification is made, printed below"
      $esxcli.network.firewall.ruleset.rule.list() | where {$_.PortBegin -eq 123 -and $_.PortEnd -eq 123}
    }   
  }
}

Wrap-Up

One of the constraints I can think of is enabling SSH on ESXi servers as it’s not recommended by VMware. I was thinking of automating the process without using SSH but couldn’t find any other ways of doing it. Please ping me if any one of you finds a way.

Assuming SSH is disabled and trying to get an approval to open the port using the script above, I would suggest you to:

  1. Work on one cluster at a time
  2. Enable SSH just after the foreach ESXi loop and disable at the end of the loop

In this way, SSH will only be enabled for one ESXi server at a time.

Hope this helps.

 

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s