Why this matters — the dabbawala rule
Think of Mumbai's dabbawalas. Twelve lakh tiffins a day reach the right office through a strict, ordered handoff — the first matching code on the lid wins, even if a more specific code exists further down the route. FortiGate firewall policies work exactly the same. The firewall scans your policy list top-down and the first rule that matches every field (source interface, source IP, destination interface, destination IP, service, schedule, user) wins — no matter how specific a later rule is.
That single sentence is where most L1 candidates pass or fail. Get it right and the next 10 minutes of the interview belong to you.
Sneha (L1 SOC, 8 months in) gets a ticket: "Sales laptop 10.20.1.50 can hit Salesforce on Monday but not on Tuesday." She finds two policies — Policy ID 7 (src 10.20.1.0/24, dst any, action allow + per-policy NAT) and Policy ID 12 (src 10.20.1.50/32, dst salesforce.com ISDB, action deny, created last Friday by mistake).
Sneha's first instinct: "Policy 12 is more specific, so it must be winning." Wrong. FortiGate evaluates top-down by sequence number, not specificity. Policy 7 sits above Policy 12 → Policy 7 wins every time → traffic is allowed. The Tuesday block was a different cause (FortiGuard ISDB DB refresh briefly empty). She solves it in 90 seconds with one command. We'll see that command at the end.
Two terms every interviewer will test
Policy ID is the immutable handle the firewall uses to remember a policy (you see it in logs, CLI, references). Sequence number is the position in the evaluation list — and that is what determines match order. Don't conflate the two. Reorder policies via the GUI drag-handle (or move CLI), don't change policy IDs.
Immutable handle assigned at creation. Shows in logs as policyid=7. Doesn't change when you reorder. CLI reference, not match-order.
Position in the evaluation list — this is what controls first-match. Drag-and-drop in GUI or move in CLI to change order.
The invisible last rule: policy 0 — deny all, log violation. Anything not explicitly allowed dies here. Always-on, can't be deleted.
IPS / AV / WebFilter / AppCtrl run after the policy allows. A "deny" policy never reaches UTM. So Web Filter blocks are still policy decisions.
The top-down match — see it as a flow
The Tuesday ticket Sneha got isn't unique. Every shift, an L1 confuses specificity with position. Here's the same scenario as a flow you can step through.
Before you scroll — if Sneha drags Policy 12 (the specific deny) above Policy 7 (the broad allow), what's the order of evaluation, and what gets allowed?
10.20.1.50 hitting 8.8.8.8: Policy 12 matches → DENY. For source 10.20.1.51 (different host) hitting anything: Policy 12 does NOT match (wrong src), falls through to Policy 7 → ALLOW. The specific deny is now exception-shaped — exactly what most admins want.
Aman at an Indian IT services firm Pune sees Policy ID 22 (deny tcp/22 to 172.16.5.10) NOT working — admins can still SSH. The policy LIST shows Policy 22 below an "allow internal-net to any" Policy ID 5. Why?
config firewall policy → move 22 before 5). Lower policy ID does NOT mean higher priority — it's just an auto-numbered handle.Central NAT vs per-policy NAT — the silent override
FortiGate gives you two NAT modes. They're mutually exclusive at the VDOM level — the second you enable Central NAT, every per-policy NAT setting you carefully tuned is silently bypassed. This is one of the top three Fortinet interview traps.
Per-policy NAT is what every new FortiGate ships with. Each IP Pool binds inside a single policy via the nat toggle and the ippool reference. Visible, scoped, easy to audit.
Central NAT moves NAT into a separate dedicated policy table (Policy & Objects → Central SNAT). Per-policy nat toggles still appear in the GUI but are ignored — Central NAT decides everything. New admins miss this and lose hours.
You enable Central NAT for a one-off project. Three months later, a new admin opens a per-policy NAT toggle, sees it's ON, and assumes per-policy NAT is happening. It isn't. Central NAT silently owns the translation. The clue? config system settings → get | grep central-nat. Read it before every NAT debug.
Pooja at an Indian enterprise Noida inherits a FortiGate. Policy 14 has NAT toggle ON and references IP-Pool pool-A. But traffic egresses with the firewall's interface IP, not pool-A's range. What's the most likely cause?
config system settings → set central-nat enable) silently overrides per-policy NAT. Per-policy toggles still show in the GUI but are ignored. Either disable Central NAT and use per-policy, or move the NAT entry into Central SNAT. Option d is wrong — exhausted IP Pool drops sessions, doesn't silently fail over.VIPs and IP Pools — what each one actually does
Two NAT building blocks confuse interview candidates more than anything else:
- VIP — Virtual IP. Inbound DNAT. You publish
10.30.5.100:443(DMZ web server) on203.0.113.10:443(public). External clients hit the public IP; FortiGate rewrites the destination. - IP Pool — Outbound SNAT. Internal hosts share one or many public IPs going out. Overload mode (default) does PAT; fixed-port preserves the source port for picky protocols.
Real config — publishing a DMZ web server
Karan at an Indian IT services firm Pune publishes 10.30.5.100 (Apache on the DMZ) on public IP 203.0.113.10. The full FortiOS config:
config firewall vip
edit "vip-webapp-public"
set extip 203.0.113.10
set mappedip "10.30.5.100"
set extintf "wan1"
set portforward enable
set protocol tcp
set extport 443
set mappedport 443
next
end
config firewall policy
edit 0
set name "Inbound-Webapp-DMZ"
set srcintf "wan1"
set dstintf "dmz"
set srcaddr "all"
set dstaddr "vip-webapp-public"
set service "HTTPS"
set action accept
set schedule "always"
set logtraffic all
next
end
config firewall policy
edit 21
set name "Inbound-Webapp-DMZ"
set srcintf "wan1"
set dstintf "dmz"
set srcaddr "all"
set dstaddr "vip-webapp-public"
set service "HTTPS"
set action accept
set schedule "always"
set logtraffic all
next
end
In the security policy, dstaddr is the VIP object (vip-webapp-public) — NOT the internal IP 10.30.5.100, and NOT the public IP 203.0.113.10. FortiGate auto-resolves the VIP to the right side at policy match time. Mess this up and the rule never fires. This is THE classic VIP interview question.
▶ Watch a packet walk the policy engine — Outbound SNAT
Sneha's session — full 6-stage journey from her laptop at a Bangalore fintech to 8.8.8.8.
port5 (zone: internal-lan)10.20.1.0/24 → any, action accept) wins
nat enable + ippool overload-pool-wan1 → translate source
203.0.113.5.
Two hours later, Sneha gets another ticket — the webapp on 203.0.113.10 is "not reachable from the internet." She checks the VIP object — looks fine. She checks the policy — source all, dest is the VIP object, service HTTPS, action accept. Still nothing.
One thing she missed: the policy's dstintf was set to wan1 (the public-facing interface). For an inbound VIP, the destination interface is the internal zone where the real server lives (dmz). FortiGate resolved the VIP, but no policy from wan1 → dmz referenced it. She flips dstintf to dmz. Webapp loads. 4-hour ticket closed in 7 minutes.
If two VIP objects map the SAME public IP+port to two different internal servers and both are referenced by different policies — which one wins?
▶ The "first-match wins" drama — two overlapping policies
Same packet, but Policy 12 (specific deny) is below Policy 7 (broad allow). Watch what happens.
Anil at an Indian MSP Mumbai wants to publish two internal apps (App-A on 10.30.5.10, App-B on 10.30.5.20) on a single public IP 203.0.113.10 using port-based DNAT. App-A on :443, App-B on :8443. Best FortiGate approach?
portforward enable, each mapping a different external port to a different internal host. FortiGate matches the destination port to pick the right VIP. IP Pools are SNAT not DNAT — wrong tool. Single VIP without port-forwarding can only do 1:1 IP mapping, not port-based fan-out.Debug like an L3 — settle every NAT argument in 60 seconds
Vikram, an L3 at an Indian security firm, doesn't argue about policies. He runs one command. You should too.
diagnose firewall iprope lookup 10.20.1.50 8.8.8.8 80
vd: root/0
iprope_lookup_check_ctx flag(0,0,0,0) tablecnt=14
gnum 100004 flag 0x2 prio 0
iprope_lookup_pol_in_check, prio 0
gnum 100004 (firewall policy)
policy id 7 - matched
src: 10.20.1.0/24
dst: 0.0.0.0/0
action: 1 (accept)
nat: 1
One command tells you which policy ID matched, whether NAT applied, and the action taken. No tcpdump. No guessing. No "let me check with the network team."
After any policy change, run:
diagnose firewall iprope lookup 10.20.1.50 8.8.8.8 80
Expected: policy id 7 - matched with action: 1 (accept). If you get action: 0 (deny) or policy id 0, the implicit deny fired — your rule didn't match.
The implicit-deny trap that costs interviews
Most candidates know "there's a deny at the end." Few can explain that it logs. The implicit deny at policy 0 drops the packet, AND when you enable set logtraffic all on the implicit-deny entry (config firewall policy → edit 0 → set logtraffic all), every dropped session shows up in forward traffic logs as policyid=0 with action deny. That's how Vikram's L3 team spots reconnaissance — a flood of policyid=0 entries from one source IP means someone is sweeping.
When you write a runbook, document policies by sequence position (or by name) NOT by policy ID. IDs are stable across reorders, but they're meaningless to readers. "Policy at sequence 3 — Allow-Internal-DNS" tells the reader where to look. "Policy ID 47" does not.
In late 2024, Mandiant traced UAG UNC5820 exploiting a missing-authentication flaw in FortiManager's fgfmsd daemon (CVE-2024-47575, CVSS 9.8). Attackers compromised the FortiManager, then pushed rogue firewall policies to managed FortiGates — typically broad "any-any-allow" internal rules — as their lateral-movement pivot. ~50+ FMG devices found compromised globally.
Defensive lesson for this blog: "any-any-allow" internal policies aren't just bad hygiene — they're the literal IOC for this campaign. Audit every internal policy for srcaddr=all + dstaddr=all + action=accept on east-west zones. Replace with explicit zone-to-zone rules. Source: Tenable PSIRT advisory.
Riya runs diag firewall iprope lookup 10.20.1.50 1.1.1.1 53 and the output shows policy id 0 - matched · action: deny. The user reports DNS not working. What's the next single command Riya should run?
diagnose debug flow filter saddr 10.20.1.50 followed by diagnose debug flow trace start 5 + diagnose debug enable. That tells her WHY no allow policy matched — wrong src interface, missing service, wrong schedule, etc. The iprope lookup confirmed "no rule allowed it"; the debug flow tells her which field of which rule was the mismatch. Top L3 muscle memory.
🤖 Ask the AI Tutor
Tap any question — instant context-aware answer. Tuned on FortiOS 7.4 / 7.6 docs + community.
Pre-curated answers grounded in FortiOS 7.4 / 7.6 docs + LIVECommunity. For complex prod issues, paste your diag firewall iprope lookup + show firewall policy output into chat.techclick.in.
📝 Final round — seven more
You've already answered 3 inline. Seven more. 70% (7 of 10) total marks this lesson complete on your Techclick profile. Tap Submit all answers at the end.
Self-explanation prompt
In 2-3 sentences, explain to a hypothetical batchmate: "Why doesn't a more specific deny policy win against a broader allow above it in FortiGate?" Writing it out cements the concept faster than re-reading.
📖 Mini-glossary — terms used in this blog
- FortiGate
- Fortinet's flagship NGFW running FortiOS.
- Policy lookup
- Top-down scan of the policy list to find the first matching rule.
- Implicit deny
- The invisible policy 0 that drops anything not explicitly allowed.
- VIP (Virtual IP)
- FortiOS DNAT object — maps external IP:port → internal IP:port.
- IP Pool
- Set of public IPs used for outbound SNAT. Modes: overload, fixed-port, etc.
- SNAT
- Source NAT — translates source IP/port (outbound, sharing public IPs).
- DNAT
- Destination NAT — translates destination IP/port (publishing internal servers).
- Central NAT
- Alternative NAT model — one global SNAT table, overrides per-policy NAT.
- FGCP
- FortiGate Clustering Protocol — the HA protocol covered in Blog 3.
- NPU
- Network Processor Unit — ASIC that offloads established sessions for wire-speed.
- VDOM
- Virtual Domain — FortiGate's logical multi-tenancy split.
diag firewall iprope lookup command and the CVE-2024-47575 awareness check.
What's next?
Blog 2 opens up FortiGate VPNs — IPsec Phase 1 / Phase 2, SSL VPN, and how to harden them against the CVE-2024-21762 + CVE-2024-55591 exploitation wave still active across 2025.
📚 Sources
- Fortinet Docs — Firewall Policy (FortiOS 7.4 / 7.6 Administration Guide). docs.fortinet.com
- Fortinet Docs — Central SNAT and Central NAT. docs.fortinet.com (FortiOS 7.6)
- Fortinet Docs — VIPs and IP Pools — Configuration and Use Cases. docs.fortinet.com
- NWKings — Top 20 Fortinet Firewall Interview Questions and Answers (2025). nwkings.com/fortinet-firewall-interview-questions-and-answers
- UniNets — Top Fortinet Firewall Interview Q&A 2025. uninets.com/blog/fortinet-firewall-interview-questions-answers
- MindMajix — Top Fortinet Interview Q&A 2025. mindmajix.com/fortinet-interview-questions
- Tenable Blog — CVE-2024-47575 FAQ: FortiJump Zero-Day in FortiManager. tenable.com/blog/cve-2024-47575-faq-about-fortijump-zero-day-in-fortimanager
- GitHub yuriskinfo — FortiGate debug-diagnose complete cheat sheet. github.com/yuriskinfo/cheat-sheets
- Fortinet Community — Troubleshooting Tip: Using the FortiOS built-in packet sniffer. community.fortinet.com