FortiGate IPsec Site-to-Site VPN to Cisco ASA on FortiOS 7.4
The Problem
Building an IPsec tunnel between a FortiGate and a Cisco ASA is one of those tasks that looks straightforward until Phase 2 refuses to come up and you’re staring at two different vendor debug outputs trying to figure out which side is lying. The encryption parameters, PFS settings, and traffic selectors all have to match exactly — and each platform expresses them slightly differently.
This post walks through a production setup I built between a branch FortiGate 60F running FortiOS 7.4.4 and an HQ Cisco ASA 5516-X running ASA 9.16(4). Both sides have static public IPs. The tunnel uses IKEv2 with a pre-shared key, AES-256/SHA-256 encryption, and DH group 14. I’ll cover both sides of the config, the CLI commands to verify status, and the exact errors I ran into during the build.
Environment Summary
| Parameter | Value |
|---|---|
| Branch device | FortiGate 60F, FortiOS 7.4.4 |
| HQ device | Cisco ASA 5516-X, ASA 9.16(4) |
| FortiGate public IP | 203.0.113.5 |
| ASA public IP | 198.51.100.10 |
| Branch subnet | 10.20.0.0/24 |
| HQ subnet | 10.10.0.0/24 |
| IKE version | IKEv2 |
| Authentication | Pre-shared key |
| Encryption | AES-256 |
| Integrity | SHA-256 |
| DH group | 14 |
| Phase 1 lifetime | 28800 seconds |
| Phase 2 lifetime | 3600 seconds |
| PFS | Enabled, DH group 14 |
Step 1 — Configure the FortiGate Phase 1 (IPsec Wizard)
Go to VPN > IPsec Wizard, select Custom, and name the tunnel vpn-hq-asa.
Fill in the Phase 1 parameters as follows:
| Field | Value |
|---|---|
| Remote Gateway | Static IP Address |
| IP Address | 198.51.100.10 |
| Interface | wan1 |
| IKE Version | 2 |
| Authentication Method | Pre-shared Key |
| PSK | (your shared secret) |
| Encryption | AES256 |
| Authentication | SHA256 |
| Diffie-Hellman Group | 14 |
| Lifetime | 28800 |
Leave Dead Peer Detection enabled with the default on-demand setting. The FortiGate wizard does not always expose every advanced IKEv2 parameter in the GUI, so after finishing the wizard, verify the Phase 1 config from CLI:
show vpn ipsec phase1-interface vpn-hq-asa
You should see output that includes:
config vpn ipsec phase1-interface
edit "vpn-hq-asa"
set interface "wan1"
set ike-version 2
set keylife 28800
set peertype any
set proposal aes256-sha256
set dhgrp 14
set remote-gw 198.51.100.10
set psksecret ENC <encrypted-secret>
next
end
If ike-version shows 1, the wizard silently reverted it. Set it manually:
config vpn ipsec phase1-interface
edit "vpn-hq-asa"
set ike-version 2
next
end
Step 2 — Configure the FortiGate Phase 2
Still in the wizard (or via VPN > IPsec Tunnels > Edit > Phase 2 Selectors), configure:
| Field | Value |
|---|---|
| Local Address | 10.20.0.0/24 |
| Remote Address | 10.10.0.0/24 |
| Encryption | AES256 |
| Authentication | SHA256 |
| Enable PFS | Yes |
| DH Group | 14 |
| Keylifetime | 3600 seconds |
Verify from CLI:
show vpn ipsec phase2-interface
Expected output:
config vpn ipsec phase2-interface
edit "vpn-hq-asa-p2"
set phase1name "vpn-hq-asa"
set proposal aes256-sha256
set dhgrp 14
set pfs enable
set keylifeseconds 3600
set src-subnet 10.20.0.0 255.255.255.0
set dst-subnet 10.10.0.0 255.255.255.0
next
end
Pay attention to pfs enable and dhgrp 14. These two fields must align with whatever the ASA is configured to negotiate. If one side has PFS enabled and the other does not, Phase 2 will not come up and you’ll see no SA proposal chosen in the FortiGate debug.
Step 3 — Add a Static Route
The tunnel interface needs a route pointing traffic toward it. Go to Network > Static Routes > Create New:
| Field | Value |
|---|---|
| Destination | 10.10.0.0/24 |
| Interface | vpn-hq-asa |
| Distance | 1 |
From CLI:
config router static
edit 0
set dst 10.10.0.0 255.255.255.0
set device "vpn-hq-asa"
set distance 1
next
end
Verify it shows up in the routing table:
get router info routing-table static
You should see:
S 10.10.0.0/24 [1/0] via vpn-hq-asa tunnel 198.51.100.10
Step 4 — Create Firewall Policies
You need two policies: one for outbound traffic (LAN to VPN) and one for inbound (VPN to LAN). NAT must be disabled on both.
Policy 1 — LAN to HQ (outbound):
config firewall policy
edit 0
set name "LAN-to-HQ-VPN"
set srcintf "internal"
set dstintf "vpn-hq-asa"
set srcaddr "10.20.0.0/24"
set dstaddr "10.10.0.0/24"
set action accept
set schedule "always"
set service "ALL"
set nat disable
next
end
Policy 2 — HQ to LAN (inbound):
config firewall policy
edit 0
set name "HQ-VPN-to-LAN"
set srcintf "vpn-hq-asa"
set dstintf "internal"
set srcaddr "10.10.0.0/24"
set dstaddr "10.20.0.0/24"
set action accept
set schedule "always"
set service "ALL"
set nat disable
next
end
NAT off is critical. If NAT is enabled on the outbound policy, the FortiGate will SNAT traffic to its WAN IP before encapsulating it, which breaks the Phase 2 traffic selector match.
Step 5 — Configure the Cisco ASA
Here is the complete ASA configuration for this tunnel. The ASA initiates as a responder here, but these commands also work if the ASA is the initiator.
IKEv2 Policy:
crypto ikev2 policy 10
encryption aes-256
integrity sha256
group 14
prf sha256
lifetime seconds 28800
IPsec Proposal:
crypto ipsec ikev2 ipsec-proposal AES256-SHA256
protocol esp encryption aes-256
protocol esp integrity sha-256
Access List defining interesting traffic (encryption domain):
access-list VPN-ACL extended permit ip 10.10.0.0 255.255.255.0 10.20.0.0 255.255.255.0
Crypto Map:
crypto map vpn-map 10 match address VPN-ACL
crypto map vpn-map 10 set peer 203.0.113.5
crypto map vpn-map 10 set ikev2 ipsec-proposal AES256-SHA256
crypto map vpn-map 10 set pfs group14
crypto map vpn-map interface outside
Tunnel Group:
tunnel-group 203.0.113.5 type ipsec-l2l
tunnel-group 203.0.113.5 ipsec-attributes
ikev2 remote-authentication pre-shared-key <PSK>
ikev2 local-authentication pre-shared-key <PSK>
Note that IKEv2 on the ASA requires both remote-authentication and local-authentication pre-shared keys set explicitly under the tunnel-group. IKEv1 only required one. Missing either one will cause the Phase 1 authentication exchange to fail.
Enable IKEv2 on the outside interface if not already:
crypto ikev2 enable outside
Step 6 — Bring Up the Tunnel and Verify
On the FortiGate, bring up the tunnel by sending interesting traffic or using the GUI toggle. Then verify:
diagnose vpn ike gateway list name vpn-hq-asa
Look for IKEv2 established in the output. A healthy Phase 1 shows:
vd: root/0
name: vpn-hq-asa
version: 2
interface: wan1 6
addr: 203.0.113.5:500 -> 198.51.100.10:500
created: Xs ago
IKE SA: created 1/1 established 1/1 time 0/0/0 ms
IPsec SA: created 1/1 established 1/1 time 0/0/0 ms
Verify Phase 2 and see packet counters:
diagnose vpn tunnel list name vpn-hq-asa
You should see enc and dec counters incrementing if traffic is passing.
get router info routing-table static
Confirm the static route to 10.10.0.0/24 is present.
On the ASA, verify with:
show crypto ikev2 sa
show crypto ipsec sa peer 203.0.113.5
For show crypto ipsec sa, look at the #pkts encaps and #pkts decaps counters. If encaps is incrementing but decaps is not, traffic is leaving the ASA but not returning — check the FortiGate firewall policy for the inbound direction.
To simulate traffic without a live host:
packet-tracer input inside icmp 10.10.0.5 8 0 10.20.0.5 detailed
This traces an ICMP packet from an HQ host toward the branch and shows every policy/crypto decision the ASA makes.
Troubleshooting
Error 1: Phase 1 Comes Up but Phase 2 Stays Down
Symptom: diagnose vpn ike gateway list shows Phase 1 established, but diagnose vpn tunnel list shows no SA and no packet counters.
Most likely cause: Mismatched traffic selectors (encryption domain). The FortiGate quick mode selector and the ASA crypto map ACL must define the exact same source and destination subnets. If the ASA ACL matches 10.10.0.0/25 and the FortiGate selector is 10.10.0.0/24, the negotiation fails.
Fix: Align both sides to the same exact subnet. On the FortiGate, check:
show vpn ipsec phase2-interface
On the ASA:
show access-list VPN-ACL
Make sure the subnet masks match exactly on both sides.
Error 2: “no SA proposal chosen”
Symptom: FortiGate debug (diagnose debug application ike -1) shows no SA proposal chosen during Phase 2 negotiation.
Cause: PFS mismatch. One side has PFS enabled with DH group 14, the other has PFS disabled or uses a different group.
Fix: On the FortiGate, confirm:
show vpn ipsec phase2-interface
Confirm set pfs enable and set dhgrp 14. On the ASA, confirm the crypto map includes:
crypto map vpn-map 10 set pfs group14
If you want to disable PFS, remove it from both sides. Either both enabled with the same group, or both disabled — no mixing.
Error 3: Phase 1 Fails — Authentication Error
Symptom: diagnose vpn ike gateway list shows no established SA, and IKE debug shows authentication failed.
Cause 1: PSK mismatch. Copy-paste errors are common here, especially with special characters.
Cause 2: On IKEv2, the ASA requires both ikev2 remote-authentication pre-shared-key and ikev2 local-authentication pre-shared-key under the tunnel-group. If only one is set, authentication fails.
Fix: Verify both keys on the ASA:
show running-config tunnel-group 203.0.113.5
Both lines must be present. Reset the PSK on both sides to a known value and retest.
Error 4: Tunnel Is Up but No Traffic Passes
Symptom: Both sides show established SAs with packet counters, but pings fail end-to-end.
Cause: NAT is enabled on the FortiGate firewall policy, or a firewall policy in one direction is missing.
Fix: Check both firewall policies exist and NAT is off:
show firewall policy
Look for nat: disable on both VPN-related policies. If NAT is enabled, traffic gets SNAT’d before matching the Phase 2 selector, and the ASA drops it because the source IP no longer matches the ACL.
Error 5: Tunnel Drops Periodically
Symptom: Tunnel comes up fine but drops every few hours and re-establishes.
Cause: Phase 1 or Phase 2 lifetime mismatch causing a race condition during rekey, or DPD is triggering on an idle tunnel.
Fix: Align lifetimes exactly on both sides (Phase 1: 28800, Phase 2: 3600 as configured here). If the tunnel carries low-volume traffic, also check that DPD isn’t timing out during quiet periods. On FortiGate:
config vpn ipsec phase1-interface
edit "vpn-hq-asa"
set dpd on-demand
set dpd-retrycount 3
set dpd-retryinterval 20
next
end
on-demand only sends DPD probes when there is traffic to send, which avoids false failures on low-traffic tunnels.
FAQ
How do I troubleshoot Phase 2 failure on FortiGate IPsec VPN?
Start with the IKE debug on the FortiGate:
diagnose debug reset
diagnose debug application ike -1
diagnose debug enable
Trigger the tunnel by sending traffic or toggling the interface down/up. Watch for the Phase 2 exchange — look for no SA proposal chosen (proposal mismatch), TS_UNACCEPTABLE (traffic selector mismatch), or authentication failed (PSK issue). Turn off debug when done:
diagnose debug disable
diagnose debug reset
Also run diagnose vpn tunnel list name vpn-hq-asa to check packet counters. Zero dec with non-zero enc means traffic is leaving but not returning — look at the far-end firewall policy or routing.
What encryption domain should I use for FortiGate to Cisco ASA?
The encryption domain is the set of source and destination subnets that define what traffic is protected by the tunnel. On the FortiGate, this is the Phase 2 local and remote subnet selectors. On the ASA, this is the ACL referenced by the crypto map.
Both sides must match exactly — same network address, same subnet mask. Do not summarize one side. If the FortiGate protects 10.20.0.0/24 and the ASA ACL says 10.20.0.0/25, Phase 2 will not establish. The platforms compare these selectors during the IKEv2 TS (Traffic Selector) negotiation and reject mismatches.
For this setup: FortiGate local 10.20.0.0/24, remote 10.10.0.0/24. ASA ACL: permit ip 10.10.0.0/24 to 10.20.0.0/24. Exact match, no summarization.
How do I match PFS settings between FortiGate and ASA?
PFS must be either enabled with the same DH group on both sides, or disabled on both sides. There is no middle ground.
FortiGate (PFS enabled, DH 14):
set pfs enable
set dhgrp 14
ASA (PFS enabled, DH 14):
crypto map vpn-map 10 set pfs group14
To disable PFS on both sides:
FortiGate:
set pfs disable
ASA: remove the set pfs line from the crypto map entry.
If you toggle PFS on the FortiGate and forget to update the ASA (or vice versa), you’ll get no SA proposal chosen every time Phase 2 tries to negotiate.
What CLI commands verify IPsec status on FortiGate?
These are the four commands I use in order:
1. Check Phase 1 (IKE SA) status:
diagnose vpn ike gateway list name vpn-hq-asa
2. Check Phase 2 (IPsec SA) status and packet counters:
diagnose vpn tunnel list name vpn-hq-asa
3. Confirm routing is in place:
get router info routing-table static
4. Run live IKE debug during negotiation:
diagnose debug application ike -1
diagnose debug enable
For a broader view of all active tunnels, drop the name filter:
diagnose vpn ike gateway list
diagnose vpn tunnel list
Conclusion
Building a FortiGate-to-ASA IKEv2 tunnel is a straightforward process once you understand where the two platforms use different terminology for the same concepts. The encryption domain (FortiGate’s Phase 2 selectors vs. the ASA’s crypto map ACL) and PFS configuration are the two most common sources of Phase 2 failures — get those aligned and the rest usually falls into place.
Key takeaways from this build:
- Match encryption domain subnets exactly. No summarization on one side.
- PFS must be consistently enabled or disabled with the same DH group on both platforms.
- IKEv2 on the ASA requires both
remote-authenticationandlocal-authenticationPSK entries under the tunnel-group. - Use
diagnose vpn tunnel liston the FortiGate to read packet counters — it’s the quickest way to confirm if encrypted traffic is actually flowing.
Once the tunnel is up, the day-two work is verification — when something drops at 3 AM you want the CLI flow already in muscle memory. The diagnostic companion to this post is Cómo verificar un túnel IPsec en FortiGate por CLI (FortiOS 7.4.4) (Spanish), which walks the diagnose vpn ike gateway list → diagnose vpn tunnel list → IKE debug → sniffer flow against the same FortiGate ↔ ASA setup built here. If the bigger picture is that you’re moving off SSL VPN and onto IPsec across the board — not just site-to-site but also dialup — the pre-migration audit lives in the FortiGate SSL VPN Migration Checklist (FortiOS 7.6). Both posts plus the rest of the FortiGate work on this site are organized in the FortiGate Field Guide.
