<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nizar Tuanku</title>
    <description>The latest articles on DEV Community by Nizar Tuanku (@nizar_tuanku).</description>
    <link>https://dev.to/nizar_tuanku</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4136545%2F98288248-750d-4a92-8010-05cddd5e50df.png</url>
      <title>DEV Community: Nizar Tuanku</title>
      <link>https://dev.to/nizar_tuanku</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nizar_tuanku"/>
    <language>en</language>
    <item>
      <title>Why firewall migrations frighten the people who have done one</title>
      <dc:creator>Nizar Tuanku</dc:creator>
      <pubDate>Tue, 29 Sep 2026 13:18:11 +0000</pubDate>
      <link>https://dev.to/hexwardlabs/why-firewall-migrations-frighten-the-people-who-have-done-one-33m5</link>
      <guid>https://dev.to/hexwardlabs/why-firewall-migrations-frighten-the-people-who-have-done-one-33m5</guid>
      <description>&lt;h2&gt;
  
  
  Why firewall migrations frighten the people who have done one
&lt;/h2&gt;

&lt;p&gt;Companies replace firewalls for ordinary reasons: the hardware reaches end of support, the vendor changes, a contract ends. Management takes the decision in a single meeting.&lt;br&gt;
What does not come up in that meeting: the old firewall carries a rule base — the list of rules about who may talk to whom — written by seven different people over nine years. Most of the authors no longer work there. Nobody knows exactly why rule number 43 exists.&lt;/p&gt;

&lt;p&gt;Moving it to a new device is not copying a file. Every vendor has its own shape for concepts that are the same in principle, and some concepts on one vendor have no equivalent on another.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why the vendor's own tool is not enough
&lt;/h2&gt;

&lt;p&gt;Every vendor ships a migration tool, and all of them run one way — into their own product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cisco FMT only converts into FTD&lt;/li&gt;
&lt;li&gt;FortiConverter only into FortiGate&lt;/li&gt;
&lt;li&gt;SmartMove only into Check Point&lt;/li&gt;
&lt;li&gt;Palo Alto Expedition was discontinued in January 2025
That makes sense from their side of the business: the tool exists to help you in, not to help you go anywhere.
The problem appears when you need a direction no vendor wants — FortiGate to Palo Alto, say, or checking whether a move from ASA to Check Point makes sense before you commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The part people most often misunderstand
&lt;/h2&gt;

&lt;p&gt;Conversion tools are usually judged by what percentage succeeded. That number sounds reassuring and is almost useless.&lt;br&gt;
Take one real job we measured — Cisco ASA to Palo Alto PAN-OS:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;Rules&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Converted successfully&lt;/td&gt;
&lt;td&gt;130&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partially converted&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needs a human decision&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What decides whether cut-over night succeeds or fails is not the 130 that worked. It is the 10.&lt;br&gt;
Those ten items are the things with no automatic equivalent: features the target device does not have, rules that depend on the old vendor's specific behaviour, constructs that could be translated two different ways where only a human knows which is right.&lt;br&gt;
A tool that hides those ten items is not helping you — it is postponing the problem until 2am.&lt;br&gt;
RuleForge writes them down as a list, with the reason for each. That list is what people actually use during a migration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why the config must never be uploaded anywhere
&lt;/h2&gt;

&lt;p&gt;A firewall config is a map of your network. It contains internal addresses, segment names, which services may be reached from where. Whoever holds it does not need to guess anything about your network.&lt;br&gt;
Many web-based conversion tools ask you to upload it.&lt;br&gt;
RuleForge is a single binary that runs on your laptop or a jump host, with no outbound connection at all. Not because we deserve more trust — but because uploading it should never have been part of this job.&lt;/p&gt;
&lt;h2&gt;
  
  
  One limit we put up front — and what fixing it uncovered
&lt;/h2&gt;

&lt;p&gt;RuleForge has a feature called round-trip verification: the generated config is read back by its own parser and compared against the internal model.&lt;/p&gt;

&lt;p&gt;For its first releases, that comparison only counted things — the number of interfaces, the number of rules. An interface address 198.51.100.2/28 that became 198.51.100.0/28 slipped straight past it, because the number of interfaces was still right.&lt;br&gt;
On 5 September the review was rebuilt to compare values: interface addresses, routes, object contents. And the very first time it ran with values, it caught two more defects that had already shipped — the generators for two vendors were writing network addresses where interface addresses belonged, and a stray comment line was landing inside a block where the firewall would have silently dropped everything after it. Both are fixed, both have tests.&lt;br&gt;
We tell you this because it is the whole argument for the product: a check that only counts cannot see the mistakes that matter. And we tell you what is still excluded, on purpose — rule bodies and NAT, whose names and ordering are legitimately rewritten during conversion. For those, the Conversion Process Report stays your source of truth.&lt;/p&gt;
&lt;h2&gt;
  
  
  What changes once you are using it
&lt;/h2&gt;

&lt;p&gt;Before: a migration begins by copying thousands of lines into a spreadsheet, then hoping nothing was missed.&lt;br&gt;
After: you have a target config, two documents, and a short list of things you must decide yourself — before cut-over night, not during it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Optional: AI-narrated explanations
&lt;/h2&gt;

&lt;p&gt;Since v0.1.4, RuleForge can explain a conversion issue in plain language with a small language model that runs on your own hardware. It is off by default. Turn it on by starting a hexward-ai sidecar (github.com/nizartuanku/hexward-ai) and pointing RuleForge at it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ruleforge &lt;span class="nt"&gt;-ai-assist-url&lt;/span&gt; http://127.0.0.1:8435
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each partial, manual-review, failed or info item in the per-item outcomes then gets an &lt;strong&gt;Explain&lt;/strong&gt; button. The model writes what the outcome means for the migration and what to verify before you act. It also gets a fixed disclaimer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The converter still decides.&lt;/strong&gt; The model receives one per-item outcome after RuleForge's generator has produced it. It cannot add, remove, re-score or resolve an item, and it is never asked to write target configuration - the button explains, the download is the converter's. If the sidecar is off, slow or broken, the button shows a short note and nothing else changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What leaves the process.&lt;/strong&gt; One item: its outcome, RuleForge's own message for it, a short identifier, the source and target vendor, the context name, the item's position and RuleForge's own next-step text. The uploaded configuration, the generated output, rule bodies, pre-shared keys and passwords are never sent. Nothing goes to the internet. The sidecar runs where you run it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editions.&lt;/strong&gt; The free edition works with a sidecar on the same host - that is the &lt;code&gt;lab&lt;/code&gt; profile, SmolLM3-3B. Pro and Team can also use one dedicated AI host for several products, or your own OpenAI-compatible endpoint. Enterprise uses Qwen3 or your own endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language.&lt;/strong&gt; English is the supported language in this release.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest limit.&lt;/strong&gt; Small local models sometimes add general background that is not in the evidence, and that background can be wrong. Treat the explanation as a starting point: the per-item outcome, the process report and the generated files remain the record, which is why every explanation carries the "verify against raw findings" line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed.&lt;/strong&gt; On a CPU-only machine an explanation takes about 15-50 seconds, depending on the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Look at the output first — without installing anything
&lt;/h2&gt;

&lt;p&gt;Two complete sample reports are at github.com/nizartuanku/ruleforge/docs/samples, public, no email gate.&lt;br&gt;
If after that you want to try it on your own config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/nizartuanku/ruleforge/releases/latest/download/ruleforge-free-0.1.4-linux-amd64.tar.gz
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/nizartuanku/ruleforge/releases/latest/download/SHA256SUMS
&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; SHA256SUMS
&lt;span class="nb"&gt;tar &lt;/span&gt;xzf ruleforge-free-0.1.4-linux-amd64.tar.gz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./ruleforge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The free Apache-2.0 edition runs the same engine, up to 150 rules per job — enough to watch the manual-review register appear on your own config, not on an example we made up.&lt;br&gt;
Run it on a config you have sanitised.&lt;br&gt;
Nizar Tuanku — Cybersecurity Tools + AI. · github.com/nizartuanku/ruleforge&lt;/p&gt;

&lt;h2&gt;
  
  
  Terms used above
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rule base — the set of firewall rules, read from top to bottom. The first rule that matches a packet decides that packet's fate.&lt;/li&gt;
&lt;li&gt;Round-trip verification — the conversion output is re-parsed and compared with the source, to make sure nothing fell through.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is the &lt;code&gt;docs/CONCEPTS.md&lt;/code&gt; of &lt;strong&gt;ruleforge&lt;/strong&gt;, one of the Hexward self-hosted security tools. The free edition is on GitHub under Apache-2.0 with no time limit: &lt;a href="https://github.com/nizartuanku/ruleforge" rel="noopener noreferrer"&gt;https://github.com/nizartuanku/ruleforge&lt;/a&gt; — the README has the install block, and the concepts above are the reasoning behind it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Nizar Tuanku — Cybersecurity Tools + AI.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>security</category>
      <category>firewall</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Your attack surface is whatever the internet remembers — and it remembers more than you do</title>
      <dc:creator>Nizar Tuanku</dc:creator>
      <pubDate>Tue, 22 Sep 2026 03:22:04 +0000</pubDate>
      <link>https://dev.to/hexwardlabs/your-attack-surface-is-whatever-the-internet-remembers-and-it-remembers-more-than-you-do-1p08</link>
      <guid>https://dev.to/hexwardlabs/your-attack-surface-is-whatever-the-internet-remembers-and-it-remembers-more-than-you-do-1p08</guid>
      <description>&lt;h2&gt;
  
  
  The problem starts with something perfectly reasonable
&lt;/h2&gt;

&lt;p&gt;Someone spins up staging.company.com for a client demo. The demo goes well, the client is happy, everyone moves on to the next thing.&lt;br&gt;
That server is still running. It is still running the version of the application from eight months ago. Its admin panel still has the password someone picked in a hurry. And nobody in the company remembers it exists.&lt;br&gt;
No one was careless. This is how organisations normally work: things built to be temporary are rarely switched off, because switching them off was never anyone's job.&lt;br&gt;
Everything like that — exposed to the internet, reachable by outsiders — is what people mean by your attack surface.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why an attacker finds it before you do
&lt;/h2&gt;

&lt;p&gt;There is a difference in point of view that decides everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You see your infrastructure from the inside — from a server list, from documentation, from memory.&lt;/li&gt;
&lt;li&gt;An attacker sees it from the outside, and carries no assumptions about what is supposed to be there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are not looking for your important servers. They scan the whole internet, note what answers, and look for the weakest thing. That forgotten staging box is the ideal target precisely because it is real, connected to the same network, and watched by no one.&lt;/p&gt;
&lt;h2&gt;
  
  
  How forgotten assets can be found without guessing
&lt;/h2&gt;

&lt;p&gt;Here is where one little-known detail becomes decisive.&lt;br&gt;
Every time a site is issued an HTTPS certificate, the issuer is required to record it in a Certificate Transparency log — a public ledger anyone can read. The rule exists for a good reason: if someone issues a fraudulent certificate for your domain, the evidence is visible.&lt;/p&gt;

&lt;p&gt;The side effect: a company's list of subdomain names is often already public, with no guessing required. staging., vpn-old., backup., test2. — if it ever had a certificate, the name is in there.&lt;br&gt;
ASM reads that list, then checks which of those names are still actually alive. Anything that does not resolve is discarded. What remains is your real attack surface.&lt;/p&gt;
&lt;h2&gt;
  
  
  What gets checked once an asset is found
&lt;/h2&gt;

&lt;p&gt;On assets you have proven you own, ASM checks the things that most often turn out to be real ways in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases reachable from the internet. PostgreSQL, MySQL, MongoDB, Redis. A database should only be reachable by your application, not by anyone on the internet. This shows up far more often than people expect — usually because of one firewall rule added for debugging and never removed.&lt;/li&gt;
&lt;li&gt;Open remote access. RDP, VNC or Telnet facing the internet is a standing invitation to try passwords over and over.&lt;/li&gt;
&lt;li&gt;Every other open port, so you know what is actually answering.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The part that makes it useful every day: what changed
&lt;/h2&gt;

&lt;p&gt;Scanning once produces a long list that makes people give up.&lt;br&gt;
What is genuinely useful is the difference from yesterday:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new subdomain appears → a new finding&lt;/li&gt;
&lt;li&gt;A port that used to be closed is now open → a new finding&lt;/li&gt;
&lt;li&gt;A port you closed → the finding disappears on its own&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So after the first day you are no longer looking at a long list, but at a short list of things that changed. That is something a real person can work through each morning.&lt;/p&gt;
&lt;h2&gt;
  
  
  One limit you should know before you judge the results
&lt;/h2&gt;

&lt;p&gt;When we ran ASM against our own domain, hexwardlabs.com, it returned one asset — even though bridge.hexwardlabs.com is plainly alive and reachable by anyone.&lt;br&gt;
Why? Because that domain uses a wildcard certificate — a single *.hexwardlabs.com certificate covering every subdomain at once.&lt;/p&gt;

&lt;p&gt;So there was nothing to find from that source, and ASM does not guess names.&lt;br&gt;
We put this up front rather than hiding it, because if you run it against a wildcard domain and see a small number, you deserve to know why. A small number on a domain like that is not evidence that your surface is small.&lt;br&gt;
Since 5 September, ASM tells you this itself: when it detects a wildcard certificate it raises a coverage note before showing the inventory, so the report admits its own blind spot instead of letting a low number speak for itself. That note is filed as informational, not as a problem with your setup — owning a wildcard certificate is perfectly sensible. The limitation is ours, and it would be wrong to score you for it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why ASM refuses to scan until you prove ownership
&lt;/h2&gt;

&lt;p&gt;Before it scans anything, ASM asks for proof that the domain is yours — via a single DNS TXT record, or a file on that server.&lt;br&gt;
This is not a formality. Port-scanning someone else's systems without permission is a legal problem in many countries, and a tool that scans whatever its user types in is a tool that sooner or later gets used for exactly that.&lt;br&gt;
The boundary is permanent and cannot be switched off.&lt;/p&gt;
&lt;h2&gt;
  
  
  What changes once you are using it
&lt;/h2&gt;

&lt;p&gt;Before: you have a list of the servers you remember, and you hope it is complete.&lt;br&gt;
After: you have a list of what is provably alive and visible from outside, plus a notice every time something is added to it.&lt;br&gt;
That sounds like a small change, right up until the day the thing that was added is not something you built.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it yourself — 15 minutes
&lt;/h2&gt;

&lt;p&gt;The free Apache-2.0 edition on GitHub runs the same engine, one domain, with no time limit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/nizartuanku/attack-surface-monitor/releases/latest/download/asm-free-0.1.1-linux-amd64.tar.gz
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/nizartuanku/attack-surface-monitor/releases/latest/download/SHA256SUMS
&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; SHA256SUMS
&lt;span class="nb"&gt;tar &lt;/span&gt;xzf asm-free-0.1.1-linux-amd64.tar.gz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./asm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open 127.0.0.1:8423, enter one domain you own, publish its verification TXT record, and see what comes back.&lt;br&gt;
If what comes back surprises you — that is rather the point.&lt;br&gt;
Nizar Tuanku — Cybersecurity. · github.com/nizartuanku/attack-surface-monitor&lt;/p&gt;

&lt;h2&gt;
  
  
  Terms used above
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Certificate Transparency (CT) — a public list of every HTTPS certificate ever issued. Readable by anyone, including you, and including an attacker.&lt;/li&gt;
&lt;li&gt;Wildcard certificate — one certificate for all subdomains. Convenient for the administrator, but it means no individual subdomain name has ever appeared in a CT log.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is the &lt;code&gt;docs/CONCEPTS.md&lt;/code&gt; of &lt;strong&gt;attack-surface-monitor&lt;/strong&gt;, one of the Hexward self-hosted security tools. The free edition is on GitHub under Apache-2.0 with no time limit: &lt;a href="https://github.com/nizartuanku/attack-surface-monitor" rel="noopener noreferrer"&gt;https://github.com/nizartuanku/attack-surface-monitor&lt;/a&gt; — the README has the install block, and the concepts above are the reasoning behind it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Nizar Tuanku — Cybersecurity.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>networking</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Central NAT on FortiGate: what changes, what breaks, and the order you have to do it in</title>
      <dc:creator>Nizar Tuanku</dc:creator>
      <pubDate>Mon, 21 Sep 2026 23:45:08 +0000</pubDate>
      <link>https://dev.to/hexwardlabs/central-nat-on-fortigate-what-changes-what-breaks-and-the-order-you-have-to-do-it-in-42nf</link>
      <guid>https://dev.to/hexwardlabs/central-nat-on-fortigate-what-changes-what-breaks-and-the-order-you-have-to-do-it-in-42nf</guid>
      <description>&lt;p&gt;&lt;em&gt;First note in a series on cross-vendor firewall migration: where two platforms disagree, verified against vendor docs and real migrations.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are moving a policy set onto FortiGate from an ASA or a Palo Alto, there is a decision you have to make before you write a single rule, and FortiOS will not let you unmake it afterwards without tearing the policies down.&lt;/p&gt;

&lt;p&gt;This is about central NAT. Not what it is — the documentation covers that — but what it does to a migration, and why it has to be the first thing you decide rather than the last.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why migrations run into this at all
&lt;/h2&gt;

&lt;p&gt;Per-policy NAT is the FortiGate default, and for a greenfield FortiGate it is usually the right choice. Each firewall policy carries its own &lt;code&gt;nat enable&lt;/code&gt; and optionally an IP pool. Simple, local, readable.&lt;/p&gt;

&lt;p&gt;The trouble is that neither an ASA nor a PAN-OS policy set is shaped that way.&lt;/p&gt;

&lt;p&gt;On an ASA, NAT lives in its own ordered table — object NAT and twice NAT, evaluated in sections, entirely separate from the ACLs. On PAN-OS, NAT rules are their own rulebase, also separate from security rules. In both, one NAT rule serves many policy rules.&lt;/p&gt;

&lt;p&gt;Per-policy NAT has no way to express that. If a single ASA twice-NAT statement covers traffic matched by fourteen ACEs, per-policy NAT makes you write the translation fourteen times, once on each converted policy. It works, and it is a maintenance problem the day you have to change it.&lt;/p&gt;

&lt;p&gt;Central NAT restores the shape you came from: one ordered SNAT table, one DNAT table, and firewall policies that only decide allow or deny. That is why converted configurations tend to land in central NAT, and why anyone doing this by hand usually ends up there too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The order problem — read this one first
&lt;/h2&gt;

&lt;p&gt;You cannot switch to central NAT on a FortiGate that already has policies referencing VIPs or IP pools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cisco_ios"&gt;&lt;code&gt;&lt;span class="k"&gt;FGT&lt;/span&gt; # config sys settings
&lt;span class="k"&gt;FGT&lt;/span&gt; (settings) # set central-nat enable
&lt;span class="k"&gt;Cannot&lt;/span&gt; enable central-nat with firewall policy using vip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is an equivalent error for IP pools, and it names the policy ID. Every VIP and every IP pool has to reach zero references before the toggle will take. Not deleted necessarily — dereferenced — but on a freshly built policy set that usually amounts to the same thing.&lt;/p&gt;

&lt;p&gt;So the failure mode is this. You spend two days building out interfaces, zones, address objects, service objects and four hundred policies. You get to NAT, decide central NAT is the right model, and FortiOS refuses. Now you are editing four hundred policies to strip VIP references before you can enable the mode you should have enabled on an empty box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decide central NAT before you build the policy set.&lt;/strong&gt; On a new appliance the sequence is: enable central NAT, log out and back in so the GUI redraws, then build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What flips underneath you: the destination address
&lt;/h2&gt;

&lt;p&gt;This is the one that costs a cut-over window, because it fails in a direction that looks like a routing problem.&lt;/p&gt;

&lt;p&gt;With per-policy NAT, an inbound policy references the &lt;strong&gt;VIP object&lt;/strong&gt; as its destination address. That is the familiar pattern and it matches how an ASA or PAN-OS engineer thinks: the rule talks about the public address.&lt;/p&gt;

&lt;p&gt;With central NAT enabled, that is wrong. The DNAT and Virtual IPs table applies to every policy on the FortiGate, whether or not the policy mentions a VIP. Destination translation has already happened by the time the policy is evaluated. So the policy must reference the VIP's &lt;strong&gt;mapped address&lt;/strong&gt; — the internal one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Policy destination address&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FortiGate, per-policy NAT&lt;/td&gt;
&lt;td&gt;the VIP object (public address)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FortiGate, central NAT&lt;/td&gt;
&lt;td&gt;the mapped address (internal address)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cisco ASA&lt;/td&gt;
&lt;td&gt;real address, post-8.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PAN-OS security rule&lt;/td&gt;
&lt;td&gt;pre-NAT address, post-NAT zone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Four platforms, and the answer is different on each. PAN-OS is the cruellest of them — pre-NAT address but post-NAT zone in the same rule — and if you have spent years there, "destination is the public IP" is muscle memory. On a central-NAT FortiGate that muscle memory silently denies every inbound session.&lt;/p&gt;

&lt;p&gt;Worth saying plainly: under central NAT, &lt;strong&gt;all VIP/DNAT rules are in effect regardless of the central SNAT table&lt;/strong&gt;. The two tables are independent. A VIP you created and forgot about is live the moment central NAT is on, with no policy referencing it anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Central SNAT is first-match, and your old order does not carry over
&lt;/h2&gt;

&lt;p&gt;The central SNAT table is read top down and the first match wins. Same as an ACL, same as an ASA NAT section — but the &lt;em&gt;match keys&lt;/em&gt; are not the same, and that is where converted tables go wrong.&lt;/p&gt;

&lt;p&gt;A central SNAT entry matches on source interface, destination interface, source address, destination address, protocol, destination port and original source port. An ASA NAT rule has no concept of destination interface as a match key in the same way, and section ordering in ASA (manual NAT before auto NAT before after-auto NAT) does not map onto a single flat list.&lt;/p&gt;

&lt;p&gt;The practical consequence: an ASA NAT table that was correct in its own ordering can be flattened into a central SNAT table that is also individually correct rule by rule, and still behave differently, because the first-match boundary now falls somewhere else.&lt;/p&gt;

&lt;p&gt;The specific thing to check is your catch-all. Most estates end with a broad "everything out to the internet, hide behind the interface address" rule. If a narrower rule that used to be evaluated in an earlier ASA section ends up &lt;em&gt;below&lt;/em&gt; that catch-all in the flat table, it never matches, and the traffic silently leaves with the wrong source address. Nothing breaks. Nothing logs an error. A far-end ACL somewhere starts dropping you a week later.&lt;/p&gt;

&lt;p&gt;Read the table bottom-up looking for anything below your broadest rule. That is a five-minute check and it is the highest-yield five minutes in the whole exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicit port mapping and the ICMP trap
&lt;/h2&gt;

&lt;p&gt;Central SNAT lets you pin an original source port range to a translated port range — &lt;code&gt;set orig-port&lt;/code&gt; and &lt;code&gt;set nat-port&lt;/code&gt;. Two constraints come with it:&lt;/p&gt;

&lt;p&gt;Only the &lt;strong&gt;Overload&lt;/strong&gt; IP pool type supports it. And any protocol without ports — ICMP first among them — &lt;strong&gt;cannot match a rule that uses explicit port mapping&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So the rule you wrote to pin a port range for one application quietly does not apply to ping, traceroute or path-MTU discovery from the same hosts. That traffic falls through to whatever rule comes next, which is usually the interface-address catch-all, which is usually a different source address.&lt;/p&gt;

&lt;p&gt;You will find this the first time someone asks why the monitoring system sees a different source IP for ICMP than for TCP from the same server. Better to know before they ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two more that catch people
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NGFW policy-based mode implies central NAT.&lt;/strong&gt; If the VDOM is in policy-based NGFW mode, central SNAT is on implicitly. You do not get to choose. If you are converting into a policy-based VDOM, you are in central NAT whether you planned for it or not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With VDOMs, the SNAT and DNAT tables are per-VDOM, not global.&lt;/strong&gt; Obvious once said, easy to assume otherwise when you are consolidating several ASA contexts into VDOMs on one chassis and thinking of the NAT table as a property of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-cut-over checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Central NAT decided and enabled &lt;strong&gt;before&lt;/strong&gt; the policy set is built, on an empty box&lt;/li&gt;
&lt;li&gt;Logged out and back in so the GUI shows the Central SNAT and DNAT tables&lt;/li&gt;
&lt;li&gt;Every inbound policy references the &lt;strong&gt;mapped&lt;/strong&gt; address, not the VIP object&lt;/li&gt;
&lt;li&gt;VIP table audited — under central NAT everything in it is live, referenced or not&lt;/li&gt;
&lt;li&gt;Central SNAT table read bottom-up: nothing meaningful sits below the broad catch-all&lt;/li&gt;
&lt;li&gt;Any rule with explicit port mapping checked against the ICMP behaviour above, and the fall-through rule confirmed to be acceptable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;diagnose sys session list&lt;/code&gt; on real traffic before you call it done — the &lt;code&gt;hook=post dir=org act=snat&lt;/code&gt; line tells you the actual translated address, which is the only answer that counts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last one is worth more than any amount of reading the config. The session table does not have opinions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I cannot check for you
&lt;/h2&gt;

&lt;p&gt;Everything above is behaviour I have hit on real migrations and then confirmed against the FortiOS documentation. What I cannot tell you is which of it applies to your build — central NAT behaviour has moved between major versions, and the version you are landing on matters.&lt;/p&gt;

&lt;p&gt;Verify against your own lab before your change window. The cost of being wrong here is not a config error, it is a cut-over that half works.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by someone who does firewall migrations for a living, after doing this one the hard way. Corrections welcome — if your experience differs on any of the above, I would rather hear it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; FortiOS 7.4.3 Administration Guide, &lt;em&gt;Central SNAT&lt;/em&gt; · Fortinet community article 181805, &lt;em&gt;cannot enable central-nat error&lt;/em&gt; · Fortinet community article 97658, &lt;em&gt;Configuration changes regarding Central NAT and Virtual IPs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;More notes like this, as they get written: &lt;a href="https://github.com/nizartuanku/firewall-migration-notes" rel="noopener noreferrer"&gt;github.com/nizartuanku/firewall-migration-notes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>security</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
