Most engineers think…
Most engineers think the migration tool does 100% of the work and you just import the output file to go live.
Wrong -- tools consistently deliver 70-85% at best, and even that portion will silently break your network if NAT direction, zone design, and dropped inline rules are not reviewed by a human engineer who knows both platforms.
Migration Vocabulary — tap a card to flip
Four terms you need to own before you open any migration tool.
A logical label on one or more interfaces; policy is zone-to-zone, not by interface name. PAN and FortiGate are both zone/interface-pair based — ASA used security-levels (0–100) instead. So every migration must translate numbers into named zones with explicit rules.
Palo Alto's engine that identifies the real application in a flow ("this is Zoom, not just TCP/443"), so rules match the application, not the port. Port-based rules from ASA/Check Point work fine temporarily — use Policy Optimizer to migrate safely over 7–30 days.
FortiGate's inbound DNAT object — maps a public IP/port to an internal server. The equivalent of ASA's static-NAT-to-inside. Critical gotcha: VIPs are DNAT only; for bidirectional static NAT (like ASA), you need nat-source-vip enable or Central NAT — or the server egresses on its raw private IP.
A rule that can never match because a broader rule above it catches the traffic first. Common after flattening Check Point packages. Dangerous because the hidden rule may have carried the real IPS or URL-filter security profile — your traffic is "allowed" but unscanned.
▶ The 6-phase migration workflow
Sneha at HCL runs the universal playbook end-to-end. Press Play for the healthy path, then Break it to see the failure.
① Cisco ASA to Palo Alto: Zones, App-ID, and the Implicit-Allow Trap
When you export a Cisco ASA config and push it through a migration tool, the output looks complete — zones, rules, NAT entries. But there is one silent assumption baked into every ASA deployment that the tool cannot fix for you: security-level implicit allows. On an ASA, the inside interface at security-level 100 talks freely to the DMZ at security-level 50 with zero ACL entries. On Palo Alto, every packet between two zones is denied by default at the bottom of the rulebase — a hidden rule called interzone-default. Every implicit path your ASA passed silently now needs an explicit PAN rule, or it black-holes with no alert.
The conversion tool you would normally reach for — Expedition — reached End-of-Life on 1 January 2025. CVE-2024-5910 (CVSS 9.3, unauthenticated admin takeover) was added to the CISA KEV list and is actively exploited in the wild. Do not run Expedition on any network-reachable host. The current path is Strata Cloud Manager (SCM) with Palo Alto's Migration Factory professional-services team, or a manual conversion using the concept map below.
Even if you get every zone and ACL right, there is still the pre-NAT IP / post-NAT zone rule. If you publish a server via Destination NAT, the security rule must reference the public (pre-NAT) IP as destination and the private zone (post-NAT) as the destination zone. Expedition frequently generates the rule with the private IP, matching ASA's post-8.3 convention — and that rule never matches on PAN, so inbound traffic dies silently on day one.
After you get traffic flowing, do not flip every tcp-443 rule to App-ID immediately. Run Policy Optimizer for a minimum of 7 days first, read the "Applications Seen" list, then clone an App-ID rule above the port rule — never replace it outright. Custom internal apps that speak non-standard TLS on port 443 get classified as unknown-tcp the moment you switch, and those sessions reset instantly.
| Source (Cisco ASA) | → Target (PAN-OS) | Watch out for |
|---|---|---|
nameif inside |
Zone name inside |
Zone name is cosmetic — no trust value attached |
security-level 100 / 50 / 0 |
No equivalent | Every implicit higher→lower allow needs an explicit PAN rule or traffic black-holes |
access-group ACL in interface inside |
Security rule from zone inside |
ACL name has no PAN concept; map by source zone only |
object network HOST / subnet |
Address object (ip-netmask) |
Years of duplicate objects — same IP, 3 different names; consolidate before converting |
tcp eq 443 (service) |
Service object tcp-443 OR application-default on App-ID rule |
Port-based rule = expensive packet filter; App-ID rule = NGFW value; migrate gradually via Policy Optimizer |
Object NAT dynamic interface (PAT) |
Source NAT, Dynamic IP and Port, Interface Address | NAT exemption (no-NAT) rule MUST sit above the PAT catch-all in PAN — no automatic Section 1 priority like ASA |
Static NAT (static (dmz,outside)) |
Destination NAT rule + Security rule with pre-NAT public IP, post-NAT destination zone | Security rule destination = public IP, not private; zone = DMZ (where private lives) |
route outside 0.0.0.0 0.0.0.0 <gw> |
Static route under Virtual Router (default-gw) |
PAN has no routing without a Virtual Router; assign all L3 interfaces to it |
# ── ASA running-config (source) ──────────────────────────────────────────── interface GigabitEthernet0/1 nameif inside security-level 100 ip address 10.10.10.1 255.255.255.0 ! interface GigabitEthernet0/2 nameif dmz security-level 50 ip address 172.16.20.1 255.255.255.0 ! object network OBJ_APP_SERVER host 172.16.20.10 nat (dmz,outside) static 203.10.45.50 object network OBJ_INSIDE subnet 10.10.10.0 255.255.255.0 nat (inside,outside) dynamic interface ! ! NOTE: inside→dmz requires NO ACL on ASA — security-level 100→50 is implicit allow # ── PAN-OS set CLI equivalent (target) ───────────────────────────────────── # Zones (no security-level) set zone inside network layer3 [ ethernet1/2 ] set zone dmz network layer3 [ ethernet1/3 ] set zone outside network layer3 [ ethernet1/1 ] # Address objects set address OBJ_APP_SERVER ip-netmask 172.16.20.10/32 set address OBJ_INSIDE ip-netmask 10.10.10.0/24 # Source NAT (PAT for inside→outside) set rulebase nat rules PAT_INSIDE_OUT from inside set rulebase nat rules PAT_INSIDE_OUT to outside set rulebase nat rules PAT_INSIDE_OUT source 10.10.10.0/24 set rulebase nat rules PAT_INSIDE_OUT destination any set rulebase nat rules PAT_INSIDE_OUT source-translation dynamic-ip-and-port interface-address interface ethernet1/1 # Destination NAT (publish app server on public IP) set rulebase nat rules DNAT_APPSERVER from outside set rulebase nat rules DNAT_APPSERVER to outside set rulebase nat rules DNAT_APPSERVER destination 203.10.45.50 set rulebase nat rules DNAT_APPSERVER destination-translation translated-address 172.16.20.10 # EXPLICIT inside→dmz allow (was implicit on ASA — MUST add or traffic black-holes) set rulebase security rules ALLOW_INSIDE_TO_DMZ from inside set rulebase security rules ALLOW_INSIDE_TO_DMZ to dmz set rulebase security rules ALLOW_INSIDE_TO_DMZ source OBJ_INSIDE set rulebase security rules ALLOW_INSIDE_TO_DMZ destination any set rulebase security rules ALLOW_INSIDE_TO_DMZ application any set rulebase security rules ALLOW_INSIDE_TO_DMZ service any set rulebase security rules ALLOW_INSIDE_TO_DMZ action allow set rulebase security rules ALLOW_INSIDE_TO_DMZ log-end yes # Inbound allow — PRE-NAT public IP as destination, POST-NAT zone (dmz) set rulebase security rules ALLOW_INBOUND_APP from outside set rulebase security rules ALLOW_INBOUND_APP to dmz set rulebase security rules ALLOW_INBOUND_APP destination 203.10.45.50 set rulebase security rules ALLOW_INBOUND_APP application [ web-browsing ssl ] set rulebase security rules ALLOW_INBOUND_APP service application-default set rulebase security rules ALLOW_INBOUND_APP action allow commit
admin@PA-5250> show session all filter from-zone inside to-zone dmz
--------------------------------------------------------------------------------
ID Application State Type Flag Src[Sport]/Zone/Proto (translated IP[Port])
Dst[Dport]/Zone (translated IP[Port])
--------------------------------------------------------------------------------
12481 web-browsing ACTIVE FLOW NS 10.10.10.55[52301]/inside/6 (10.10.10.55[52301])
172.16.20.10[80]/dmz (172.16.20.10[80])
12499 unknown-tcp ACTIVE FLOW 10.10.10.82[55210]/inside/6 (10.10.10.82[55210])
172.16.20.15[8443]/dmz (172.16.20.15[8443])
admin@PA-5250> show counter global filter delta yes severity drop
Global counters:
Elapsed time since last sampling: 60.453 seconds
flow_policy_deny 0 0.0/s drop flow Packets dropped: policy deny
Sneha Iyer at HCL Technologies (Bengaluru) faces this
After migrating a Cisco ASA 5525-X to a PA-5250 for a manufacturing client, SAP traffic between the factory floor (10.10.10.0/24) and the ERP server (172.16.20.10) drops intermittently. No firewall alert fires — PAN passes the initial SYN but silently discards TCP retransmits. The application team reports "ERP timeout" errors and assumes the server is down.
The ASA had two ISP uplinks with asymmetric routing — the SYN enters on ISP-A but the reply sometimes leaves on ISP-B. ASA tracks sessions per interface and handles this fine. PAN-OS, by default, uses strict symmetric session matching: if the return packet enters a different interface than the session was created on, PAN drops it as a TCP state violation (reason: asymmetric-path). The Expedition migration did not carry over any asymmetric routing compensation because ASA had no explicit config for it.
Run the session filter and look for DISCARD state with the asymmetric-path reason flag. Also enable logging on interzone-default before going live on any migration — it catches both this and the security-level implicit-allow gaps simultaneously.
Short term: go to Device › Setup › Session › Session Settings and set "Asymmetric Path" to bypass to stop the drops while you stabilize. Long term, configure ECMP-aware routing under Network › Virtual Routers › [VR] › ECMP with symmetric hashing, and add Policy-Based Forwarding rules to pin each flow to one ISP. The bypass option disables stateful inspection on asymmetric paths — it is a diagnostic step, not a production setting.
Re-run show session all filter destination-port 3200 — all sessions should show state ACTIVE with no DISCARD entries. Run a 30-minute SAP login and transaction test from three factory-floor machines and confirm zero application drops. Then check show counter global filter delta yes severity drop to confirm flow_policy_deny and flow_tcp_asymmetric counters are both at zero.
Pause & Predict
You migrate an ASA that had nat (inside,outside) 1 source static OBJ_BRANCH OBJ_BRANCH destination static OBJ_HQ OBJ_HQ — a NAT exemption so VPN traffic is never translated. Expedition migrates both this no-NAT rule and the outbound PAT rule. Site-to-site VPN establishes but passes zero data. What most likely went wrong? Type your guess.
Sneha at HCL migrates a Cisco ASA 5525-X to a PA-5250. The ASA had interfaces with security-level 100 (inside), 50 (dmz), and 0 (outside). No ACLs covered inside→dmz traffic because ASA allowed it implicitly. After Expedition converts the config and Sneha pushes it live, inside users can no longer reach the DMZ application servers. Logs show no alerts. What is the most likely cause?
▶ When a 1:1 port→App-ID flip backfires
A naive port rule converted verbatim, then hard-switched to App-ID. Press Play for the healthy path, then Break it to see the failure.
② Check Point (R80/R81) → Palo Alto via Expedition
Check Point organises its rules inside policy packages that sit above one another in a strict hierarchy. When you hand that structure to Expedition, it collapses everything into a single, flat PAN-OS rulebase — and that collapse is where most migrations quietly break. Before you touch the export button, you need to understand what survives the flatten and what does not.
The most dangerous survivor is the inline layer. In Check Point an inline layer is a conditional branch: traffic hits a parent rule, gets redirected into a child policy tree, and is evaluated against sub-rules there. Expedition imports the parent rule with Action=Allow and silently drops every sub-rule inside the inline layer (documented in LIVEcommunity td-p/334292). Your "block social media for HR" enforcement vanishes with zero error message. Pre-flatten every inline layer in SmartConsole before you export — there is no shortcut.
The second gap is implied rules. Check Point silently permits SIC (port 18191), log forwarding (port 257), and routing protocol hellos via implied rules that ShowPolicyPackage never exports. After cutover on PAN-OS, interzone-default will drop all of that infrastructure traffic. Add explicit management-access rules for Panorama (HTTPS 443, SSH 22), syslog, and your routing protocol hellos before you flip the cable.
Expedition itself reached End-of-Life on 1 January 2025 — no patches, no TAC support, and CVE-2024-5910 (CVSS 9.3, unauthenticated admin takeover, CISA KEV) is actively exploited in the wild. If your organisation still uses it for this migration, run it on an isolated, air-gapped VM and decommission it immediately afterwards. For new projects, the replacement path is Palo Alto's Migration Factory engagement via fwmigrate@paloaltonetworks.com.
| Source (Check Point R80/R81) | → Target (PAN-OS) | Watch out for |
|---|---|---|
| Host Object / Network Object | Address Object (type: IP Netmask) | PAN names are global per vsys — avoid duplicates from multi-package exports |
| Address Group | Address Group (nested groups supported) | Negated objects ("NOT host X") need manual rebuild as two sequential rules |
| Service-TCP/UDP object | Service Object (TCP/UDP + port) | ICMP service objects have NO PAN service equivalent — map to App-ID ping/icmp |
| Ordered Layer ("Network", "DMZ") | Rulebase Section (cosmetic divider only) | Sections have no enforcement weight in PAN-OS — ordering of rules IS the enforcement |
| Inline Layer (child sub-policy) | Flat sequential rules with parent criteria prepended | Expedition drops child rules silently — pre-flatten in SmartConsole or rules are lost |
| Automatic Hide NAT (behind Gateway) | Source NAT — Dynamic IP and Port (interface-address) | Expedition skips "Hide behind Gateway" type — manually create DIPP rules for each |
| Manual Static DNAT (Dst translation) | Destination NAT rule + security rule using pre-NAT IP and post-NAT zone | Security rule must reference the PUBLIC IP (pre-NAT), but zone must be where the private server lives |
| Track → Log | log-end yes on the security rule |
Track → None migrates to no logging — easy to miss, kills your SOC visibility |
| Gateway topology: external / internal / DMZ | Zone: Untrust / Trust / DMZ | Map consistently before export; zone mismatch = interzone-default drops on day one |
| Implied rules (SIC, routing, log) | Not exported — explicit PAN management rules required | Missing = Panorama disconnects, VPN fails, OSPF adjacency drops post-cutover |
# ── STEP 1: Export from Check Point R81 Management Server ──────────────────
# Run this in expert mode on the SMS:
$MDS_FWDIR/scripts/web_api_show_package.sh \
-n "Corporate" \ # policy package name
--format json
# Also capture the route table from the gateway:
clish -c "show route all" > /tmp/gw-routes.txt
# ── CHECK POINT: the original objects + NAT rule ────────────────────────────
# Host Object:
# Name: WebServer-DMZ
# IPv4: 10.10.1.50/32
#
# Manual NAT Rule 1 — Static DNAT (internet → server):
# Original Src=Any Dst=203.88.12.20 Svc=Any
# Translated Src=Original Dst=10.10.1.50 Svc=Original
#
# Access Rule 7:
# Src=Any Dst=WebServer-DMZ Svc=HTTPS,Custom-8443 Action=Accept Track=Log
# ── PAN-OS EQUIVALENT (after Expedition + human review) ────────────────────
# Address objects:
set address WebServer-DMZ ip-netmask 10.10.1.50/32
set address WebServer-DMZ-Public ip-netmask 203.88.12.20/32
# NAT rule — Static DNAT (pre-NAT zone=Untrust, post-NAT zone=DMZ):
set rulebase nat rules Inbound-WebServer-DMZ from Untrust
set rulebase nat rules Inbound-WebServer-DMZ to Untrust
set rulebase nat rules Inbound-WebServer-DMZ source any
set rulebase nat rules Inbound-WebServer-DMZ destination WebServer-DMZ-Public
set rulebase nat rules Inbound-WebServer-DMZ service any
set rulebase nat rules Inbound-WebServer-DMZ destination-translation translated-address WebServer-DMZ
# Security rule — pre-NAT IP (203.88.12.20), post-NAT zone (DMZ):
set rulebase security rules Permit-Inbound-WebServer from Untrust
set rulebase security rules Permit-Inbound-WebServer to DMZ
set rulebase security rules Permit-Inbound-WebServer source any
set rulebase security rules Permit-Inbound-WebServer destination WebServer-DMZ-Public
set rulebase security rules Permit-Inbound-WebServer application ssl
set rulebase security rules Permit-Inbound-WebServer service application-default
set rulebase security rules Permit-Inbound-WebServer action allow
set rulebase security rules Permit-Inbound-WebServer log-end yes
admin@PA-3410> show nat rule-hit-count vsys vsys1
Name Pkg Rule Hit-Count
Inbound-WebServer-DMZ - Inbound-WebServer-DMZ 2,841
admin@PA-3410> show security rule-hit-count vsys vsys1
Name Pkg Rule Hit-Count
Permit-Inbound-WebServer - Permit-Inbound-WebServer 2,841
admin@PA-3410> test security-policy-match from Untrust to DMZ \
source 172.16.200.5 destination 203.88.12.20 protocol 6 port 443
Rule: Permit-Inbound-WebServer action: allow profile: IPS-Inbound
Rahul at TCS Mumbai faces this
After migrating Check Point R80.40 (3 policy packages, 620 rules) to Panorama + PA-3410, inbound HTTPS to the company's customer portal is allowed — but the Threat log shows zero IPS hits on that traffic. The SOC flags it three weeks later: a broad outbound rule with no security profile is matching inbound DMZ traffic.
Expedition merged three Check Point packages alphabetically ("Branch" → "Corporate" → "DMZ"). A broad Corporate rule — Src=any, Dst=any, App=ssl, Action=Allow — landed 60 positions above the specific DMZ-inbound rule that had the IPS profile attached. The broad rule shadows the specific one; inbound traffic matches the permissive rule and skips the IPS profile entirely. This is the classic policy-layer-flattening ordering bug.
Open Policy Optimizer and check Rule Usage. Any DMZ-inbound rule with zero hits despite known traffic is shadowed. Confirm by running a test match for a known inbound IP — the wrong rule name will appear in the output.
Panorama → Policies → Security → Policy Optimizer → Rule Usage / test security-policy-match CLIMove the specific DMZ-inbound rule above the broad any-to-any Corporate rule. Re-attach the correct Security Profile (IPS + AV + URL Filtering) to the DMZ-inbound rule. Long-term: use Panorama shared pre-rules + device-group post-rules to mirror the logical isolation that Check Point's separate packages provided — never flatten all packages into one order without deliberate re-sequencing.
Replay a known inbound HTTPS request in the lab and confirm the Threat log shows IPS hits on the correct rule. Run show security rule-hit-count after 30 minutes of live traffic — the DMZ-inbound rule must have a non-zero counter, and Policy Optimizer must show no shadowed rules with attached profiles.
Pause & Predict
You export a Check Point R81 policy that contains 180 rules. After Expedition imports it, Panorama shows only 153 rules. No error was logged. Where did the 27 rules go? Type your guess.
Rahul at TCS migrates a Check Point R80.40 cluster with an HR inline layer that blocks social-media sites for HR segment users. After Expedition converts the policy and the new PA-3410 goes live, the SOC team discovers HR users are freely accessing Instagram and YouTube during business hours. Which root cause best explains this?
③ Check Point (R80/R81) → FortiGate via FortiConverter
Check Point and FortiGate share the same first-match policy logic, so the rule ordering stays familiar — but almost everything else is named, structured, and evaluated differently. Before you touch FortiConverter, you must make one architectural decision that cannot be reversed mid-project: do you want Central NAT mode or Policy NAT mode? For a Check Point migration, Central NAT is the right answer 95% of the time, because Check Point already separates its access rulebase from its NAT rules. Matching that separation on FortiGate keeps your policy count near 1:1 and your audit far simpler.
Export your Check Point config before running the tool. On R80.10 and later, FortiConverter needs two CSV exports from SmartConsole: the firewall rules CSV and the NAT rules CSV. On R80.31 and above you can also use the ShowPolicyPackage JSON export, which preserves UUIDs for later audit tracing. Run FortiConverter in a lab VM or on a jump host — never on a live production host — and target the FortiOS version your new hardware runs (6.4, 7.0, 7.2, or 7.4 are all supported).
Expect FortiConverter to handle around 70–80% of the conversion automatically. The remaining 20–30% requires your hands: NAT global properties are silently dropped, protocol-type services like GRE and SCTP are not auto-converted, and FGCP HA needs per-unit out-of-band management IPs before you enable clustering. There is one more post-conversion step you must not skip: FortiConverter enables allowaccess on ALL services on ALL interfaces. Lock down your WAN-facing interface to ping only before you push anything to production.
After import, run diagnose firewall iprope lookup for every critical server flow. In Central NAT mode the policy matches on the pre-DNAT public IP, which is the same mental model Check Point engineers already use. In Policy NAT mode the VIP lookup happens first — the policy must explicitly list the VIP object as its destination or the flow gets dropped after DNAT fires. That mismatch is the top-reported failure mode on this path, and it is invisible until you test inbound traffic from outside.
| Source (Check Point R80/R81) | → Target (FortiOS) | Watch out for |
|---|---|---|
| Network / host object | config firewall address (type ipmask / iprange) |
FQDN objects resolve at policy install time on CP; FortiGate uses live DNS with TTL cache — behavior differs for fast-changing IPs |
| Address group | config firewall addrgrp |
Groups with >600 members hit FortiGate's default limit; split before migration |
| TCP/UDP service object | config firewall service custom |
Check Point names like SAP_RFC may collide with FortiGate built-ins; FortiConverter may suffix — audit the _conflict entries |
| Protocol-type service (GRE 47, SCTP 132) | config system session-helper (manual) |
Not auto-converted — every raw-protocol service is a manual post-step |
| Ordered access rulebase (first-match, implicit deny) | config firewall policy (srcintf + dstintf pairs; Policy 0 = implicit deny) |
Check Point rulebases are NOT interface-pair locked; FortiConverter infers pairs from routing — supply ifconfig output for accuracy |
| Hide NAT (dynamic masquerade / auto-hide behind gateway) | config firewall central-snat-map (Central NAT) or set nat enable in policy |
NAT Global Properties are silently dropped by FortiConverter — rebuild outbound masquerade rules manually |
| Static NAT (1:1 object-attached Automatic NAT) | config firewall vip (type static-nat) + policy with VIP as dstaddr |
Policy NAT only: policy must reference the VIP as destination — NOT the internal host object — or DNAT fires but policy lookup fails (iprope_in_check() check failed) |
| ClusterXL Active/Passive | FGCP set mode a-p; primary gets virtual MACs and owns all IPs |
Assign per-unit OOB management IPs via set ha-mgmt-interfaces BEFORE enabling HA — skipping this locks you out of both units simultaneously |
| VPN community (Star/Mesh) encryption domain | Phase1/phase2 stubs; Quick Mode selectors = named address objects | CP /32 host encryption domains do NOT automatically match FortiGate phase2 subnet blocks — build a selector comparison table before cutover |
| Track = Log (per rule) | set logtraffic [utm / all] per policy |
FortiConverter defaults all policies to logtraffic utm (UTM events only) — change to all where full session logging is required |
# ── Step 1: Enable Central NAT (do this ONCE before import) ──────────
config system settings
set central-nat enable
end
# ── Step 2: VIP for inbound DNAT (replaces CP static NAT on host object) ─
# CP had: Automatic NAT on host_WebPortal → static, 10.10.50.20 ↔ 203.0.113.60
config firewall vip
edit "VIP_GovPortal_HTTPS"
set extip 203.0.113.60
set extintf "port1"
set type static-nat
set mappedip "10.10.50.20"
set portforward enable
set protocol tcp
set extport 443
set mappedport 443
set comment "Migrated: CP Automatic NAT on host_WebPortal"
next
end
# ── Step 3: Firewall policy (Central NAT — dstaddr is the VIP) ──────────
config firewall policy
edit 5
set name "Internet_to_GovPortal"
set srcintf "port1"
set dstintf "port2"
set srcaddr "all"
set dstaddr "VIP_GovPortal_HTTPS"
set action accept
set schedule "always"
set service "HTTPS"
set logtraffic all
set comments "Migrated from CP rule 14"
next
end
# ── Step 4: Central SNAT for outbound hide NAT (CP auto-hide behind gateway) ─
config firewall central-snat-map
edit 1
set orig-addr "Corp_LAN"
set srcintf "port3"
set dst-addr "all"
set dstintf "port1"
set nat enable
set comments "Migrated: CP Auto Hide Corp_LAN → WAN"
next
end
# diagnose firewall iprope lookup 172.16.100.5 54320 203.0.113.60 443 tcp port1
<src [172.16.100.5-54320] dst [10.10.50.20-443] proto tcp dev port1>
matches policy id: 5
# get firewall policy (excerpt)
policyid: 5 name: "Internet_to_GovPortal" srcintf: port1 dstintf: port2
srcaddr: all dstaddr: VIP_GovPortal_HTTPS action: accept logtraffic: all
# diagnose debug flow filter dport 443
id=20085 trace_id=1 func=iprope_in_check line=106 msg="Allowed by Policy-5"
# get system ha status (cluster check)
HA Health Status: OK sync-state: in-sync master: FW-UNIT1
Aditya at Wipro (Hyderabad) faces this
Three Telangana government portal servers stop responding from the internet after a Check Point R77.30 → FortiGate 600E cutover. Internal users hit them fine. No firewall deny log is visible.
FortiConverter ran in Policy NAT mode (the default). Check Point's Automatic NAT was attached to each host object, so FortiConverter created VIPs correctly — but left the inbound firewall policies pointing to the original internal host address objects (10.10.30.5, etc.) instead of the VIP objects. In Policy NAT mode, DNAT (VIP lookup) fires first in the kernel, translates the destination to the private IP, and then the policy lookup runs. Since no policy lists the VIP as its destination, the lookup finds no match and drops the packet after NAT — which is why no explicit deny log appears.
Enable a debug flow filter on destination port 443 and watch for iprope_in_check() check failed — that message confirms the packet passed DNAT but failed the policy lookup. Cross-check by running the iprope lookup tool: use the translated private IP as the destination; it should match a policy. Then use the public (pre-DNAT) IP; it will return no match — confirming the policy lists the wrong destination.
Two options. Quick fix: edit each inbound policy in Policy & Objects → Firewall Policy and change the Destination field from the internal host object to the corresponding VIP object. Better long-term fix: switch to Central NAT mode (config system settings → set central-nat enable) and re-run the FortiConverter output — Central NAT mode matches policies on the pre-DNAT IP, which mirrors how Check Point Automatic NAT worked and removes the VIP-in-policy requirement entirely.
Re-run diagnose debug flow filter dport 443 — packets must now show Allowed by Policy-N. Test inbound browser access to all three portals from a mobile hotspot (external IP) and confirm HTTP 200 responses. Run get firewall policy and confirm every inbound policy's dstaddr is a VIP object, not a plain host address.
Pause & Predict
You run FortiConverter on a 300-rule Check Point R81 config using the default NAT mode. Your colleague tells you the output has 840 policies. Is that expected, and how do you prevent it in a re-run? Type your guess.
Aditya at Wipro migrates a Check Point R77.30 gateway to a FortiGate 600E in Policy NAT mode using FortiConverter. Three government portal servers have inbound DNAT entries (public IP→private 10.x). After cutover, external users cannot reach the portals. Running 'diagnose debug flow filter dport 443' shows 'iprope_in_check() check failed'. What is the correct fix?
④ Cisco ASA → FortiGate via FortiConverter
You export a Cisco ASA running-config with show running-config, upload it to FortiConverter, and download a FortiOS CLI script — that is the mechanical part. The hard part starts after you run get system status on the target box, because the decision you make in the next five minutes (Central NAT or Policy NAT?) determines whether your NAT rules work or silently break under load.
Before you apply any generated script, decide your Central NAT mode. Enable it once with config system settings; set central-nat enable. If you skip this and try to add Central SNAT rules later while Policy NAT is active, FortiGate silently ignores the central-snat-map entries — traffic keeps flowing but from the wrong source IP, and the logs will not tell you why. For large ASA jobs, Central NAT cuts rule inflation and matches the ASA model far more cleanly than the Policy NAT default.
Once the base L3/L4 config is stable, you are only halfway done. The ASA you just replaced was a stateful L3/L4 packet filter. It had zero visibility into file content, application behaviour, or exploit payloads. FortiGate ships with a full UTM security profile framework sitting idle until you turn it on. Add AV and IPS profiles in monitor mode first; block mode on Day 1 will cause false-positive outages on production traffic.
Finally, patch the box before it touches production. Two actively-exploited CVEs affect fresh FortiGate deployments: CVE-2024-55591 (CVSS 9.6, auth bypass to super-admin on FortiOS 7.0.0–7.0.16, CISA KEV since January 2025) and CVE-2024-21762 (CVSS 9.6, unauthenticated RCE via the SSL-VPN daemon on FortiOS pre-7.4.3/7.2.7/7.0.14). Run get system status — confirm your FortiOS build is ≥7.4.3, ≥7.2.7, or ≥7.0.17 before you connect the WAN cable.
| Source (ASA) | → Target (FortiOS) | Watch out for |
|---|---|---|
nameif outside / security-level 0 |
set role wan on wan1; optional config system zone UNTRUST |
No security-level concept on FortiGate — every direction needs an explicit policy or traffic drops silently |
nameif inside / security-level 100 |
set role lan on internal; optional TRUST zone |
ASA implicitly allowed higher→lower (inside→outside); FortiGate does not — write the permit rule explicitly |
object network host/subnet |
config firewall address type ipmask |
Names like HTTP, any, ALL collide with FortiGate built-ins; search output for _conflict before applying |
object-group network |
config firewall addrgrp |
Same name-collision risk; audit every _conflict object individually |
access-group ACL in interface X |
Firewall policy with srcintf + dstintf pair |
ASA ACL binds to one interface; FortiGate policy needs BOTH interfaces — FortiConverter generates only the one-directional policy; add reverse policies for bidirectional initiated traffic manually |
Object NAT static (DNAT): nat (dmz,outside) static <pub-ip> |
config firewall vip with extip + mappedip; policy dstaddr = VIP name |
VIP is DNAT only by default — outbound from the server still uses its raw private IP unless you add set nat-source-vip enable on the VIP (reproduces ASA's bi-directional static NAT) |
Object NAT dynamic interface (PAT): nat (inside,outside) dynamic interface |
config firewall ippool type overload; policy set nat enable; set ippool enable; set poolname <pool> |
Without Central NAT, the IP pool must be explicitly referenced in every outbound policy — easy to miss when the pool IP is the same as the WAN interface IP |
| ASA Twice NAT (manipulates src and dst in one rule) | VIP (handles DNAT) + config firewall central-snat-map (handles SNAT on same flow) |
Requires Central NAT mode enabled globally first — mixing Central SNAT with Policy NAT mode silently ignores the central-snat-map entries |
route outside 0.0.0.0 0.0.0.0 <gw> |
config router static; edit 1; set dst 0.0.0.0/0; set gateway <gw>; set device wan1 |
FortiConverter generally converts routes correctly; verify with get router info routing-table all post-import |
| No UTM profiles (ASA is L3/L4 only) | Add AV + IPS + Web Filter + App Control profiles to policies after base migration | Add in monitor mode first — switching directly to block mode causes false-positive production outages on Day 1 |
_conflict object and add nat-source-vip enable for bi-directional servers, and you patch to ≥7.4.3/7.2.7/7.0.17 before the WAN is live.
! ── ASA running-config excerpt (office LAN + SWIFT server, Indian ISP /29) ──
interface GigabitEthernet0/0
nameif outside
security-level 0
ip address 103.21.58.1 255.255.255.248
!
interface GigabitEthernet0/1
nameif inside
security-level 100
ip address 192.168.10.1 255.255.255.0
!
interface GigabitEthernet0/2
nameif dmz
security-level 50
ip address 10.50.1.1 255.255.255.240
!
object network SWIFT-SRV
host 10.50.1.10
object network INSIDE-LAN
subnet 192.168.10.0 255.255.255.0
! Bi-directional static NAT for SWIFT server
object network SWIFT-SRV
nat (dmz,outside) static 103.21.58.2
! PAT for outbound office traffic
object network INSIDE-LAN
nat (inside,outside) dynamic interface
!
access-list OUTSIDE-IN extended permit tcp any host 103.21.58.2 eq 443
access-list OUTSIDE-IN extended deny ip any any log
access-group OUTSIDE-IN in interface outside
access-list INSIDE-OUT extended permit ip object INSIDE-LAN any
access-group INSIDE-OUT in interface inside
route outside 0.0.0.0 0.0.0.0 103.21.58.6
! ── Equivalent FortiOS 7.4 CLI (after FortiConverter + manual review) ──
config system settings
set central-nat enable ! must be set BEFORE applying NAT objects
end
config system interface
edit "wan1"
set ip 103.21.58.1 255.255.255.248
set allowaccess ping ! lock down — FortiConverter defaults are too permissive
set role wan
next
edit "internal"
set ip 192.168.10.1 255.255.255.0
set allowaccess ping https ssh
set role lan
next
edit "dmz"
set ip 10.50.1.1 255.255.255.240
set allowaccess ping
set role dmz
next
end
config firewall address
edit "SWIFT-SRV"
set type ipmask
set subnet 10.50.1.10 255.255.255.255
next
edit "INSIDE-LAN"
set type ipmask
set subnet 192.168.10.0 255.255.255.0
next
end
config firewall vip
edit "VIP-SWIFT-SRV"
set extip 103.21.58.2
set extintf "wan1"
set mappedip "10.50.1.10"
set portforward disable
set nat-source-vip enable ! reproduces ASA bi-directional static NAT
next
end
config firewall ippool
edit "POOL-WAN-OUT"
set startip 103.21.58.1
set endip 103.21.58.1
set type overload
next
end
config router static
edit 1
set dst 0.0.0.0 0.0.0.0
set gateway 103.21.58.6
set device "wan1"
next
end
config firewall policy
edit 10
set name "OUTSIDE-to-DMZ-SWIFT"
set srcintf "wan1"
set dstintf "dmz"
set srcaddr "all"
set dstaddr "VIP-SWIFT-SRV" ! must be VIP name, not internal host
set service "HTTPS"
set action accept
set logtraffic all
next
edit 20
set name "INSIDE-to-OUTSIDE"
set srcintf "internal"
set dstintf "wan1"
set srcaddr "INSIDE-LAN"
set dstaddr "all"
set service "ALL"
set action accept
set nat enable
set ippool enable
set poolname "POOL-WAN-OUT"
set logtraffic utm
next
end
FortiGate # get system status | grep Version
Version: FortiGate-80F v7.4.3,build2573,240222
FortiGate # get router info routing-table all
S* 0.0.0.0/0 [10/0] via 103.21.58.6, wan1
C 10.50.1.0/28 is directly connected, dmz
C 103.21.58.0/29 is directly connected, wan1
C 192.168.10.0/24 is directly connected, internal
FortiGate # diagnose debug flow trace start 5
id=65308 trace_id=1 msg="DNAT 103.21.58.2->10.50.1.10"
id=65308 trace_id=1 msg="find a route: gw-10.50.1.10 via dmz"
id=65308 trace_id=1 msg="Allowed by Policy-10: OUTSIDE-to-DMZ-SWIFT"
id=65308 trace_id=1 msg="SNAT 10.50.1.10->103.21.58.2 (nat-source-vip)"
Priya Verma at a Lucknow urban co-operative bank faces this
After migrating the SWIFT payment servers from ASA to FortiGate 80F, inbound connections to the servers work fine — but the correspondent bank's team reports that outbound connection attempts from the SWIFT servers arrive with the bank's internal IP 192.168.10.20 instead of the registered public IP 103.21.58.2. The correspondent bank's firewall is blocking them.
FortiConverter correctly created a VIP for inbound DNAT (103.21.58.2 → 192.168.10.20) but did not add set nat-source-vip enable. FortiGate VIPs are DNAT-only by default — the outbound (server-initiated) half of the ASA bi-directional static NAT was silently dropped. The SWIFT server's traffic goes out on its raw private IP.
Run a packet capture on the WAN interface targeting the SWIFT server's traffic. If source IP in the capture shows 192.168.10.20 rather than 103.21.58.2, the VIP's outbound SNAT is missing. Confirm with the session list — look for act=snat in the reply hook; if it shows the private IP instead of the public IP, nat-source-vip is not active.
Edit the VIP object for each SWIFT server and add set nat-source-vip enable. Then confirm the outbound firewall policy for SWIFT traffic has set nat enable and that the policy's source address includes the SWIFT server. No change to the policy ID or VIP IP mapping is needed — only the nat-source-vip flag and the outbound NAT enable.
Re-run diagnose sniffer packet wan1 'host 192.168.10.20' 4 — the captured WAN packets should now show source IP 103.21.58.2. Initiate a test transaction from the SWIFT server and ask the correspondent bank to confirm the connection arrives from the registered public IP. Cross-check with diagnose sys session list | grep 192.168.10.20 — the reply hook should show act=snat 192.168.10.20:<port>→103.21.58.2:<port>.
Pause & Predict
You port an ASA config to FortiGate with FortiConverter and go live. Internal users can reach the internet fine (outbound PAT works). But users outside cannot reach the web server published on 103.21.58.2 — the connection just times out. The VIP object exists. What is the most likely missing piece? Type your guess.
SWIFT-SRV or WEB-SRV) as the destination instead of the VIP object (VIP-SWIFT-SRV). In Policy NAT mode, FortiGate performs the DNAT lookup only when the policy's dstaddr is the VIP name — if the policy points at the raw internal IP, DNAT fires but the policy match fails with iprope_in_check() check failed and the connection is dropped. Fix: edit the inbound policy and change dstaddr from the host object to the VIP object. If you are on Central NAT mode, this is handled differently — the VIP is still the dstaddr in the policy, but NAT itself is managed by the DNAT table rather than being embedded in the policy action.Priya, IT head at a Lucknow co-operative bank, replaces a Cisco ASA 5506-X with a FortiGate 80F. The ASA had a bidirectional static NAT for two SWIFT servers: internal 192.168.10.20 ↔ public 203.0.113.50. FortiConverter creates a VIP for inbound DNAT. After cutover, inbound traffic to the SWIFT servers works, but the correspondent bank reports the bank's connection attempts arrive from 192.168.10.20, not 203.0.113.50. What must Priya configure?
⚖️ Which path, which tool, and how to cut over
Automate or rebuild? Run the tool when your config is recent and reasonably clean. Rebuild from scratch when it is more than five years old, never formally audited, or shows over 35% zero-hit rules — those numbers mean you would just be porting years of technical debt onto a new box. In a rebuild you still run the tool, but only as a reference document: keep its output in one window and your blank PAN-OS or FortiOS policy editor in the other, and build each rule intentionally with zones, App-ID and security profiles from day one.
Big-bang, phased, or parallel? Big-bang (flip everything at once) is only safe for a small site with a tested rollback. Phased moves one segment or branch at a time. The standard for anything that matters is a parallel dual-run: stand the new firewall beside the old one in monitor/tap mode, run both for about 14 days, compare logs daily, then flip the gateway at 2 AM on a Sunday. Keep the old firewall powered but out of path for the first 48 hours — that is your instant rollback. Most failed cutovers trace back to a skipped baseline, not bad hardware.
All four paths at a glance: the two Palo Alto paths use Expedition (now End-of-Life — offline use only) and turn into a zone-and-App-ID job; the security-level model and Check Point's inline layers are the hardest things to translate. The two FortiGate paths use FortiConverter, and the make-or-break decision is choosing Central NAT mode before you run it. Across every path, NAT is where engineers lose the most hours, so prove every NAT rule in a lab before cutover.
Decide your FortiGate NAT mode before you run FortiConverter, and pick Central NAT for ASA and Check Point sources. Both vendors already keep access policy and NAT separate, so Central NAT lands you near a 1:1 rule count — Policy NAT inflates the same job 2–3× and the cleanup eats your whole audit window.
Trusting the tool's output as finished. Expedition and FortiConverter convert 70–85% at best, and they silently drop the dangerous parts — Check Point inline sub-rules, NAT global properties, "Hide behind Gateway" NAT — while leaving management wide open on every interface. A pushed-but-unreviewed config looks fine until inbound servers, VPN tunnels, or HR web-filtering quietly fail.
Don't eyeball it — trace it. On Palo Alto, log interzone-default and run Policy Optimizer before converting to App-ID; on FortiGate, run diagnose firewall iprope lookup <src> <sport> <dst> <dport> tcp <srcintf> and confirm the expected policy ID matches post-NAT. Compare source-vs-target rule and NAT counts, replay critical flows, and get written sign-off from each app owner before you decommission the old box.
Top 4 Migration Mistakes — tap each card to see the fix
These four mistakes account for the majority of post-migration production incidents.
Tools deliver 70–85% at best. NAT direction, App-ID, zone design, and asymmetric routing are your calls — the tool cannot taste the dish, only translate the recipe. Always human-review and lab-test every path before cutover.
No. PAN's interzone-default denies all traffic between different zones unless an explicit rule allows it. Every implicit ASA allow (inside→DMZ, etc.) needs an explicit PAN rule or traffic black-holes with no alert, no log, no obvious cause.
Expedition imports only the parent rule and silently drops the inline sub-rules. Your "block social media for HR" enforcement vanishes entirely. Pre-flatten all inline layers in SmartConsole before export — then verify the rule count matches post-import.
Check the OTHER direction. FortiGate VIPs are DNAT-only. A 1:1 ASA static NAT needs nat-source-vip enable (or Central NAT) or the server egresses on its raw private IP — clients see a foreign source address and reset the session.
🤖 Ask the AI Tutor
Tap any question — instant, scoped to this lesson. No login, no waiting.
Pre-curated from Multi-Vendor docs + community Q&A, scoped to this lesson. For a live prod issue, paste your export into chat.techclick.in.
📝 Wrap-up assessment — six more
You've answered 4 inline. Six left. 70% (7 of 10) marks the lesson complete on your profile. Tap Submit all answers at the end.
🧠 In your own words
Type one line: In one line, why can't a migration tool alone guarantee a successful firewall migration? Then compare to the expert version.
🗣 Teach a friend
Best way to lock it in — explain it in one line to a teammate. Tap to generate a paste-ready summary.
📖 Glossary
- Expedition
- Palo Alto's former config-migration VM; End-of-Life since 1 Jan 2025, no patches, several actively-exploited CVEs (CVE-2024-5910 CVSS 9.3, CISA KEV). Use offline/air-gapped only, or move to SCM / Migration Factory.
- FortiConverter
- Fortinet's migration tool (standalone Tool 7.4.x or engineer-reviewed Service 25.1.0); converts approximately 70–85% of a real config to FortiOS CLI — mandatory human review for the remainder.
- Security-level
- Cisco ASA's numeric trust value (0–100); higher→lower passes by default. Has no equivalent on PAN-OS or FortiGate — every interzone path needs an explicit allow rule after migration.
- interzone-default
- PAN-OS's hidden bottom rule that denies all traffic between different zones unless an explicit rule allows it; the most common source of silent black-holes after an ASA migration.
- Policy Optimizer
- PAN-OS tool that watches which apps actually hit a port-based rule so you can safely convert it to App-ID over 7–30 days, without breaking legitimate traffic.
- Inline layer
- Check Point's conditional sub-policy attached to a parent rule; the part Expedition silently drops on import — pre-flatten in SmartConsole before export to prevent silent policy gaps.
- Hide NAT (PAT)
- Many-to-one translation: many internal hosts share one public IP via different ports. Called 'dynamic interface' in ASA, 'set nat enable' or central-snat-map in FortiGate.
- Static NAT
- One-to-one, bidirectional mapping between a private and a public IP; used for servers reachable from the internet on a fixed address. Implemented as a VIP in FortiGate.
- Central NAT
- FortiGate mode that keeps SNAT (central-snat-map) and DNAT (VIP) in separate tables from firewall policies; recommended for both ASA and Check Point migrations to avoid rule-count explosion.
- Parallel dual-run
- Cutover method where old and new firewalls run together — new in tap/monitor mode — for approximately 14 days to baseline traffic before flipping the gateway IP, with the old firewall on 48-hour rollback standby.
📚 Sources
- Palo Alto Networks — Expedition End-of-Life Announcement (Jan 2025). live.paloaltonetworks.com
- Palo Alto Networks — Migrate Port-Based to App-ID Based Security Policy Rules. docs.paloaltonetworks.com
- LIVEcommunity — Check Point R80.30 Inline Layers Conversion (sub-rules dropped by Expedition). live.paloaltonetworks.com
- Fortinet — FortiConverter Service 25.1.0: Policy NAT vs Central NAT Mode. docs.fortinet.com
- Fortinet — FortiConverter 7.4.1 Check Point Conversions (known limitations, AllowAccess). docs.fortinet.com
- Tenable — CVE-2024-55591: FortiOS Authentication Bypass Zero-Day Exploited in the Wild (CVSS 9.6). tenable.com
- CybersecurityDive — CVE-2024-5910: Palo Alto Expedition Exploited in the Wild (CVSS 9.3, CISA KEV). cybersecuritydive.com
- Fortinet PSIRT — FG-IR-24-015: CVE-2024-21762 SSL-VPN Out-of-Bounds Write RCE (CVSS 9.6). fortiguard.com
- Fortinet Community — Technical Tip: Trace which firewall policy matches based on IP (diagnose iprope lookup). community.fortinet.com
- PacketSwitch — The Correct Way to Migrate from Cisco ASA to Palo Alto. packetswitch.co.uk
- FusionComputing — Firewall Migration Plan: 7-Step Checklist for Zero Downtime. fusioncomputing.ca
- FireMon — Firewall Migration Checklist: Complete 10-Step Guide. firemon.com
What's next?
You can now move a rulebase between platforms. Next, go deep on the single hardest part of every path — NAT. The next lesson breaks down how source and destination NAT actually evaluate on each firewall, so your published servers come up the first time.