FortiGate to Azure Site-to-Site VPN

Build an IKEv2 IPsec tunnel between a FortiGate VM and Azure VPN Gateway.

Introduction

30 Second Summary

When a company has offices in two different cities, their networks need to talk to each other securely over the public internet. A site-to-site VPN creates an encrypted tunnel between the two locations so that private traffic stays private.

In this project, you will build a site-to-site IPsec VPN between a FortiGate firewall and an Azure VPN Gateway. You will validate end-to-end encrypted connectivity by sending traffic between two test VMs through the tunnel.

What You'll Build

A fully functional site-to-site IPsec VPN lab in Azure simulating a real-world hybrid connectivity scenario between a FortiGate next-generation firewall (acting as on-premises) and an Azure cloud network protected by a VPN Gateway.

By the end of this project, you'll have:

  • A FortiGate VM with dual-NIC architecture deployed in a simulated on-premises network, controlling traffic through explicit firewall policies.
  • An Azure VPN Gateway with a custom IPsec/IKE policy establishing an encrypted IKEv2 tunnel using AES-256 encryption.
  • End-to-end validated connectivity between two test VMs proving traffic flows through the encrypted tunnel, with a controlled deny test proving active policy enforcement.
  • Secret Mission: Replace static routes with BGP dynamic routing over the IPsec tunnel for automatic route advertisement.

Are there any prerequisites?

You need an Azure subscription with permissions to create resources. Familiarity with IPsec/IKE concepts (Phase 1, Phase 2, DH groups, encryption algorithms) and basic Azure Portal navigation will help you follow along.

Create the Azure Foundation and Start VPN Gateway Deployment

The Azure VPN Gateway takes 30-45 minutes to provision. You will deploy the Azure-side infrastructure first so you can use that wait time productively in Steps 2 and 3.

In this step, you will create the cloud-side virtual network, its subnets, and kick off the VPN Gateway deployment. Think of this as laying the foundation on the Azure side of your tunnel.

In this step, get ready to:
  • Create a Resource Group and Virtual Network (VNet B) with two subnets.
  • Create a Standard SKU public IP and deploy the VPN Gateway.
  • Note where to find the VPN Gateway public IP after provisioning completes.
Create the Resource Group and VNet B

Every Azure project starts with a Resource Group. This is a container that holds all related resources so you can manage and delete them together.

  • In the Azure Portal, click Create a resource at the top of the home page.
  • Search for Resource group and select Resource group from the results.
  • Click Create.
  • Enter rg-vpn-lab in the Resource group name field.
  • Select East US 2 for the Region.
  • Click Review + create, then click Create.

You should see a "Deployment succeeded" notification. Now create VNet B inside this Resource Group.

  • Click Create a resource again.
  • Search for Virtual network and select Virtual network from the results.
  • Click Create.
  • Select rg-vpn-lab as the Resource group.
  • Enter vnet-b in the Virtual network name field.
  • Select East US 2 for the Region.
  • Click Next to move to the IP Addresses tab.

Now configure the address space and subnets for VNet B.

  • Set the IPv4 address space to 10.1.0.0/16. Remove any default address spaces if present.
  • Click Add a subnet.
  • Enter GatewaySubnet as the Subnet name.
  • Set the Subnet address range to 10.1.0.0/27.
  • Click Add to save the subnet.
  • Click Add a subnet again.
  • Enter sn-vnetb-vms as the Subnet name.
  • Set the Subnet address range to 10.1.1.0/24.
  • Click Add to save the subnet.
  • Click Review + create, then click Create.

Why must it be named exactly GatewaySubnet?

Azure requires the VPN Gateway's subnet to be named exactly GatewaySubnet. If you use any other name, the VPN Gateway deployment will fail. The minimum recommended size is /27 to allow room for future gateway configurations.

VNet creation failing?

Make sure you removed any default address spaces before adding 10.1.0.0/16. Overlapping address spaces will cause a validation error.

Double check the subnet ranges fit inside the VNet's address space. 10.1.0.0/27 and 10.1.1.0/24 must both be within 10.1.0.0/16.

Help me troubleshoot my VNet B creation error in Azure Portal.

Create the public IP and deploy the VPN Gateway

The VPN Gateway needs a public IP address so the FortiGate can reach it over the internet. Azure requires a Standard SKU public IP with static allocation for new VPN Gateways.

  • Click Create a resource in the Azure Portal.
  • Search for Public IP address and select Public IP address from the results.
  • Click Create.
  • Select rg-vpn-lab as the Resource group.
  • Select East US 2 as the Region.
  • Enter pip-vpngw in the Name field.
  • Select Standard for the SKU.
  • Select Static for the Assignment.
  • Click Review + create, then click Create.

Now deploy the VPN Gateway itself. This is the resource that will terminate the IPsec tunnel on the Azure side.

  • Click Create a resource.
  • Search for Virtual network gateway and select Virtual network gateway from the results.
  • Click Create.
  • Enter vpngw-lab in the Name field.
  • Select East US 2 as the Region.
  • Select VPN for the Gateway type.
  • Select Route-based for the VPN type.
  • Select VpnGw1AZ for the SKU.
  • Select vnet-b for the Virtual network.
  • Confirm that GatewaySubnet is automatically selected as the Subnet.
  • Select pip-vpngw for the Public IP address.
  • Click Review + create, then click Create.

Do NOT wait for this deployment to finish

The VPN Gateway takes approximately 30-45 minutes to provision. You will use this time productively by building the FortiGate side of the tunnel in Steps 2 and 3. Proceed to Step 2 immediately.

Why VpnGw1AZ instead of the Basic SKU?

The Basic SKU cannot be configured through the Azure Portal and does not support custom IPsec/IKE policies or BGP. VpnGw1AZ supports portal configuration, custom crypto policies, and BGP for the Secret Mission.

Non-AZ gateway SKUs (VpnGw1 through VpnGw5 without the AZ suffix) can no longer be created as of November 2025. VpnGw1AZ is the current-generation choice.

VPN Gateway creation failing validation?

Confirm the subnet in vnet-b is named exactly GatewaySubnet. Any other name will cause the deployment to fail.

Make sure the public IP pip-vpngw is Standard SKU and in the same region (East US 2) as the VNet.

Help me troubleshoot my VPN Gateway creation error.

Record the VPN Gateway public IP

Once the VPN Gateway finishes provisioning (check back after completing Steps 2-3), you will need its public IP address to configure the FortiGate tunnel.

  • After the deployment completes, navigate to your Resource Group rg-vpn-lab.
  • Click on pip-vpngw in the resource list.
  • On the Overview page, find the IP address field and note this value down.

Save this IP for later

You will need the pip-vpngw public IP address in Step 5 when configuring the FortiGate Phase 1 remote gateway. Write it down or keep the tab open.

Your Azure foundation is in place. The VPN Gateway is provisioning in the background. Next up, you will build the simulated on-premises network with a FortiGate firewall while you wait.

Deploy VNet A and FortiGate VM

Your VPN Gateway is provisioning in the background. That 30-45 minute wait is the perfect window to build the other side of the tunnel.

In this step, you will create VNet A to simulate an on-premises network. You will also deploy a FortiGate Next-Generation Firewall VM into that network with a dual-NIC architecture, giving it one interface facing the internet and one facing the protected internal network.

In this step, get ready to:
  • Create VNet A with an external subnet and an internal subnet.
  • Deploy a FortiGate VM from the Azure Marketplace with dual-NIC networking.
  • Log into the FortiGate GUI and confirm both interfaces are operational.
Create VNet A with two subnets

VNet A represents the simulated on-premises network. It needs two subnets: one for the FortiGate's external (untrusted) interface where it terminates the IPsec tunnel, and one for the internal (trusted) interface that protects your on-premises resources.

  • In the Azure Portal, search for Virtual networks in the top search bar and select it.
  • Click Create.
  • Select your resource group rg-vpn-lab.
  • Enter vnet-a as the Name.
  • Set the Region to East US 2 (same region as your other resources).
  • Click Next to proceed to the Security tab. Leave defaults and click Next again to reach the IP addresses tab.
  • Delete any default address space, then add 10.0.0.0/16 as the address space.
  • Click Add a subnet. Enter sn-external as the name and 10.0.0.0/24 as the address range. Click Add.
  • Click Add a subnet again. Enter sn-internal as the name and 10.0.1.0/24 as the address range. Click Add.
  • Click Review + create, then click Create.

Why two subnets?

The sn-external subnet is the untrusted/WAN side where the FortiGate terminates the IPsec tunnel and faces the public internet. The sn-internal subnet is the trusted/LAN side where protected resources like test VMs sit behind the firewall.

This dual-subnet architecture mirrors how physical firewalls connect to separate network zones in a real data center.

Wait for the deployment to complete. You should see a Your deployment is complete message.

Seeing an address space conflict?

Make sure you deleted the default address space before adding 10.0.0.0/16. Azure does not allow overlapping address ranges within the same VNet.

Also confirm you are using 10.0.0.0/16 (not 10.1.0.0/16 which is already used by VNet B).

Help me resolve a VNet address space error in Azure Portal.

Deploy FortiGate VM from Azure Marketplace

The FortiGate Next-Generation Firewall is available in the Azure Marketplace with a pay-as-you-go plan that includes a 30-day free evaluation license. You will deploy it with two network interfaces to match the dual-subnet architecture you just created.

  • In the Azure Portal search bar, type FortiGate Next-Generation Firewall and select it from the Marketplace results.
  • Select the FortiGate Next-Generation Firewall single VM deployment option.
  • Choose the Pay As You Go (PAYG) plan and click Create.

What is the PAYG plan?

The Pay As You Go plan charges an hourly license fee (~$0.36/hr for 1 vCPU) on top of your VM compute costs. It includes a 30-day free evaluation period, so you will not be charged for the license if you tear down the lab today.

Now configure the VM basics:

  • Set Resource group to rg-vpn-lab.
  • Enter fg-onprem as the Virtual machine name.
  • Set the Region to East US 2.
  • Select Standard_F2s (2 vCPU) as the Size.
  • Set an Admin username and a strong Password. Write these down. You will need them to log into the FortiGate GUI.

Next, configure the networking:

  • Click Next until you reach the Networking tab.
  • For Virtual network, select vnet-a.
  • For the port1 (external) NIC, select subnet sn-external. This interface will receive private IP 10.0.0.4.
  • Create a new public IP for port1. Name it pip-fortigate with Standard SKU and static allocation.
  • For the port2 (internal) NIC, select subnet sn-internal. This interface will receive private IP 10.0.1.4. Do not assign a public IP to port2.

Why does FortiGate get IP .4 and not .1?

Azure reserves the first four IPs (.0, .1, .2, .3) and the last IP in every subnet for internal platform use. The first IP available for your resources is always .4.

  • Click Review + create, review the summary, then click Create.
  • Wait for the deployment to complete. This takes approximately 5 minutes.

You should see the Your deployment is complete message once the FortiGate VM finishes provisioning.

Deployment failed or quota error?

If you see a quota error for the Standard_F2s size, your subscription may have reached its vCPU limit in East US 2. Try selecting a different region for all resources, or request a quota increase under Subscription > Usage + quotas.

If the Marketplace offer cannot be found, ensure your subscription type supports Marketplace purchases (free trial subscriptions sometimes restrict this).

Help me troubleshoot a FortiGate Marketplace deployment failure in Azure.

Connect to FortiGate GUI and verify interfaces

The FortiGate VM exposes a web-based management interface on its public IP. You will log in and confirm both network interfaces are up before configuring the IPsec tunnel in a later step.

  • In the Azure Portal, navigate to Resource groups > rg-vpn-lab.
  • Click on the public IP resource pip-fortigate and copy the IP address value displayed on the Overview page.
  • Open a new browser tab and navigate to https:// followed by the IP address you just copied.
  • Your browser will show a certificate warning because the FortiGate uses a self-signed certificate. Click Advanced and then Proceed (or equivalent) to continue.
  • Log in with the admin username and password you set during deployment.

You should see the FortiGate dashboard after a successful login.

Now verify the interfaces:

  • In the left sidebar, click Network > Interfaces.
  • Confirm that port1 shows IP 10.0.0.4 and is in the up state.
  • Confirm that port2 shows IP 10.0.1.4 and is in the up state.
  • Write down the public IP of pip-fortigate (the one you used to access the GUI). You will need this value when creating the Azure Local Network Gateway in Step 4.

What does each interface do?

Port1 (10.0.0.4) is the external/untrusted interface. It faces the internet, receives the public IP, and is where the IPsec tunnel will terminate.

Port2 (10.0.1.4) is the internal/trusted interface. It connects to the protected network where your test VMs will live. All traffic from internal VMs destined for Azure will pass through FortiGate on this interface.

Cannot reach the FortiGate GUI?

Make sure you are using https:// (not http://). The FortiGate management interface only responds on HTTPS (port 443).

Check that the Network Security Group on the port1 NIC allows inbound HTTPS (port 443) from your IP. The Marketplace deployment usually creates this rule automatically.

Help me troubleshoot FortiGate GUI access in Azure.

Your simulated on-premises network is now fully operational. The FortiGate is ready to terminate an IPsec tunnel on port1 and protect internal resources on port2. Next up, you will deploy the test VMs that will prove end-to-end connectivity through the tunnel.

Deploy Test VMs and Configure Network Security

Your FortiGate firewall is protecting VNet A and the VPN Gateway is still provisioning in the background. The tunnel itself is useless without endpoints that prove traffic actually flows through it.

In this step, you will deploy two test VMs, one on each side of the future tunnel. You will also lock down the Azure-side VM with Network Security Group rules so that only traffic arriving through the VPN tunnel can reach it.

In this step, get ready to:
  • Deploy Test VM A in VNet A's internal subnet behind FortiGate.
  • Deploy Test VM B in VNet B's VM subnet with a temporary public IP.
  • Configure NSG inbound rules on Test VM B to permit only tunnel-sourced traffic.
Deploy Test VM A in VNet A internal subnet

Test VM A simulates a workstation on the "on-premises" network, sitting behind FortiGate on the internal subnet. It has no public IP because all of its outbound traffic will route through the FortiGate firewall.

  • In the Azure Portal search bar, type Virtual machines and select Virtual machines from the results.
  • Click Create, then select Azure virtual machine.

Configure the Basics tab with the following settings:

  • Set Resource group to rg-vpn-lab.
  • Enter vm-test-a as the Virtual machine name.
  • Set Region to East US 2 (same as your resource group).
  • For Image, select a Windows Server image (e.g., Windows Server 2022 Datacenter).
  • Set Size to Standard_B2s.
  • Enter an admin username and password. Remember these for later access.

Now configure the Networking tab:

  • Click the Networking tab at the top of the creation page.
  • Set Virtual network to your VNet A.
  • Set Subnet to sn-internal (10.0.1.0/24).
  • Set Public IP to None.
  • Under NIC network security group, select Basic. Leave the default which allows RDP inbound from the VNet.

You need to assign a static private IP so the address does not change between reboots:

  • Still on the Networking tab, click the NIC's IP configuration link (or click Edit network interface).
  • Change Private IP address allocation from Dynamic to Static.
  • Enter 10.0.1.10 as the private IP address.
  • Click Review + create, then click Create.
  • Wait for deployment to complete (approximately 2-3 minutes).

Why no public IP on Test VM A?

In a real on-premises network, workstations do not have public internet addresses. All their traffic exits through the firewall. By giving Test VM A no public IP, you are simulating this architecture accurately.

You will access this VM later through Azure Serial Console or via the FortiGate.

Can't find sn-internal in the subnet dropdown?

Make sure you selected the correct Virtual network (VNet A, not VNet B). The subnet list only shows subnets belonging to the selected VNet.

Help me find my sn-internal subnet when creating a VM in Azure.

Deploy Test VM B in VNet B VM subnet

Test VM B sits on the Azure cloud side. It represents a resource that your on-premises workstation needs to reach through the encrypted tunnel.

  • Navigate back to Virtual machines and click Create, then Azure virtual machine.

Configure the Basics tab:

  • Set Resource group to rg-vpn-lab.
  • Enter vm-test-b as the Virtual machine name.
  • Set Region to East US 2.
  • For Image, select the same Windows Server image you used for Test VM A.
  • Set Size to Standard_B2s.
  • Enter an admin username and password.

Configure the Networking tab:

  • Click the Networking tab.
  • Set Virtual network to your VNet B.
  • Set Subnet to sn-vnetb-vms (10.1.1.0/24).
  • Leave Public IP set to create a new one. This temporary public IP lets you RDP in for validation later.
  • Under NIC network security group, select Basic.

Assign a static private IP just like you did for Test VM A:

  • Click the NIC's IP configuration link or Edit network interface.
  • Change Private IP address allocation to Static.
  • Enter 10.1.1.10 as the private IP address.
  • Click Review + create, then click Create.
  • Wait for deployment to complete.

Once both VMs finish deploying, confirm their private IPs in the Azure Portal. Navigate to each VM's Overview page and verify vm-test-a shows 10.0.1.10 and vm-test-b shows 10.1.1.10.

VM deployment failed?

Check that your subscription has quota for Standard_B2s VMs in the East US 2 region. Navigate to Subscriptions > your subscription > Usage + quotas to verify available vCPU capacity.

Help me troubleshoot my Azure VM deployment failure.

Configure NSG on Test VM B for tunnel traffic

Right now, Test VM B's NSG only allows RDP from any source. You need to tighten this so that only traffic arriving from the FortiGate protected network (10.0.1.0/24) can reach it. This ensures your validation traffic actually proves it traversed the tunnel.

  • In the Azure Portal, navigate to vm-test-b.
  • In the left menu, click Networking, then Network settings.
  • Click on the NSG name linked to the VM's network interface.
  • In the NSG blade, click Inbound security rules in the left menu.
  • Click Add to create the first rule.

Configure the ICMP allow rule with these settings:

  • Set Source to IP Addresses.
  • Enter 10.0.1.0/24 in the Source IP addresses/CIDR ranges field.
  • Set Destination to Any.
  • Set Service to Custom.
  • Set Protocol to ICMP.
  • Set Action to Allow.
  • Set Priority to 100.
  • Enter Allow-ICMP-From-OnPrem as the Name.
  • Click Add.

Now add the second rule for RDP traffic. Click Add again to create another inbound rule:

  • Set Source to IP Addresses.
  • Enter 10.0.1.0/24 in the Source IP addresses/CIDR ranges field.
  • Set Destination to Any.
  • Set Service to Custom.
  • Set Protocol to TCP.
  • Set Destination port ranges to 3389.
  • Set Action to Allow.
  • Set Priority to 110.
  • Enter Allow-RDP-From-OnPrem as the Name.
  • Click Add.

Why restrict by source IP?

These NSG rules only allow traffic from 10.0.1.0/24, which is the FortiGate internal subnet. When traffic arrives at Test VM B from this range, it proves the packets traversed the IPsec tunnel. Without this restriction, you could not be certain that connectivity was actually flowing through the VPN.

Verify the rules are in place by reviewing the Inbound security rules list. You should see your two new rules (priority 100 and 110) listed alongside the default rules.

Rules not appearing in the list?

Make sure you are viewing the correct NSG. If you created the NSG at the subnet level rather than the NIC level, navigate to Virtual networks > VNet B > Subnets > sn-vnetb-vms to find the associated NSG.

Help me locate my NSG rules for vm-test-b.

Your test endpoints are ready on both sides of the tunnel. Next up, you will configure the Azure VPN connection objects that tell the VPN Gateway how to reach your FortiGate.

Configure Azure-Side VPN Connection

Your test VMs are deployed and your network security rules are in place. Now it is time to connect the two sides of your lab together.

The VPN Gateway you deployed in Step 1 should now be fully provisioned. In this step, you will create the Azure-side connection objects that tell the gateway where to find the FortiGate and what encryption parameters to use for the tunnel.

In this step, get ready to:
  • Create a Local Network Gateway representing the FortiGate as the remote device.
  • Create a site-to-site VPN connection with a custom IPsec/IKE policy.
  • Verify the connection status and record the exact crypto parameters for FortiGate configuration.
Create the Local Network Gateway

A Local Network Gateway is an Azure resource that represents the remote (on-premises) VPN device. It tells Azure the public IP of the remote device and which address ranges sit behind it.

  • In the Azure Portal search bar, type Local network gateways and select the result.
  • Click Create.
  • Select your subscription and resource group rg-vpn-lab.
  • Set the region to East US 2.
  • Enter lng-fortigate-onprem as the name.
  • For Endpoint, select IP address.
  • In the IP address field, enter the public IP address of your FortiGate port1 (pip-fortigate). This is the IP you recorded in Step 2.
  • Under Address space, enter 10.0.1.0/24. This is the FortiGate protected network that Azure needs to know is reachable through the tunnel.
  • Click Review + create, then click Create.

Why does the Local Network Gateway need an address space?

The address space tells Azure which IP ranges live behind the remote device. When the VPN Gateway receives traffic destined for 10.0.1.0/24, it knows to route that traffic through the IPsec tunnel to the FortiGate.

Without this address space, Azure has no way to know that the subnet behind FortiGate is reachable through this connection.

The deployment takes about 30 seconds. Wait for the notification confirming the Local Network Gateway was created successfully.

Deployment failed?

Make sure the IP address you entered is the actual public IP of pip-fortigate, not the private IP 10.0.0.4. You can find the public IP by navigating to pip-fortigate in your resource group.

help me troubleshoot my Local Network Gateway deployment failure

Create the VPN connection with a custom IPsec/IKE policy

The connection object links your VPN Gateway to the Local Network Gateway and defines the exact encryption parameters both sides must use. When you specify a custom IPsec/IKE policy, the Azure VPN Gateway will only accept that exact proposal with no fallback negotiation.

  • In the Azure Portal search bar, type Virtual network gateways and select your VPN Gateway.
  • In the left menu, click Connections.
  • Click Add.
  • Enter a name for the connection (e.g., conn-to-fortigate).
  • Set Connection type to Site-to-site (IPsec).
  • For Local network gateway, select lng-fortigate-onprem.
  • In the Shared key (PSK) field, enter VPNLab2026SecureKey!. You will enter this exact same key on the FortiGate side later.

What is a pre-shared key?

A pre-shared key (PSK) is a secret string that both sides of the VPN tunnel must know before the connection can establish. It proves identity during IKE Phase 1 negotiation. If the keys do not match exactly, the tunnel will never come up.

Now configure the custom IPsec/IKE policy. This is the most important part of the connection setup.

  • Scroll down to the IKE protocol section.
  • Set IKE Version to IKEv2.
  • Under IPsec / IKE policy, select Custom.

Configure the IKE Phase 1 (Main Mode) parameters:

  • Set IKE Phase 1 Encryption to AES256.
  • Set IKE Phase 1 Integrity to SHA256.
  • Set DH Group to DHGroup2.

Configure the IPsec Phase 2 (Quick Mode) parameters:

  • Set IPsec Encryption to AES256.
  • Set IPsec Integrity to SHA256.
  • Set PFS Group to None.
  • Set SA Lifetime (seconds) to 27000.
  • Set SA Lifetime (KB) to 102400000.
  • Set DPD timeout (seconds) to 45.
  • Click OK or Review + create, then click Create.

Why do these parameters matter so much?

When you specify a custom IPsec/IKE policy, the Azure VPN Gateway will only send and accept that exact cryptographic proposal. There is no fallback negotiation. If the FortiGate proposes different algorithms or lifetimes, the tunnel will fail to establish.

This is why you must record these values precisely. You will configure the FortiGate with matching parameters in the next step.

Write down the PSK and policy values

Keep a note of the pre-shared key (VPNLab2026SecureKey!) and all six custom policy parameters. You will need to enter each one on the FortiGate side in Step 5. Even one mismatched value will prevent the tunnel from coming up.

Verify connection status

The connection is now created, but the tunnel is not yet established. The FortiGate side has not been configured yet, so Azure has no peer to negotiate with.

  • Navigate back to your Virtual Network Gateway.
  • Click Connections in the left menu.
  • Confirm the connection you just created appears in the list.
  • Verify the Status column shows Connecting. This is expected. The status will change to Connected once you configure the FortiGate tunnel in the next step.
  • Click on the connection name and confirm the Overview blade shows the VPN Gateway status as Succeeded.

What should I see?

Your connection details page should show the connection type as IPsec, the status as Connecting, and the linked Local Network Gateway as lng-fortigate-onprem. The custom policy parameters you set are visible under the connection's Configuration blade.

Connection shows Unknown or Not connected?

If the status shows anything other than Connecting, check that your Local Network Gateway IP matches the FortiGate port1 public IP exactly. Also confirm you selected the correct Local Network Gateway when creating the connection.

help me troubleshoot my Azure VPN connection status

The Azure side of your tunnel is fully configured and waiting for a peer. Next up, you will configure the FortiGate to establish the IPsec tunnel back to Azure and bring the connection online.

Configure FortiGate-Side IPsec Tunnel

The Azure VPN Gateway is waiting for someone to answer on the other end of the line. Right now your VPN Connection shows "Connecting" because the FortiGate hasn't been told to initiate or accept the tunnel yet.

In this step, you will configure the FortiGate side of the IPsec tunnel with matching crypto parameters, create firewall policies to permit tunnel traffic, and set up routing so that traffic from the internal subnet reaches Azure through the tunnel.

In this step, get ready to:
  • Create an IKEv2 IPsec tunnel on FortiGate with Phase 1 and Phase 2 proposals matching Azure.
  • Build firewall policies permitting bidirectional traffic through the tunnel.
  • Configure routing and IP forwarding so traffic flows from the internal subnet through FortiGate into the tunnel.
Create the IPsec Phase 1 and Phase 2 tunnel

An IKEv2 tunnel negotiates in two phases. Phase 1 establishes a secure channel between the two gateways (authentication and key exchange). Phase 2 negotiates the actual encryption parameters for user traffic.

Why must parameters match exactly?

When you set a custom IPsec/IKE policy on the Azure VPN Gateway, it sends ONLY that exact proposal during negotiation. There is no fallback. If the FortiGate proposes different algorithms or lifetimes, the tunnel will never come up.

  • In the FortiGate GUI, navigate to VPN in the left sidebar.
  • Click IPsec Tunnels.
  • Click Create New.
  • Select Custom (not the wizard template).

Configure the Phase 1 settings as follows:

  • Enter azure-vpngw in the Name field.
  • Set Remote Gateway to the public IP of your VPN Gateway (the pip-vpngw address you recorded earlier).
  • Set Interface to port1.
  • Set IKE Version to 2.
  • Set Authentication Method to Pre-shared Key.
  • Enter VPNLab2026SecureKey! in the Pre-shared Key field. This must match the PSK you set on the Azure VPN Connection.

Now configure the Phase 1 Proposal settings:

  • Set Encryption to AES256.
  • Set Authentication to SHA256.
  • Set DH Group to 2.
  • Set Key Lifetime (seconds) to 28800.

Why 28800 for Phase 1?

Azure VPN Gateways use a fixed IKE Main Mode SA lifetime of 28,800 seconds. This value is not configurable on the Azure side, so FortiGate must match it exactly.

Scroll down to the Phase 2 Selectors section and configure it:

  • Enter azure-vpngw-p2 in the Name field.
  • Set Local Address to 10.0.1.0/24 (the FortiGate protected subnet).
  • Set Remote Address to 10.1.0.0/16 (the entire VNet B address space).

Configure the Phase 2 Proposal:

  • Set Encryption to AES256.
  • Set Authentication to SHA256.
  • Disable Perfect Forward Secrecy (PFS) by setting it to No PFS or unchecking the option.
  • Set Key Lifetime (seconds) to 27000.
  • Click OK to save the tunnel configuration.

You should now see the azure-vpngw tunnel listed under VPN > IPsec Tunnels. Its status will show as down until both firewall policies and routing are configured.

Don't see the tunnel listed?

Make sure you selected Custom when creating the tunnel. The wizard templates may name the tunnel differently or apply incompatible defaults.

Verify you clicked OK at the bottom of the form. If the page refreshed without saving, re-enter your settings.

Help me troubleshoot my FortiGate IPsec tunnel creation

Create address objects and firewall policies

FortiGate firewall policies reference named address objects instead of raw IP ranges. You need two objects representing each side of the tunnel, then two policies permitting traffic in both directions.

  • In the FortiGate GUI, navigate to Policy & Objects in the left sidebar.
  • Click Addresses.
  • Click Create New.
  • Enter net-azure-vnetb in the Name field.
  • Set Type to Subnet.
  • Enter 10.1.0.0/16 as the subnet.
  • Click OK.
  • Click Create New again to create the second address object.
  • Enter net-onprem-internal in the Name field.
  • Set Type to Subnet.
  • Enter 10.0.1.0/24 as the subnet.
  • Click OK.

Now create the outbound firewall policy (on-prem to Azure):

  • Navigate to Policy & Objects > Firewall Policy.
  • Click Create New.
  • Set Incoming Interface to port2 (the internal/trusted interface).
  • Set Outgoing Interface to azure-vpngw (the IPsec tunnel interface).
  • Set Source to net-onprem-internal.
  • Set Destination to net-azure-vnetb.
  • Set Action to Accept.
  • Disable NAT by toggling it off.
  • Enable Log Allowed Traffic (set to All Sessions). You will use these logs to verify tunnel traffic in the next step.
  • Click OK.

Why disable NAT on tunnel policies?

IPsec Phase 2 selectors define which source and destination IP ranges are allowed through the tunnel. If NAT is enabled, FortiGate translates the source IP before sending traffic into the tunnel. The translated IP won't match the Phase 2 selector, so the packet gets dropped.

NAT must always be disabled on firewall policies that handle IPsec tunnel traffic.

Now create the inbound firewall policy (Azure to on-prem):

  • Click Create New again in the Firewall Policy list.
  • Set Incoming Interface to azure-vpngw (traffic arriving from the tunnel).
  • Set Outgoing Interface to port2.
  • Set Source to net-azure-vnetb.
  • Set Destination to net-onprem-internal.
  • Set Action to Accept.
  • Disable NAT.
  • Enable Log Allowed Traffic (set to All Sessions).
  • Click OK.

You should now see two new firewall policies in the list. One permits outbound traffic from port2 to the tunnel, and the other permits inbound traffic from the tunnel to port2.

Don't see azure-vpngw as an interface option?

The tunnel interface only appears after the IPsec tunnel is successfully created in the previous substep. Go back to VPN > IPsec Tunnels and confirm azure-vpngw is listed there.

Help me troubleshoot missing tunnel interface in FortiGate firewall policy

Create a static route and enable IP forwarding

Even with the tunnel and firewall policies in place, traffic won't flow yet. You need to tell FortiGate where to send packets destined for VNet B. You also need to tell Azure that FortiGate is allowed to forward packets that aren't addressed to its own IP.

First, create a static route on FortiGate pointing VNet B traffic into the tunnel:

  • In the FortiGate GUI, navigate to Network > Static Routes.
  • Click Create New.
  • Set Destination to 10.1.0.0/16.
  • Set Interface to azure-vpngw.
  • Set Administrative Distance to 10.
  • Click OK.

What is IP forwarding?

Azure drops any packet arriving at a NIC that isn't addressed to that NIC's own IP. This is a security default. Since FortiGate acts as a router (forwarding packets from Test VM A to the tunnel), Azure needs to be told to allow this behavior on both NICs.

Next, enable IP forwarding on both FortiGate NICs in the Azure Portal:

  • Switch to the Azure Portal in your browser.
  • Search for Network interfaces in the top search bar.
  • Click the NIC associated with FortiGate port1 (the one in sn-external with IP 10.0.0.4).
  • In the left menu, click IP configurations.
  • Set IP forwarding to Enabled.
  • Click Save.
  • Go back to Network interfaces and click the NIC associated with FortiGate port2 (the one in sn-internal with IP 10.0.1.4).
  • Click IP configurations in the left menu.
  • Set IP forwarding to Enabled.
  • Click Save.

Why do both NICs need IP forwarding?

Traffic arrives at port2 (internal NIC) from Test VM A, gets processed by FortiGate, and exits through port1 (external NIC) into the IPsec tunnel. Both the receiving and sending NIC must have IP forwarding enabled for the end-to-end path to work.

Finally, create a User-Defined Route table to steer traffic from the internal subnet through FortiGate:

  • In the Azure Portal, search for Route tables in the top search bar.
  • Click Create.
  • Select your resource group rg-vpn-lab.
  • Enter rt-internal as the name.
  • Select the same region as your other resources (East US 2).
  • Click Review + create, then Create.

Once the route table is created, add a route to it:

  • Open the rt-internal route table.
  • In the left menu, click Routes.
  • Click Add.
  • Enter a route name (e.g. to-azure-vnetb).
  • Set Destination type to IP Addresses.
  • Enter 10.1.0.0/16 as the destination IP address.
  • Set Next hop type to Virtual appliance.
  • Enter 10.0.1.4 as the next hop address (FortiGate port2 internal IP).
  • Click Add.

Now associate the route table with the internal subnet:

  • In the rt-internal route table, click Subnets in the left menu.
  • Click Associate.
  • Select VNet A as the Virtual network.
  • Select sn-internal as the Subnet.
  • Click OK.

Why is a route table needed?

Without this route table, Test VM A has no path to 10.1.0.0/16. The two VNets are not peered, so Azure's default routing has no entry for VNet B. The UDR overrides default routing and forces traffic through FortiGate (10.0.1.4), which then sends it through the IPsec tunnel.

Verify the route table shows the route associated with sn-internal under the Subnets blade.

Route table not showing the subnet association?

Make sure you selected the correct VNet (VNet A, not VNet B) when associating. The sn-internal subnet lives in VNet A.

If sn-internal doesn't appear in the dropdown, check that the route table is in the same region as VNet A.

Help me troubleshoot my Azure route table association

Your FortiGate-side configuration is complete. The IPsec tunnel, firewall policies, static route, IP forwarding, and UDR are all in place. Next up, you will bring the tunnel online and validate end-to-end connectivity between the two test VMs.

Validate Tunnel and End-to-End Connectivity

You have configured both sides of the IPsec tunnel with matching crypto parameters, firewall policies, and routing. The real test is whether encrypted traffic actually flows between your two networks.

In this step, you will confirm the tunnel is established, prove end-to-end connectivity with a ping test, and demonstrate active policy enforcement by running a controlled deny test. This validation sequence is how network engineers verify VPN deployments in production.

In this step, get ready to:
  • Verify the IPsec tunnel is up on both FortiGate and Azure.
  • Test end-to-end connectivity by pinging across the tunnel.
  • Prove active policy enforcement with a controlled deny test.
Verify tunnel status on both sides

Both sides of the tunnel must show an established state before any traffic can flow. You will check the FortiGate GUI, the FortiGate CLI, and the Azure Portal to confirm the tunnel is active.

  • In the FortiGate GUI, navigate to VPN > IPsec Tunnels.
  • Locate the azure-vpngw tunnel. The status indicator should show green (up) with both Phase 1 and Phase 2 established.
  • If the tunnel shows as down, click the tunnel name and select Bring Up to initiate the connection.

Now confirm the tunnel via CLI for deeper diagnostic detail. In the FortiGate GUI, open the CLI console (the >_ icon in the top toolbar).

  • Check the IKE gateway status by running this command:
diagnose vpn ike gateway list
  • You should see output showing the azure-vpngw gateway with a status of established and the remote gateway IP matching your VPN Gateway public IP.
  • Check the IPsec tunnel list by running this command:
diagnose vpn tunnel list
  • You should see the Phase 2 selector showing source 10.0.1.0/24 and destination 10.1.0.0/16 with an active SA (Security Association).

What do these CLI commands show?

The diagnose vpn ike gateway list command shows Phase 1 (IKE) status. It confirms the two gateways have authenticated each other and agreed on encryption parameters.

The diagnose vpn tunnel list command shows Phase 2 (IPsec) status. It confirms the traffic selectors (which subnets can communicate) and that encryption keys have been negotiated for actual data flow.

Now verify the Azure side matches.

  • In the Azure Portal, navigate to your Virtual Network Gateway.
  • Click Connections in the left menu.
  • The connection status should now show Connected (previously it showed "Connecting").

Still showing "Connecting"?

If the Azure connection remains in "Connecting" state after the FortiGate tunnel shows up, check these common causes:

  • PSK mismatch. Verify the pre-shared key is exactly VPNLab2026SecureKey! on both sides.
  • Phase 1/Phase 2 parameter mismatch. Azure custom policies require an exact match with no negotiation fallback. Verify AES256/SHA256/DHGroup2 on both sides and that PFS is disabled on both.
  • Local Network Gateway IP mismatch. The IP in lng-fortigate-onprem must match the public IP of FortiGate port1 (pip-fortigate).
  • SA lifetime mismatch. Phase 1 must be 28800 seconds and Phase 2 must be 27000 seconds.

My tunnel is still not coming up after checking all parameters.

Test end-to-end connectivity

A green tunnel status means the gateways have agreed on encryption parameters. The true test is whether a packet from vm-test-a (10.0.1.10) can travel through FortiGate, enter the encrypted tunnel, exit at the Azure VPN Gateway, and reach vm-test-b (10.1.1.10).

  • You need to access vm-test-a's command prompt. Since vm-test-a has no public IP, use Azure Serial Console.
  • In the Azure Portal, navigate to Virtual machines and select vm-test-a.
  • In the left menu, scroll down to Help and click Serial console.
  • Once the console loads, press Enter to get a login prompt. Log in with the admin credentials you set during VM creation.
  • Open a command prompt (type cmd and press Enter if you see a PowerShell or SAC prompt).
  • Run the ping test by entering this command:
ping 10.1.1.10
  • You should see successful ICMP replies from 10.1.1.10 with response times.

What is the ping proving?

This single ping validates the entire chain: vm-test-a sends a packet to 10.1.1.10, the UDR on sn-internal routes it to FortiGate (10.0.1.4), FortiGate's firewall policy permits it, FortiGate encrypts it via the IPsec tunnel, the Azure VPN Gateway decrypts it, and the NSG on vm-test-b allows it through.

If any single component in this chain is misconfigured, the ping fails. A successful reply proves every layer is working correctly.

Ping timing out?

  • Check the FortiGate firewall policies have logging enabled. Navigate to Policy & Objects > Firewall Policy and verify the outbound policy shows accepted sessions (not zero).
  • Verify the UDR on sn-internal. Go to rt-internal and confirm the route to 10.1.0.0/16 has next hop 10.0.1.4 (FortiGate port2).
  • Check the NSG on vm-test-b allows ICMP from 10.0.1.0/24. If you only allowed specific IPs instead of the /24 range, the traffic may be blocked.
  • Confirm IP forwarding is enabled on both FortiGate NICs in the Azure Portal. Azure drops routed traffic on NICs without this setting.

Help me troubleshoot why my ping from vm-test-a to vm-test-b is failing.

Review traffic logs and test controlled deny

A successful ping proves connectivity, but production environments require proof that the firewall is actively enforcing policy. You will review FortiGate's traffic logs and then temporarily disable a policy to prove FortiGate controls what crosses the tunnel.

  • In the FortiGate GUI, navigate to Log & Report > Forward Traffic.
  • Add a filter for destination 10.1.1.10.
  • Confirm you see log entries with action accept and the outgoing interface showing the tunnel interface (azure-vpngw).

What do the logs confirm?

The logs show FortiGate actively inspecting and permitting each packet before it enters the tunnel. The action field proves the traffic matched your outbound firewall policy. Without that policy, FortiGate's implicit deny would block the traffic.

Now perform the controlled deny test. This proves FortiGate is the enforcement point, not just a passthrough.

  • Navigate to Policy & Objects > Firewall Policy.
  • Find your outbound policy (source port2/net-onprem-internal, destination net-azure-vnetb, outgoing interface azure-vpngw).
  • Right-click the policy and select Disable.
  • Return to the vm-test-a Serial Console and run the ping again:
ping 10.1.1.10
  • The ping should now fail with "Request timed out" or no replies. FortiGate's implicit deny is blocking the traffic because no policy permits it.

Now re-enable the policy to restore connectivity.

  • Return to Policy & Objects > Firewall Policy.
  • Right-click the disabled outbound policy and select Enable.
  • Run the ping from vm-test-a again:
ping 10.1.1.10
  • Successful ICMP replies should resume, confirming the policy is back in effect.

Why does the controlled deny test matter?

In security audits and compliance reviews, you need to prove that your firewall is actively enforcing policy on tunnel traffic. A successful ping alone could mean the firewall is in a permissive state. The deny-then-allow cycle proves FortiGate is the decision point for all cross-tunnel communication.

Your site-to-site IPsec VPN is fully validated. You have proven encrypted connectivity between networks and demonstrated active firewall enforcement on tunnel traffic.

Secret mission

Add BGP Dynamic Routing Over the Tunnel

Your IPsec tunnel works, but it relies on static routes. Every time a new subnet is added to either network, someone has to manually update route tables on both sides. In production environments, this is a recipe for outages and configuration drift. Replace static routing with BGP to make route advertisement automatic.

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 Azure resources that cost approximately $0.80/hr while running.

Cost warning

Your VPN Gateway alone costs ~$0.21/hr and charges even when idle. The FortiGate VM adds ~$0.46/hr (license + compute). If you leave everything running overnight, you could accumulate $15-20 in charges.

For a single-day lab, deleting the entire Resource Group is the safest way to stop all charges immediately.

Resources you used:

  • Resource Group (rg-vpn-lab).
  • VPN Gateway (VpnGw1AZ) with public IP (pip-vpngw).
  • FortiGate VM (fg-onprem) with public IP (pip-fortigate).
  • Test VM A (vm-test-a) in VNet A.
  • Test VM B (vm-test-b) in VNet B with public IP.
  • VNet A (10.0.0.0/16) with external and internal subnets.
  • VNet B (10.1.0.0/16) with GatewaySubnet and VM subnet.
  • Local Network Gateway (lng-fortigate-onprem).
  • Route Table (rt-internal) with User-Defined Route.
  • Network Security Groups on test VMs.

Keep everything running

No action needed. Choose this if you are still actively testing your VPN tunnel or plan to extend the lab with the Secret Mission.

  • All resources remain active and billing continues at ~$0.80/hr.
  • Your IPsec tunnel stays established and you can continue running connectivity tests.
  • Monitor your Azure Cost Management to track spending.

Pause - I'll come back to this later

Shut down the VMs to save compute costs while keeping the network infrastructure intact. The VPN Gateway continues to charge even when VMs are stopped.

  • In the Azure Portal, navigate to each VM (fg-onprem, vm-test-a, vm-test-b).
  • Click Stop on each VM to deallocate it.
  • Confirm the status changes to Stopped (deallocated) for each VM.
  • The VPN Gateway (~$0.21/hr) and public IPs still incur charges while the VMs are stopped.
  • To resume, start each VM and verify the IPsec tunnel re-establishes (you may need to bring the tunnel up manually in FortiGate).

Delete - I don't want to use this again

Remove all project resources and stop all charges immediately. This is recommended for a single-day lab.

  • In the Azure Portal, navigate to Resource Groups.
  • Select rg-vpn-lab.
  • Click Delete resource group.
  • Type the resource group name rg-vpn-lab to confirm deletion.
  • Click Delete to remove all resources.
  • This permanently removes the VPN Gateway, FortiGate VM, test VMs, virtual networks, route tables, and all associated resources.

That's a Wrap!

That's a Wrap!

Nice work! You just built a production-grade site-to-site IPsec VPN between a FortiGate VM and an Azure VPN Gateway.

This is exactly the kind of hybrid connectivity you configure in real network and cloud security roles. Here's what you accomplished:

  • Deployed a dual-NIC FortiGate VM and an Azure VPN Gateway (VpnGw1AZ) with a custom IPsec/IKE policy specifying AES256/SHA256/DHGroup2.
  • Configured matching IKEv2 Phase 1/Phase 2 parameters on both sides with pre-shared key authentication and brought the tunnel up.
  • Validated end-to-end encrypted connectivity between test VMs and proved active firewall policy enforcement with a controlled deny test.
  • Secret Mission: Added BGP dynamic routing over the IPsec tunnel for automatic route advertisement.

Ready to quiz yourself?