FortiGate to Azure VPN Gateway (Advanced)
Build a site-to-site IPsec VPN with custom crypto policies and BGP routing.
Introduction
30 Second Summary
Organisations connect their on-premises data centres to the cloud through encrypted tunnels called site-to-site VPNs. Configuring both ends of that tunnel correctly is one of the most common tasks a network or cloud engineer faces.
In this project, you will independently deploy and configure a site-to-site IPsec VPN between a FortiGate VM and an Azure VPN Gateway using custom cryptographic policies, routing, and firewall rules.
What You'll Build
A dual-VNet lab simulating a site-to-site VPN between an on-premises FortiGate firewall and Azure, with custom IKEv2 policies explicitly configured on both sides.
By the end of this project, you'll have:
- A working IKEv2 IPsec tunnel between a FortiGate VM and an Azure VPN Gateway with custom crypto policies (AES256/SHA256/DHGroup2).
- Bidirectional ICMP and RDP connectivity between test VMs across the tunnel, verified through explicit firewall policies with NAT disabled.
- Validated firewall policy enforcement by observing a controlled deny test that proves traffic is actively filtered.
- Secret Mission: Configure BGP dynamic routing over the tunnel to replace static routes.
Are there any prerequisites?
This is the advanced version of an existing guided project. You should have already completed the guided version, which walks through the same topology with full step-by-step instructions.
You also need familiarity with Azure networking (VNets, subnets, NSGs, UDRs), FortiGate CLI and GUI, and IPsec/IKE fundamentals.
Deploy VNet A and FortiGate VM
The simulated on-prem side of your tunnel needs a VNet with two subnets and a dual-NIC FortiGate VM acting as the edge device.
In this step, you will deploy VNet A, place a FortiGate VM across its two subnets, enable IP forwarding so Azure does not drop forwarded packets, and confirm management access to the FortiGate GUI.
In this step, get ready to:
- Create VNet A with an external subnet and an internal subnet.
- Deploy a FortiGate VM (PAYG) with dual NICs from Azure Marketplace.
- Enable IP forwarding on both NICs and verify FortiGate GUI access.
Create VNet A
VNet A represents the on-premises network. It needs two subnets to separate the FortiGate's external-facing interface from the internal network behind it.
- In the Azure Portal, create a new Virtual Network with these settings:
- Address space: 10.0.0.0/16
- Subnet 1 name: external-subnet, range: 10.0.0.0/24 (FortiGate port1).
- Subnet 2 name: internal-subnet, range: 10.0.1.0/24 (FortiGate port2).
- Choose any region, but use the same region for all resources in this project.
Deploy the FortiGate VM from Azure Marketplace
The FortiGate VM requires a dual-NIC deployment with one interface on each subnet.
- In Azure Marketplace, search for Fortinet FortiGate Next-Generation Firewall.
- Select the listing that shows Azure Application as the type.
- Choose the PAYG (Pay-As-You-Go) SKU.
Why PAYG instead of BYOL?
BYOL without a valid license drops into permanent trial mode. That restricts you to 3 interfaces, 3 firewall policies, and 3 routes. PAYG avoids all licensing friction and gives you full feature access.
- Configure the VM with these network settings:
- port1 (NIC 1): attached to external-subnet (10.0.0.0/24). Assign a new public IP.
- port2 (NIC 2): attached to internal-subnet (10.0.1.0/24). No public IP needed.
- Ensure the NSG on port1 allows inbound TCP 443 (HTTPS) and TCP 22 (SSH) for management access.
- Deploy the VM and wait for provisioning to complete.
Enable IP forwarding and verify GUI access
Without IP forwarding enabled at the Azure NIC level, Azure drops any packet not destined for the VM's own IP. Both NICs need this setting for the FortiGate to function as a network virtual appliance.
- Navigate to the FortiGate VM's networking settings in the Azure Portal.
- Select the port1 NIC and open its IP configurations.
- Set IP forwarding to Enabled and save.
- Repeat for the port2 NIC. Both NICs must have IP forwarding enabled.
- Note the public IP assigned to port1. This is your FortiGate public IP. You will need it as the VPN peer address on the Azure side.
- Note the private IP of port2. This is your FortiGate port2 private IP. You will use this as the UDR next-hop address later.
- Open a browser and navigate to https:// followed by your FortiGate public IP.
- Log in with the credentials you set during deployment. Confirm the FortiGate dashboard loads.
VNet A is live with the FortiGate ready to terminate a tunnel. Next, you will deploy VNet B with the Azure VPN Gateway on the other side.
Deploy VNet B, VPN Gateway, and Test VMs
VNet A and your FortiGate VM are ready to act as the simulated on-prem side. Now you need the Azure side: a second VNet hosting a VPN Gateway that will terminate the IPsec tunnel, plus test VMs on both sides to verify connectivity later.
The VPN Gateway takes 45 minutes or more to provision. You will kick off that deployment first, then deploy both test VMs in parallel while you wait.
In this step, get ready to:
- Create VNet B with a GatewaySubnet and a VM subnet.
- Deploy an Azure VPN Gateway (VpnGw1AZ, Route-based, Generation2).
- Deploy a Windows Server test VM in each VNet.
Create VNet B
- In the Azure Portal, create a new Virtual Network with these settings:
- Name: a name you will recognise (e.g. vnet-b).
- Region: the same region you used for VNet A.
- Address space: 10.1.0.0/16.
- Add a subnet named exactly GatewaySubnet with address range 10.1.0.0/27.
- Add a second subnet (e.g. vm-subnet) with address range 10.1.1.0/24.
Why must it be named GatewaySubnet?
Azure requires the gateway subnet to be named exactly GatewaySubnet. This lets Azure know which subnet to deploy the virtual network gateway VMs and services to. Gateway creation will fail if the subnet uses any other name.
Deploy the VPN Gateway
- Navigate to Create a resource and search for Virtual network gateway.
- Configure the gateway with these parameters:
- Gateway type: VPN.
- VPN type: Route-based.
- SKU: VpnGw1AZ.
- Generation: Generation2.
- Virtual network: select VNet B.
- Public IP address: create a new one.
- Click Review + create, then Create.
Gateway provisioning takes time
The VPN Gateway takes 45 minutes or more to provision. Do not wait for it to finish. Proceed to deploy the test VMs now and return to note the gateway public IP once provisioning completes.
Deploy the test VMs
You need a test VM on each side of the tunnel to verify end-to-end connectivity later.
- Deploy Test VM A in VNet A's internal subnet (10.0.1.0/24):
- OS: Windows Server.
- Networking: set a static private IP of 10.0.1.10.
- Deploy Test VM B in VNet B's VM subnet (10.1.1.0/24):
- OS: Windows Server.
- Networking: set a static private IP of 10.1.1.10.
- Choose an appropriate VM size for both (no heavy compute needed for this lab).
- Set an admin username and password you will remember for RDP access later.
Use the same credentials for both VMs
Setting the same admin username and password on both test VMs simplifies RDP testing later in the project.
Once the VPN Gateway finishes provisioning, note its public IP. You will need this as the peer address when configuring the FortiGate side of the tunnel in the next step.
Configure the IPsec Tunnel on Both Sides
Your infrastructure is deployed and the VPN Gateway is ready. Now you need to establish the actual IPsec tunnel between the two sites.
Both sides of the tunnel must negotiate with exactly matching cryptographic parameters. If even one algorithm or DH group differs between the Azure VPN Gateway and the FortiGate, the tunnel will silently fail to establish.
In this step, get ready to:
- Create the Local Network Gateway and VPN Connection on the Azure side with a custom IPsec/IKE policy.
- Configure Phase 1 and Phase 2 on the FortiGate with matching proposals.
- Verify the tunnel establishes successfully.
Create the Local Network Gateway and VPN Connection (Azure side)
The Azure side needs two resources to complete the tunnel: a Local Network Gateway that represents the FortiGate peer, and a Connection that ties the VPN Gateway to that peer with your custom crypto policy.
Create a Local Network Gateway with these settings:
- Gateway IP address: your FortiGate's public IP.
- Address space: 10.0.1.0/24 (the network behind the FortiGate).
Create a Connection on the VPN Gateway with these settings:
- Connection type: Site-to-site (IPsec).
- IKE version: IKEv2.
- Custom IPsec/IKE policy:
- Pre-shared key (PSK): choose a strong key and record it. You will need the same key on the FortiGate.
- Connection mode: Default.
Why these specific algorithms?
AES256/SHA256/DHGroup2 with PFS None is the target policy for this lab. DHGroup2 uses 1024-bit MODP, which is straightforward to configure on both sides.
Disabling PFS simplifies the Phase 2 negotiation by not requiring a fresh Diffie-Hellman exchange for each new SA.
Configure the FortiGate Phase 1 and Phase 2
On the FortiGate, configure the IPsec tunnel to point at the Azure VPN Gateway public IP with proposals that exactly match the Azure custom policy.
Phase 1 interface requirements:
- IKE version: 2.
- Interface: port1 (external).
- Remote gateway: the Azure VPN Gateway's public IP.
- Proposal: aes256-sha256.
- DH group: 2.
- Pre-shared key: the same PSK you set on the Azure Connection.
Phase 2 selector requirements:
- Local subnet: 10.0.1.0/24.
- Remote subnet: 10.1.1.0/24.
- Proposal: aes256-sha256.
- PFS: disable.
GUI or CLI on the FortiGate
You can configure these settings through the FortiGate GUI (VPN > IPsec Tunnels > Create New) or via CLI. If using CLI, the relevant config sections are config vpn ipsec phase1-interface and config vpn ipsec phase2-interface.
Verify the tunnel establishes
Once both sides are configured, the tunnel should negotiate automatically. Confirm establishment from both directions.
- On the Azure Portal, navigate to your VPN Gateway's Connections blade and confirm the connection status shows Connected.
- On the FortiGate, check the IPsec monitor (Monitor > IPsec Monitor in the GUI) or run diagnose vpn ike gateway list from the CLI.
- Confirm both Phase 1 (IKE SA) and Phase 2 (IPsec SA) are up.
Tunnel not coming up?
The most common cause is a crypto mismatch. Verify that both sides specify the exact same encryption, integrity, and DH group for each phase. Also confirm the PSK is identical on both ends (watch for trailing spaces).
Check that the FortiGate's NSG allows inbound UDP 500 and UDP 4500 from the VPN Gateway's public IP. Without these ports open, IKE negotiation cannot reach the FortiGate.
Help me troubleshoot why my IPsec tunnel is not establishing between FortiGate and Azure VPN Gateway.
Your tunnel is up and both IKE phases are established. Next, you need to make sure traffic from Test VM A actually routes through the FortiGate and into the tunnel.
Configure Routing and IP Forwarding
Your tunnel is up, but traffic from Test VM A does not yet know how to reach the remote network. Azure's default routing sends traffic destined for 10.1.0.0/16 nowhere useful.
In this step, you will steer that traffic through the FortiGate by creating a User-Defined Route on the Azure side and a matching static route on the FortiGate side.
In this step, get ready to:
- Create a UDR (Route Table) directing tunnel-bound traffic to the FortiGate.
- Confirm IP forwarding is enabled on both FortiGate NICs.
- Add a FortiGate static route for the remote network via the tunnel interface.
Create and attach a UDR to the internal subnet
Without a UDR, Test VM A's traffic destined for 10.1.0.0/16 stays within Azure's default system routes and never reaches the FortiGate.
- In the Azure Portal, create a new Route Table in the same region as VNet A.
- Add a route with the following parameters:
- Destination: 10.1.0.0/16.
- Next hop type: Virtual Appliance.
- Next hop address: FortiGate port2 private IP (FORTIGATE_PORT2_PRIVATE_IP).
- Associate the Route Table with the internal-subnet (10.0.1.0/24) in VNet A.
Confirm IP forwarding on both FortiGate NICs
You enabled IP forwarding in Step 1. Verify it is still active on both NICs before proceeding.
- Navigate to the FortiGate VM in the Azure Portal.
- Open Networking and select each NIC (port1 and port2).
- Confirm IP forwarding is set to Enabled on both.
Why verify again?
Without IP forwarding enabled at the Azure NIC level, Azure drops any packet where the destination IP does not match the NIC's own address. The UDR alone is not sufficient.
Add a static route on the FortiGate for the remote network
The Azure UDR gets traffic to the FortiGate. Now the FortiGate itself needs to know where to send packets destined for 10.1.0.0/16.
- In the FortiGate GUI or CLI, create a static route:
- Destination: 10.1.0.0/16.
- Interface: your IPsec tunnel interface (the Phase 1 interface you created in Step 3).
- Save the route and verify it appears in the FortiGate routing table.
Routing is in place. Traffic from Test VM A destined for 10.1.0.0/16 now flows through the FortiGate and into the tunnel. Next, you will create firewall policies to explicitly permit that traffic and verify end-to-end connectivity.
Configure Firewall Policies, NSG Rules, and Verify Connectivity
Your tunnel is up and routing is in place. Traffic from Test VM A destined for 10.1.0.0/16 now flows through the FortiGate and into the IPsec tunnel.
But the FortiGate is a firewall. Without explicit policies permitting cross-tunnel traffic, it drops everything. You also need NSG rules on the Azure side scoped to tunnel-sourced traffic only.
In this step, get ready to:
- Create FortiGate firewall policies allowing bidirectional cross-tunnel traffic with NAT disabled.
- Scope the NSG on Test VM B to permit only tunnel-sourced ICMP and RDP.
- Verify end-to-end connectivity and validate firewall enforcement with a controlled deny test.
Create FortiGate firewall policies for cross-tunnel traffic
You need two policies. One for traffic originating behind the FortiGate heading toward Azure, and one for return traffic coming back through the tunnel.
- Create Policy 1 with these parameters:
- Incoming interface: port2 (internal).
- Outgoing interface: your VPN tunnel interface.
- Source: 10.0.1.0/24.
- Destination: 10.1.1.0/24.
- Service: ALL.
- NAT: disabled.
- Logging: enabled (log all sessions).
- Create Policy 2 with these parameters:
- Incoming interface: your VPN tunnel interface.
- Outgoing interface: port2 (internal).
- Source: 10.1.1.0/24.
- Destination: 10.0.1.0/24.
- Service: ALL.
- NAT: disabled.
- Logging: enabled (log all sessions).
Scope the NSG on Test VM B
Add inbound rules to the NSG attached to Test VM B's NIC or the vm-subnet. Only tunnel-sourced traffic should be permitted.
- Allow inbound ICMP from source 10.0.1.0/24.
- Allow inbound RDP (TCP 3389) from source 10.0.1.0/24.
- The default deny rule handles everything else.
Verify bidirectional connectivity and run a controlled deny test
RDP into Test VM A and run these verifications from its command prompt.
- From Test VM A (10.0.1.10): ping 10.1.1.10. This should succeed.
- From Test VM B (10.1.1.10): ping 10.0.1.10. This should succeed.
- From Test VM A: RDP to 10.1.1.10 (Test VM B's private IP). This should succeed.
Now prove that the FortiGate is actually enforcing policy, not just passing traffic blindly.
- Temporarily disable or delete one of your FortiGate firewall policies.
- Re-run the ping that should now be affected. Confirm that traffic stops.
- Re-enable the policy and confirm traffic resumes.
Your site-to-site VPN is fully operational with explicit firewall enforcement. You have end-to-end connectivity between both sites and proof that the FortiGate is actively controlling traffic flow. If you want to take this further, the Secret Mission adds BGP dynamic routing to replace your static routes.
Secret mission
Configure BGP Dynamic Routing Over the Tunnel
Your tunnel works with static routes, but production networks rarely stay static. Replace your UDRs and manual routes with BGP peering over the IPsec tunnel so both sides learn routes dynamically.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses multiple paid Azure resources that accumulate significant charges if left running.
Cost warning
The Azure VPN Gateway (VpnGw1AZ) costs approximately $0.21/hr ($153.30/month) and cannot be deallocated or paused. It incurs charges as long as it exists.
The FortiGate VM adds $0.50-1.00/hr depending on instance size, plus compute costs for both Windows Server test VMs. Delete all resources immediately after verifying the tunnel works.
Resources you used:
- Azure VPN Gateway (VpnGw1AZ) in VNet B.
- FortiGate VM (PAYG) with two NICs and a public IP in VNet A.
- Two Windows Server test VMs (Test VM A and Test VM B).
- Two VNets (VNet A: 10.0.0.0/16, VNet B: 10.1.0.0/16) with subnets.
- Local Network Gateway, Connection, Route Table (UDR), NSGs, and public IP addresses.
Keep everything running
No action needed. Choose this only if you are actively debugging or extending the lab (e.g. completing the BGP Secret Mission) in the same session.
Cost warning
This lab accumulates $5-8+ per hour while all resources are running. The VPN Gateway alone costs $153.30/month. Do not leave this running overnight.
Pause - I'll come back to this later
Deallocate the VMs to stop compute charges while retaining disks and configuration. The VPN Gateway cannot be paused and will continue to incur charges.
- Deallocate each VM by running the following command in Cloud Shell for each one:
az vm deallocate --resource-group [[RESOURCE_GROUP="your-resource-group-name"]] --name [[VM_NAME="your-vm-name"]]
Run this command once for the FortiGate VM, once for Test VM A, and once for Test VM B.
What keeps charging?
Deallocating VMs stops compute billing but you still pay for managed disks and public IP addresses. The VPN Gateway continues to charge ~$0.21/hr regardless.
If you will be away for more than a few hours, deleting everything is more cost-effective.
Delete - I don't want to use this again
Delete the entire resource group to remove all resources and stop all charges immediately. This is the recommended option once you have verified the tunnel works.
- Open Azure Cloud Shell or your local terminal with the Azure CLI.
- Delete the resource group containing all your lab resources by running:
az group delete --name [[RESOURCE_GROUP="your-resource-group-name"]]
- Confirm the deletion when prompted.
- If you used separate resource groups for VNet A and VNet B, run the command again for the second resource group.
What does this remove?
Deleting the resource group removes the VPN Gateway, FortiGate VM, both test VMs, all VNets, subnets, public IPs, the Local Network Gateway, Connection, Route Table, and NSGs. Every resource created in this lab is gone and billing stops.
- Verify the deletion is complete by checking the Azure Portal. Navigate to Resource groups and confirm your lab resource group no longer appears.
That's a Wrap!
That's a Wrap!
Nice work! You independently built a site-to-site IPsec VPN between a FortiGate firewall and an Azure VPN Gateway with custom crypto policies, routing, and firewall rules.
You've learned how to:
- Built an IKEv2 IPsec tunnel with custom crypto policies (AES256/SHA256/DHGroup2/PFS None) explicitly matched on both a FortiGate VM and Azure VPN Gateway.
- Configured User-Defined Routes and IP forwarding to steer traffic through a FortiGate NVA into the tunnel.
- Created explicit firewall policies with NAT disabled, scoped NSGs to tunnel traffic only, and validated enforcement through a controlled deny test.
- Configured BGP dynamic routing over the tunnel to replace static routes and verified route propagation.
Ready to quiz yourself?