VPNs to Google Cloud Platform (GCP) when FortiGate is behind a NAT gateway

Ran in to problems getting a VPN up and running between GCP and a FortiGate 60-E that was behind a NAT gateway (with ports udp/500 + udp/4500 forwarded). On the GCP side, these messages would show up in the logs:

remote host is behind NAT
generating IKE_AUTH response 1 [ N(AUTH_FAILED) ]
looking for peer configs matching GCP.VPN.GATEWAY.IP[%any]...203.0.113.77[192.168.1.1]

This error means that GCP connected to the Peer VPN gateway successfully, but it in the IKEv2 headers, it identified itself by the private IP rather than the expected public one. AWS is not picky about this, but with GCP, the Peer VPN gateway must identify itself by using the same external IP address of the NAT device.

Most vendors have long supported an option to manually override the IP address for such scenarios. In Cisco IOS or IOS-XE, this can be controlled in the IKEv2 profile with the identity local address option:

crypto ikev2 profile GCP_IKEV2_PROFILE
 match address local interface GigabitEthernet1
 identity local address MY.PUBLIC.IP.ADDRESS
 authentication remote pre-share
 authentication local pre-share
 keyring local GCP_KEYRING
 lifetime 36000
 dpd 20 5 on-demand
!

With Palo Alto, this is configured in the IKE Gateway, Local Identification field:

For the sake of argument, we’ll say that CheckPoint uses the “Statically NATed IP” field to influence Local ID, although this doesn’t actually work.

Fortigate does offer “Local ID” field in version 6.4.6 and higher, under the Phase 1 proposal:

Seems nice and straightforward, but even after changing this setting, the VPN tunnel still won’t establish. Logs on the GCP end change slightly and now show this:

looking for peer configs matching GCP.VPN.GATEWAY.IP[%any]...203.0.113.77[203.0.113.77]

The private IP is no longer showing, so it seems the issue should be solved. Instead, GCP reports a “Peer not responding” message. The Fortigate actually reports Phase 1 success, waits a few seconds, and then starts the negotiation all over. So not very helpful.

I configured a test VPN between the FortiGate and a Palo Alto, which then gave a very specific and extremely useful error message:

IKE phase-1 negotiation is failed. When pre-shared key is used, peer-ID must be type IP address. Received type FQDN

Now this explains the problem! Even though the FortiGate is sending the correct IP address in the IKEv2 header, it’s being sent as the wrong identity type. The 5 identity types are listed in RFC 7815:

  • ID_IPV4_ADDR = 32 bit IPv4 address
  • ID_IPV6_ADDR = 128 bit IPv6 address
  • ID_FQDN = DNS hostname
  • ID_RFC822_ADDR = e-mail address
  • ID_KEY_ID = octet stream

If Fortigate were smart, it would either default to IPv4 address type or auto-determine this based on the text inputted in to the field. But it seems to simply default to FQDN. Oddly, there is a CLI option called “localid-type” under the Phase1-interface that clear is intended to provide this functionality:

FGT60E1234567890 # config vpn ipsec phase1-interface

FGT60E1234567890 (phase1-interface) # edit gcp

FGT60E1234567890 (gcp) # set localid-type 
auto         Select ID type automatically.
fqdn         Use fully qualified domain name.
user-fqdn    Use user fully qualified domain name.
keyid        Use key-id string.
address      Use local IP address.

But, similar to CheckPoint, it just doesn’t work, and can be considered a broken feature.

Since GCP does not support FQDN authentication, VPNs between GCP and FortiGates behind a NAT are not possible at this time.

Advertisement

FortiGate 60-E not supporting AES-GCM in Hardware

On a previous post I’d recommended using AES-GCM on VPNs to AWS and GCP since it’s generally a more efficient algorithm that offers higher throughput. So it came as a surprised today doing some deep-diving on my Fortigate 60-E today: AES-GCM is supported for Phase 2, it is not supported in hardware on the NPU:

FGT60ETK18XXXXXX # get vpn ipsec tunnel details
 gateway
   name: 'aws1'
   type: route-based
   local-gateway: 198.51.100.78:4500 (static)
   remote-gateway: 3.140.149.245:4500 (static)
   mode: ike-v1
   interface: 'wan1' (5)
   rx  packets: 52  bytes: 6524  errors: 0
   tx  packets: 110  bytes: 6932  errors: 3
   dpd: on-demand/negotiated  idle: 20000ms  retry: 3  count: 0
   nat traversal mode: keep-alive   RFC 3947   interval: 10
   selectors
     name: 'aws1'
     auto-negotiate: disable
     mode: tunnel
     src: 0:0.0.0.0/0.0.0.0:0
     dst: 0:0.0.0.0/0.0.0.0:0
     SA
       lifetime/rekey: 3600/3289   
       mtu: 1438
       tx-esp-seq: 2
       replay: enabled
       qat: 0
       inbound
         spi: 7dbc0283
         enc:  aes-gc  35a72036fa9a87000c90415b1863827652bf9dfd875f28a6d20fd1569e5c0099de639dcc
         auth:   null  
       outbound
         spi: ccdb6ab8
         enc:  aes-gc  21dd5c71a83142b0ecee1efe2c000c0dae586054160eb76df6f338d9071380b12103b0d9
         auth:   null  
       NPU acceleration: none

FGT60ETK18XXXXXX # get vpn ipsec stats crypto
NPU Host Offloading:
     Encryption (encrypted/decrypted)
     null      : 0                0               
     des       : 0                0               
     3des      : 0                0               
     aes-cbc   : 833309           0               
     aes-gcm   : 0                0               
     aria      : 0                0               
     seed      : 0                0               
     chacha20poly1305: 0                0               
     Integrity (generated/validated)
     null      : 0                0               
     md5       : 0                0               
     sha1      : 803671           0               
     sha256    : 29540            0               
     sha384    : 48               0               
     sha512    : 50               0 

Since the hardware offload isn’t occurring, the main CPU is moderately taxed when doing transfers via AES-GCM. Also, the throughput is only ~ 100 Mbps:

Reconfiguring the VPNs to AES-CBC and redoing the transfers, we get lower CPU usage and significantly higher throughput:

AWS or GCP IPSec Tunnels with BGP routing on a FortiGate software version 6.x

To use BGP routing on an AWS or GCP VPN connection, the tunnel interface needs to have its IP address assigned as a /32 and then the remote IP specified:

config system interface
    edit "GCP"
        set vdom "root"
        set ip 169.254.0.2 255.255.255.255
        set type tunnel
        set remote-ip 169.254.0.1 255.255.255.255
        set interface "wan1"
    next
end

BGP can be configured under the GUI in Network -> BGP in most cases, but the CLI has additional options. Here’s an example config for a peer 169.254.0.1 with ASN 64512, announcing the 192.168.1.0/24 prefix.

config router bgp
    set as 65000
    set router-id 192.168.1.254
    set keepalive-timer 10
    set holdtime-timer 30
    set scan-time 15
    config neighbor
       edit "169.254.0.1"
           set remote-as 64512
       next
    end
    config network
        edit 1
            set prefix 192.168.1.0 255.255.255.0
        next
    end


FortiGate Initial Config via CLI

Configure Network Interfaces

Example:

  • Set wan1 interface to static IP address 198.51.100.244/255.255.255.240
  • Configured default route of 198.51.100.241.
  • Allow ping and HTTPS on wan1 interface
  • Set LAN interface to 192.168.100.1/255.255.255.192
  • Set LAN interface’s DHCP scope address range as 192.168.100.30-59
  • Change lease time from default of 7 days to 2 hours
config system interface
 edit wan1
  set mode static
  set ip 198.51.100.244/28
  set allowaccess ping https fgfm
 next
 edit lan
  set ip 192.168.100.1/26
 end
config router static
 edit 0 
  set gateway 198.51.100.241
  set distance 1
  set device wan1
 end
config sys dhcp server
 edit 1
  set default-gateway 192.168.100.1
  set netmask 255.255.255.192
  set lease-time 7200
  config ip-range
   edit 1
    set start-ip 192.168.100.30
    set end-ip 192.168.100.59
   end
  end

Other useful commands

Change the admin user password:

config system admin
 edit admin
 set password MyNewPassword end

Create a secondary admin user

config system admin
    edit secondadminusername
      set accprofile super_admin
      set password MyPasswordGoesHere

Get L1 and L3 status of all interfaces

get system interface physical

Disabled/Enable an interface

config system interface
 edit lan
  set status down
 next
 edit lan
  set status up
 end

Enable sending of LLDP information

config system global
    set lldp-transmission enable
end

Check the route table

get router info routing-table all

Check the ARP Table

get system arp

Get the software version and serial number

get system status

Ping something

execute ping 8.8.8.8

Reboot the firewall

execute reboot

 

 

Authentication to Synology Directory Server (LDAP Server)

Upon configuring Directory Server the Synology will provide something like this:

The password configured is password for the ‘root’ user

Configuration for Cisco ASA / AnyConnect

aaa-server SYNOLOGY protocol ldap
aaa-server SYNOLOGY (Inside) host 192.168.1.100
 ldap-base-dn dc=myserver,dc=mydomain,dc=com
 ldap-scope subtree
 ldap-naming-attribute uid
 ldap-login-password <root user password>
 ldap-login-dn uid=root,cn=users,dc=myserver,dc=mydomain,dc=com
 server-type auto-detect

Configuration for FortiGate GUI

  • Common Name Identifier = uid
  • Distinguished Name = cn=users,dc=myserver,dc=mydomain,dc=com
  • Bind Type = Simple

Configuration for F5 BigIP

Need to change Authentication from ‘Basic’ to ‘Advanced’ to set Login LDAP attribute

  • Remote Directory Tree: dc=myserver,dc=mydomain,dc=com
  • Scope: Sub
  • BIND DN: uid=root,cn=users,dc=myserver,dc=mydomain,dc=com
  • Password: <root user password>
  • User Template: uid=%s,cn=users,dc=myserver,dc=mydomain,dc=com
  • Login LDAP Attribute: uid

To use Remote Role Groups:

Attribute String: memberOf=cn=users,cn=groups,dc=myserver,dc=mydomain,dc=com

 

Importing SSL Certificate on FortiGate 90D

The instructions talk about importing via GUI, but lower end platforms like the F90D don’t have that option.

Instead, certificates must be imported via a copy/paste job in the CLI

FWF90D5318062277 # config vpn certificate local
FWF90D5318062277 (local) # edit MyNewCert
FWF90D5318062277 (MyNewCert) # set private-key "-----BEGIN RSA PRIVATE KEY-----..."
FWF90D5318062277 (MyNewCert) # set certificate "-----BEGIN CERTIFICATE-----..."
FWF90D5318062277 (MyNewCert) # end

The certificate can then be set in the GUI.

FortiGate Static NAT using Port Forwarding / PAT

Easy in hindsight, but may be counter-intuitive for those coming from a Cisco or Palo Alto background such as myself.  There are two steps:

  1. Under Policy & Objects -> Virtual IPs, add a statement for each PAT rule with the “Port Forwarding” switch enabled at the bottom.
  2. Under Policy & Objects -> IPv4 Policy, add a rule from the public interface to the private interface with destination to be the object(s) created and service set to ALL.  NAT switch should remain disabled.

FortiGate_PAT_Virtual_IP

FortiGate_PAT_Rule