In this blog I will explain how to create Firewall Rules in NSX with PowerCLI (Policy API).
In my previous blogs I explained how to Tag VMs and create Groups. Now I use this Groups to create the Firewall Rules. I am using a simple 3 Tier APP.
- All Internal Servers can reach the DNS Servers
- Any can reach the Web Server via HTTP and HTTPS (80+443)
- Web Server can reach App Server via HTTP (80)
- App Server can reach DB Server via MySQL (3306)
- All other traffic will to the Servers will be rejected
I have created the following Groups before and added the VMs with Tags:
- Internal (all internal VMs belonging to this 3 Tier App)
- web
- app
- db
I put all the Datas together in one .json file and convert the .json file into a variable to use it later in my script. You can also use a Excel file or a CMDB to get all relevant information.
With the introduction from the Policy API, VMware also included different Categories in the distributed Firewall.
Inside each category you define the 5 Tuple Firewall Rules with following fields:
- Rule Name
- Source Group
- Destination Group
- Service (L4) and/or profile (L7 aware)
- Applied to (If not defined it will be applied to the dfw)
- Action (Allow, Drop, Reject)
Complete Script
$jsonfile = '[{
"category": "Application",
"sequence_number": "2",
"PolicyName": "DNS",
"RuleName": "Internal->DNS",
"rule_sequence_number" : "10",
"Source": "/infra/domains/default/groups/Internal",
"Destination": "ANY",
"Services": "/infra/services/DNS-UDP",
"profiles": "ANY",
"Action": "ALLOW",
"disabled": "false"
},
{
"category": "Application",
"sequence_number": "3",
"PolicyName": "3-TIER-APP",
"RuleName": "Any->WEB",
"rule_sequence_number" : "10",
"Source": "any",
"Destination": "/infra/domains/default/groups/web",
"Services": "/infra/services/HTTP,/infra/services/HTTPS",
"profiles": "ANY",
"Action": "ALLOW",
"disabled": "false"
},
{
"category": "Application",
"sequence_number": "3",
"PolicyName": "3-TIER-APP",
"RuleName": "WEB->APP",
"rule_sequence_number" : "20",
"Source": "/infra/domains/default/groups/web",
"Destination": "/infra/domains/default/groups/app",
"Services": "/infra/services/HTTP",
"profiles": "ANY",
"Action": "ALLOW",
"disabled": "false"
},
{
"category": "Application",
"sequence_number": "3",
"PolicyName": "3-TIER-APP",
"RuleName": "APP->DB",
"rule_sequence_number" : "30",
"Source": "/infra/domains/default/groups/app",
"Destination": "/infra/domains/default/groups/db",
"Services": "/infra/services/MySQL",
"profiles": "ANY",
"Action": "ALLOW",
"disabled": "false"
},
{
"category": "Application",
"sequence_number": "3",
"PolicyName": "3-TIER-APP",
"RuleName": "Deny-Any->Internal",
"rule_sequence_number" : "40",
"Source": "ANY",
"Destination": "/infra/domains/default/groups/Internal",
"Services": "ANY",
"profiles": "ANY",
"Action": "REJECT",
"disabled": "false"
},
{
"category": "Application",
"sequence_number": "3",
"PolicyName": "3-TIER-APP",
"RuleName": "Deny-Internal->ANY",
"rule_sequence_number" : "50",
"Source": "/infra/domains/default/groups/Internal",
"Destination": "ANY",
"Services": "ANY",
"profiles": "ANY",
"Action": "REJECT",
"disabled": "false"
}
]'
$jsonfileobj = ConvertFrom-Json -InputObject $jsonfile
#Create Firewall Rules
foreach ($secitem in $jsonfileobj) {
$secpolicyrulesservices = @($secitem.Services.split(","))
$secpolicyrulessource_groups = @($secitem.Source.split(","))
$secpolicyrulesdestination_groups = @($secitem.Destination.split(","))
$secpolicysvc = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.security_policies
#Create Security Policy
$secdomainspec = $secpolicysvc.Help.patch.domain_id
$secpolicyspec = $secpolicysvc.Help.patch.security_policy.Create()
$secpolicyidspec = $secpolicysvc.Help.patch.security_policy_id.Create()
$secdomainspec = "default"
$secpolicyidspec = $secitem.PolicyName
$secpolicyspec.display_name = $secitem.PolicyName
$secpolicyspec.category = $secitem.category
$secpolicyspec.sequence_number = $secitem.sequence_number
#Create Rules
$secpolicyrules = $secpolicysvc.Help.patch.security_policy.rules.Element.Create()
$secpolicyrules.display_name = $secitem.RuleName
$secpolicyrules.sequence_number = $secitem.rule_sequence_number
$secpolicyrules.source_groups = @($secpolicyrulessource_groups)
$secpolicyrules.destination_groups = @($secpolicyrulesdestination_groups)
$secpolicyrules.services = @($secpolicyrulesservices)
$secpolicyrules.action = $secitem.Action
$secpolicyrules.profiles = @($secitem.profiles)
$secpolicyrules.disabled = $secitem.disabled
$secpolicyrules.logged = "true"
$secpolicyspec.rules.Add($secpolicyrules) | Out-Null
#Run Command
$secpolicysvc.patch($secdomainspec, $secpolicyidspec, $secpolicyspec)
}
Let’s dive into the script:
First we will create the content with a .json file
$jsonfile = '[{
"category": "Application",
"sequence_number": "2",
"PolicyName": "DNS",
"RuleName": "Internal->DNS",
"rule_sequence_number" : "10",
"Source": "/infra/domains/default/groups/Internal",
"Destination": "ANY",
"Services": "/infra/services/DNS-UDP",
"profiles": "ANY",
"Action": "ALLOW",
"disabled": "false"
},
{
"category": "Application",
"sequence_number": "3",
"PolicyName": "3-TIER-APP",
"RuleName": "Any->WEB",
"rule_sequence_number" : "10",
"Source": "any",
"Destination": "/infra/domains/default/groups/web",
"Services": "/infra/services/HTTP,/infra/services/HTTPS",
"profiles": "ANY",
"Action": "ALLOW",
"disabled": "false"
},
....output ommitted
In this .json file we define the needed information for the Firewall. First we need to create a Section and than the Rule inside the Section.
category
Following Options are available (Case Sensitive):
- Emergency
- Infrastructure
- Environment
- Application
sequence_number
The Sequence Number should be used to place the Section in the right order. Otherwise the Section will be placed randomly.
PolicyName
I will use the Policyname as display Name from the Section and also as the Section ID.
Rulename
Now we create the Rule inside the Section. I use the Rulename as name for the Rule and also as Rule ID.
rule_sequence_number
The rule_sequence_number will be used to bring the Rules in the right order.
Source / Destination
Now we define the Source and Destination Group or Groups.
The Groups can be found under /infra/domains/default/groups/***
..and are Case Sensitive
If you would like to add more than one group you can separate the groups with comma.
example: “/infra/domains/default/groups/web,/infra/domains/default/groups/app”
Services
Services can be found under infra/services/***
…and are Case Sensitive.
If you would like to add more than one Service you can separate the Services with comma.
profiles
In my case should be any. Otherwise you must modify the script.
Action
The Action can be ALLOW, DROP or REJECT
disabled
Disable can be either true or false. If true, the Rule is disabled, if false the Rule is enabled.
We will now put the json content into a variable.
$jsonfileobj = ConvertFrom-Json -InputObject $jsonfile
Now we will create the loop for each Firewall Section and Firewall Rule
foreach ($secitem in $jsonfileobj) {
With the following command we will bring the content into the right format
$secpolicyrulesservices = @($secitem.Services.split(","))
$secpolicyrulessource_groups = @($secitem.Source.split(","))
$secpolicyrulesdestination_groups = @($secitem.Destination.split(","))
The following steps will create the Firewall Section. Domain is normally “default” if not changed by NSX Installation.
$secpolicysvc = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.security_policies
#Create Security Policy
$secdomainspec = $secpolicysvc.Help.patch.domain_id
$secpolicyspec = $secpolicysvc.Help.patch.security_policy.Create()
$secpolicyidspec = $secpolicysvc.Help.patch.security_policy_id.Create()
$secdomainspec = "default"
$secpolicyidspec = $secitem.PolicyName
$secpolicyspec.display_name = $secitem.PolicyName
$secpolicyspec.category = $secitem.category
$secpolicyspec.sequence_number = $secitem.sequence_number
Now we can create the Firewall Rule inside the Section.
$secpolicyrules.logged is set to true. This means all Traffic passing this rule will be logged.
#Create Rules
$secpolicyrules = $secpolicysvc.Help.patch.security_policy.rules.Element.Create()
$secpolicyrules.display_name = $secitem.RuleName
$secpolicyrules.sequence_number = $secitem.rule_sequence_number
$secpolicyrules.source_groups = @($secpolicyrulessource_groups)
$secpolicyrules.destination_groups = @($secpolicyrulesdestination_groups)
$secpolicyrules.services = @($secpolicyrulesservices)
$secpolicyrules.action = $secitem.Action
$secpolicyrules.profiles = @($secitem.profiles)
$secpolicyrules.disabled = $secitem.disabled
$secpolicyrules.logged = "true"
$secpolicyspec.rules.Add($secpolicyrules) | Out-Null
$secpolicysvc.patch($secdomainspec, $secpolicyidspec, $secpolicyspec)
}
- Setup NSX Application Platform from Scratch(K8S+MetallB+NFS Storage) - 25. February 2022
- Securing you K8S-Network with Antrea ClusterNetworkPolicy - 28. September 2020
- Integrate NSX Advanced Load Balancer (Formerly Avi Networks) in NSX-T - 17. August 2020
Hi Daniel, I am actually adding firewall rules in Manager console of NSX-T. I could create a firewall rules in a section but while adding the source and destination in it, it is failing. Actually we are migrating all dfw rules manually and thinking to leverage powershell for the same.
With the help of this article, https://www.vmbaggum.nl/2019/03/automate-nsx-t-with-powercli/, I could create but adding sources and destinations sounds tricky. Please let me know if you can help here.