Firewall Migration
A few months ago, I migrated our datacentres’ firewalls. Not only were we moving to a new platform that performs functions differently, but we also used this opportunity to move the production site from virtualised firewalls to physical firewalls. This was further amplified by a short timeframe due to looming license expiration.
Whilst I’ve got experience managing firewalls and deploying new firewalls, this was the first firewall migration I’ve performed. As you might expect, I ran into a few issues during this and definitely learnt a few lessons.
Shipping and Logistics
As the hardware in the datacentre is somewhat managed by a 3rd party, I had to collaborate with them on racking the equipment and connecting it up to the datacentre’s core switches. We also had to purchase the firewalls and licenses, including comparing different quotes, different pricing options etc.
Between purchasing hardware during a hardware shortage, miscommunications from the 3rd party on initial out-of-box configuration and organising shipping the now-configured firewalls to a datacentre across the country, I had severely underestimated just how long this would take (my expectations being days, not weeks).
Dodgy Import Tools
To avoid manually creating 100s of rules, I used an import tool from the vendor’s GitHub. The tool was designed to export firewall rules, network objects and Site-to-site VPNs from a firewall backup, then import all of this config into our new firewalls.
However, this tool failed to import several firewall rules, without leaving a log to state that it failed! Thankfully, after spotting the discrepancy (specifically, the difference in the number of rules on the old vs new firewalls), I realised what had happened. The root cause of the failed imports appeared to be when network groups had contained a large number of hosts, though on a few rules there also seemed to be an issue caused by the rule name and its length.
Furthermore, due to technical differences in where rule names are displayed, the import tool had grabbed the system-generated rule names (which were created by the old firewalls on initial rule creation), which were not readable and often mentioned decommissioned systems and narrower scopes than the rules were now covering.
Whilst this tool was created to save time, I had to manually go through and check each rule on the new firewalls against our old firewalls, and rename each rule to ensure we hadn’t greatly decreased the manageability of the ruleset on the new firewall rules.
Difference in functionality
The new firewalls we deployed handled a few different functions differently, some of which that caught me out.
IPS
On our old firewalls, the IPS configuration was firewall-wide, whereas the new firewalls’ IPS functionality operated on a per-rule basis - other security controls (application controls, TLS inspection etc) also operated in the same way. Whilst this does allow for more granular configuration, the sudden switch wasn’t ideal, especially considering that all of the imported rules had no IPS configuration by default.
Furthermore, after looking at the built-in IPS policies which contained ancient signatures to mitigate ancient (10+ years - that is ancient in the security world!) vulnerabilities, with no age filtering (ideally there’d be a ”< 1 year old” filter), I had to implement a hacky solution - filtering for any signatures that included “CVE-2026” or “CVE-2025”.
After creating the custom IPS policy, I managed to automate enabling IPS on all of the firewall rules with a quick Python script (utilising the firewall’s API, looping through each rule and enabling the custom IPS policy I’d created), mirroring the controls we had in place previously.
Zoning
On our new firewalls, all VLANs/networks reside in Zones (DMZ, Internal etc). Any newly-created firewall rules are scoped to the relevant zones too.
One would think that the firewall views the source and destination IP addresses on the packet to determine the zones, though we realised this was not the case when connectivity wasn’t being permitted for VPN clients using our dual-NIC VPN appliance (public-facing NIC in a DMZ zone, NIC for internal connectivity in an Internal Zone).
Due to this design, despite the source address of the packets being on our internal network, the packets were leaving via the DMZ interface - meaning the firewall treated the traffic as DMZ, our Internal-scoped rule didn’t match, and the connectivity was dropped.
As such, we determined the firewall looks at the interface, not the IP addresses.
NAT
Another difference I observed was the order in which NAT and firewall rules were processed. To permit connectivity to a NAT’d source/destination, you would scope the firewall rule to the pre-NAT’d address.
After enabling various firewall rules during the switchover, we observed public-facing traffic not being permitted - this was caused by the new firewall processing firewall rules after NAT, meaning to permit connectivity to a NAT’d source/destination, the post-NAT’d address was required.
Features on by default
A couple of features on the firewalls caught me out - one of which was how it handled denying HTTP(S) traffic.
When denying traffic, dropping is generally preferred from a security POV (compared to instantly rejecting the packets) as the attacker is not able to easily distinguish whether the firewall has dropped the attempted connection or if there is no host / service running on the attempted IP and port. The firewall import/migration tool migrated our drop rules as expected, though when users (generally IT) attempted to make a HTTP(S) connection to a server and the connection was dropped by the firewall, the new firewall’s behaviour was to serve a block page.
This caused lots of confusion, as it now appeared as though we were intentionally blocking the connection, but also when performing Test-NetConnection / nc connectivity tests, the port appeared to be open until further investigation.
We also observed certificate warnings due to the firewall using its TLS inspection certificate (for context - we perform TLS inspection at another layer, so don’t currently utilise the TLS inspection features on our firewalls and therefore don’t trust the certificate on our machines).
Summary
There were three main lessons I learnt from this firewall migration:
- Things take much longer than you might expect.
- Whilst systems may perform the same function, subtle differences can have big impacts.
- Anything that can go wrong, will go wrong.
I’ve been keeping these three lessons in mind since.