On the FortiGate firewall, address objects and virtual IPs (VIPs) can be set up with an interface. For address objects this has no technical relevance – the address objects simply only appear on policies if the appropriate interface is selected. But for virtual IPs, this setting has relevance on how connections are NATed. This can be problematic.
In common situations, you have only one ISP connection on which you want to set up a destination NAT (DNAT) for incoming connections. No problem there. You can select the untrust interface in the virtual IP object. If you have two ISP connections, e.g., a good one (ISP1) and a cheap one (ISP2), you MUST select the interface in the virtual IP object if it references a static IP address of ISP1. Otherwise it will be used on all outgoing connections which won’t work with ISP2.
The following example shows a virtual IP object with a static IP address of 18.104.22.168 and a misconfigured interface of “Any”. Using outgoing connections to ISP1, there are no problems (label 1 on the screenshot). But after setting up a policy route to route http traffic to ISP2, the same source NAT IP will be used which obviously didn’t work (label 2). After setting the interface to “wan1” in the virtual IP object, outgoing connections to ISP2 are correctly NATed to the outgoing interface address while outgoing connections to ISP1 are still NATed to the virtual IP (label 3). Tested with a FortiGate 100D with software version v5.2.5, build701.
However, one problem remains unsolved: If you have more than one interface on which the virtual IP must be used (e.g., for ISP1 and for a site-to-site VPN connection that also talks to the NATed IP), while some connections are policy routed to ISP2.
In this situation, you MUST set the interface inside the virtual IP to “Any”, which will not work with ISP2. One idea might be to to configure several virtual IPs with the same external/mapped IPs with different interfaces, but this is not possible to configuration restrictions. :( In this case, some more security policy entries with IP pools can be used to solve the problem.
(By the way: A problem we won’t have with IPv6 anymore.)