Build Active-Active Azure FortiGate VPN
Configure and validate dual IPsec tunnels between Azure and FortiGate.
Introduction
30 Second Summary
A green status alone cannot prove that an important connection has a working backup. Confidence comes from watching traffic continue after one path breaks.
In this project, you will build an active-active site-to-site VPN that links a Microsoft Azure workload network to a branch network protected by a FortiGate-VM. You will prove private traffic crosses both IPsec tunnels.
What You'll Build
Picture opening FortiGate IPsec Monitor to show two live tunnels while a private TCP test succeeds between two isolated Windows Server test VMs.
By the end of this project, you'll have:
- Private connectivity you can prove with a successful TCP test from vm-azure to vm-branch over port 3389.
- Two live tunnel paths visible in FortiGate IPsec Monitor as to-az-gw1 and to-az-gw2.
- An evidence pack showing successful traffic, Azure byte counters, FortiGate tunnel health, and the protected subnet route.
- Secret Mission: Introduce a wrong pre-shared key on to-az-gw2. Prove to-az-gw1 keeps private traffic moving. Restore both tunnels to a healthy state.
Are there any prerequisites?
You'll need a modern web browser and an active Microsoft Azure subscription with permission to create networking and compute resources.
You will manage both test VMs through Azure Run Command, so no Azure Bastion or Remote Desktop client is required.
Before We Start
Before We Start...
This checkpoint helps you commit to the active-active VPN lab before the hands-on work begins. You will define what you are building and why proving two live tunnels matters for redundancy and failover.
Verify Access and Lock the Lab Plan
Your active-active VPN lab depends on permission to create resources in the Microsoft Azure portal. It also depends on access to the Fortinet FortiGate Next-Generation Firewall Marketplace plan.
This step checks those gates before anything billable exists. You will also lock a non-overlapping address plan so every later route has one clear destination.
In this step, get ready to:
- Verify the cloud deployment gates for East US.
- Confirm the browser-based VM management requirements.
- Record the fixed resource names and address plan.
Verify Azure and Marketplace access
The Marketplace checks your subscription. It also checks the deployment region.
This eligibility check stops before deployment. No FortiGate instance starts here, so the plan does not begin billing.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open system search.
- Type the name of a supported browser, such as Microsoft Edge, Chrome, Firefox, or Safari.
- Press Enter to open the browser.
- Open the Microsoft Azure portal.
- Sign in with the Azure account for your intended subscription.
- Choose your intended subscription using the portal's subscription selector.
You should see the portal scoped to the subscription you intend to use for the lab.
- Start the resource-group creation workflow from the portal.
- Select your intended subscription in the Subscription field.
- Enter rg-fgt-vpn-lab in the Resource group field.
- Select East US in the Region field.
- Continue until the portal validates the resource-group details.
- Confirm the form shows no permission error for your selected subscription.
- Cancel the workflow before creating the resource group.
What Did This Check Prove?
The portal accepted the planned resource-group name and East US region under your intended subscription. You have tested the access path without creating the lab.
- Search the Marketplace for Fortinet FortiGate Next-Generation Firewall.
- Open the Fortinet FortiGate Next-Generation Firewall listing.
Before you continue, do you expect the Marketplace to accept this subscription for a FortiGate deployment in East US?
- Select the Single VM plan.
- Continue to the Basics page.
- Choose your intended subscription in the Subscription field.
- Set the deployment region to East US.
You should remain on the Basics page without an eligibility error. This confirms that the subscription accepts the Single VM plan in East US.
Marketplace Plan Blocked?
Confirm that the intended subscription is still selected. Check that the region remains East US.
If the plan remains blocked, stop before deployment so no alternative product or region is introduced.
Ask for help to diagnose my Fortinet Marketplace eligibility issue.
Confirm the headless management path
Azure Run Command lets you execute PowerShell through the Azure control plane. Your browser sends the management request over HTTPS, so your device never opens an RDP session to either VM.
- Keep the Azure portal open in your supported browser.
- Plan to set Public inbound ports to None on both Windows VMs.
- Plan to attach a Standard public IP to each test VM for explicit outbound connectivity.
- Plan to add an AzureCloud route exception for vm-branch because the protected subnet sends its default traffic through FortiGate.
This design gives each VM an explicit outbound method without opening a public management port. The protected subnet also needs an AzureCloud route exception so vm-branch can return Run Command results without sending that traffic through FortiGate.
- Confirm your corporate network allows HTTPS browsing on TCP port 443.
- Confirm the Azure account shows the intended subscription in the portal header.
- Confirm your Azure role includes the Microsoft.Compute/virtualMachines/runCommand/action permission.
- Record that each VM's Properties page must show an Agent status of Ready before you use Run Command.
Your management path is now defined: Azure sends scripts through each VM agent, and the agents return their output over outbound HTTPS.
Run Command requirements unclear?
Run Command requires outbound connectivity from each VM to Azure public IP addresses over TCP port 443. A Standard public IP is an explicit outbound method, but the protected subnet also needs the planned AzureCloud route exception.
Your Azure role must include Microsoft.Compute/virtualMachines/runCommand/action. The Virtual Machine Contributor role and higher roles include this permission.
Help me verify my headless Azure management plan.
Record the fixed lab plan
The two network environments need distinct address spaces. The fixed names also keep every later route and connection easy to identify.
- Record the fixed lab plan by copying this block into your notes:
Resource group rg-fgt-vpn-lab in East US. vnet-azure: 10.10.0.0/16, with snet-workload: 10.10.1.0/24 and GatewaySubnet: 10.10.255.0/27. vnet-branch: 10.20.0.0/16, with snet-external: 10.20.0.0/24, snet-internal: 10.20.1.0/24, and snet-protected: 10.20.2.0/24. Planned resources are vng-azure, lng-fgt, conn-azure-fgt, FortiGate-VM, vm-azure, and vm-branch. Both Windows VMs use Standard public IPs as explicit outbound methods, with public inbound ports set to None. The protected-subnet route table includes an AzureCloud route exception with Internet as its next hop. VM tests run through Azure Run Command.
How Does the Address Plan Work?
- The 10.10.0.0/16 range contains the Azure workload subnet and GatewaySubnet.
- The 10.20.0.0/16 range contains the external, internal, and protected branch subnets.
- These non-overlapping CIDR ranges give each private destination a distinct side of the VPN.
- The fixed resource names make the gateway, connection, firewall, and test VMs easy to trace through the portal.
- Save the note.
- Confirm every planned resource name appears in your note.
- Confirm all seven address ranges match the reference.
- Confirm the note assigns a Standard public IP to each test VM and keeps public inbound ports closed.
- Confirm the note includes the AzureCloud route exception for the protected subnet.
✔️ Awesome, I've got everything!
Your saved plan now gives every later deployment a fixed name and an unambiguous network range.
ⓧ I'd like to double check the full code
Resource group rg-fgt-vpn-lab in East US. vnet-azure: 10.10.0.0/16, with snet-workload: 10.10.1.0/24 and GatewaySubnet: 10.10.255.0/27. vnet-branch: 10.20.0.0/16, with snet-external: 10.20.0.0/24, snet-internal: 10.20.1.0/24, and snet-protected: 10.20.2.0/24. Planned resources are vng-azure, lng-fgt, conn-azure-fgt, FortiGate-VM, vm-azure, and vm-branch. Both Windows VMs use Standard public IPs as explicit outbound methods, with public inbound ports set to None. The protected-subnet route table includes an AzureCloud route exception with Internet as its next hop. VM tests run through Azure Run Command.
Before you make the final check, do you expect the same subscription and region to remain accepted after completing the access checks?
- Switch back to the open Fortinet Marketplace Basics page.
- Confirm the Single VM plan remains selected.
- Confirm your intended subscription remains accepted.
- Confirm East US remains accepted without an eligibility error.
You should see the Single VM Basics page accept your subscription and East US region. No lab resource has been deployed.
That removes the planning risk: your access gates, browser-based management path, and network plan are ready. Next up, you will start the slow Azure deployments in parallel.
Start the Parallel Deployments
Your active-active lab depends on several billable resources in the Microsoft Azure portal. The slowest is the Azure VPN Gateway, which can take 45 minutes or more to provision.
Launching the gateway first turns that wait into build time. The FortiGate-VM and two Windows test machines can deploy in parallel.
In this step, get ready to:
- Create both virtual networks with their planned subnets.
- Launch the active-active Azure VPN gateway and FortiGate-VM deployments.
- Deploy both Windows test VMs and reach the FortiOS dashboard.
Launch the networks and VPN gateway
The two virtual networks represent separate Azure and branch environments. Their non-overlapping address spaces allow routing to distinguish local traffic from remote traffic.
These actions start hourly billing. The cleanup section removes the complete resource group when you finish the lab.
- Return to the Azure portal search bar from the previous step.
- Open Resource groups.
- Select Create.
- Confirm the intended subscription in the Subscription field.
- Enter rg-fgt-vpn-lab in the Resource group field.
- Select East US in the Region field.
- Select Review + create.
- Select Create after validation passes.
Good start. The rg-fgt-vpn-lab resource group now keeps every billable part of the lab under one cleanup boundary.
Why keep the address spaces separate?
The Azure environment uses 10.10.0.0/16. The branch environment uses 10.20.0.0/16.
These ranges never overlap. Each routing table can therefore identify which traffic needs the VPN.
- Return to the portal search bar.
- Open Virtual networks.
- Select Create.
- Enter vnet-azure as the virtual network name.
The creation form now identifies the Azure-side network. The remaining fields define where it lives and which workloads it contains.
- Select rg-fgt-vpn-lab as the resource group.
- Select East US as the region.
The network now shares the resource group's region. Its address configuration can use the fixed lab plan.
- Set the IPv4 address space to 10.10.0.0/16.
- Add snet-workload with subnet range 10.10.1.0/24.
The address view should now show the Azure workload subnet inside 10.10.0.0/16.
- Add GatewaySubnet with subnet range 10.10.255.0/27.
- Select Review + create.
Azure should validate two subnets with no overlapping ranges. The exact name GatewaySubnet reserves that subnet for the VPN gateway.
- Select Create.
You should see vnet-azure in rg-fgt-vpn-lab with both planned subnets.
- Return to Virtual networks.
- Select Create.
- Enter vnet-branch as the virtual network name.
- Select rg-fgt-vpn-lab as the resource group.
The second form now targets the branch network. This VNet holds the FortiGate interfaces and the protected Windows VM.
- Select East US as the region.
- Set the IPv4 address space to 10.20.0.0/16.
The address view should now show the branch range. Its three subnets divide public-facing traffic from protected workloads.
- Add snet-external with subnet range 10.20.0.0/24.
- Add snet-internal with subnet range 10.20.1.0/24.
The branch network now has separate external and internal transit subnets.
- Add snet-protected with subnet range 10.20.2.0/24.
- Select Review + create.
Azure should validate all three subnets inside 10.20.0.0/16.
- Select Create.
You should now see vnet-azure and vnet-branch in the resource group.
- Return to the portal search bar.
- Open Virtual network gateways.
- Select Create.
- Enter vng-azure as the gateway name.
The gateway form now targets the Azure side of the VPN. Its mode and public IP settings determine whether both gateway instances can carry traffic.
- Select East US as the region.
- Select VPN as the Gateway type.
The form should now display the VPN-specific configuration fields.
- Select Route-based as the VPN type.
- Select VpnGw1AZ as the gateway SKU.
The selected SKU supports route-based VPN and active-active mode. It also provides zone redundancy.
- Turn on Active-active mode.
- Select vnet-azure as the virtual network.
Azure should associate the gateway with GatewaySubnet inside vnet-azure.
- Create the first new public IP resource with Standard SKU and Static assignment.
- Create the second new public IP resource with Standard SKU and Static assignment.
The summary should now show two public IP configurations. Each active gateway instance receives its own public endpoint.
- Turn off BGP.
- Select Review + create.
This next click starts a billable gateway deployment. Expect provisioning to take 45 minutes or more while you build the rest of the lab.
- Select Create after validation passes.
You should see the vng-azure deployment in progress. Leave it running while you launch the remaining resources.
How does active-active work?
Each Azure gateway instance receives a unique public IP. Both instances belong to the same site-to-site connection.
Azure can send traffic over both tunnels simultaneously. It can also switch traffic away from an affected instance.
Deploy the FortiGate-VM
The FortiGate deployment uses an external subnet for public traffic. It uses an internal transit subnet to forward traffic toward the protected subnet.
Why use three branch subnets?
The external subnet carries traffic between the FortiGate and Azure's public network. The internal subnet provides the FortiGate's private forwarding path.
The protected subnet holds vm-branch. A route table sends its remote traffic through the FortiGate.
- Duplicate the Azure portal tab in Microsoft Edge.
- Return to the Fortinet FortiGate Next-Generation Firewall Marketplace listing from the previous step.
- Select the Single VM plan.
- Select Create.
The Marketplace form now creates a single FortiGate appliance inside the branch VNet. The gateway deployment continues in the other portal tab.
- Select Pay as you go as the licensing option.
- Select FortiOS 7.4.12 as the software version.
The form should now show the Pay as you go license and FortiOS 7.4.12. This release matches the workplace environment this lab mirrors, so stop if your subscription or region does not offer it.
- Select rg-fgt-vpn-lab as the resource group.
- Select East US as the region.
The FortiGate will deploy beside the other lab resources in East US.
- Enter FortiGate-VM as the deployment name.
- Select Standard_D2s_v5 as the VM size.
The selected size provides two virtual CPUs and enough memory for the FortiGate-VM lab.
The administrator password grants full control of the firewall. Treat it as a live credential and keep it out of screenshots.
- Enter an administrator username other than root, admin, or administrator.
- Create a unique administrator password with at least 12 characters.
The credential fields should now pass the Marketplace validation rules.
- Store the FortiGate administrator credentials securely.
- Select vnet-branch as the existing virtual network.
The network configuration should now offer the three branch subnets created earlier.
- Map the external subnet field to snet-external.
- Map the internal subnet field to snet-internal.
The appliance now has a public-facing path and a private transit path.
- Map the protected subnet field to snet-protected.
- Create a new public IP resource with Standard SKU.
The completed network summary should show the external, internal, and protected branch subnets.
- Select Review + create.
- Review the Marketplace charges shown for the Pay as you go plan.
- Review the live PAYG evaluation terms shown for your subscription.
The Marketplace charge is separate from Azure compute, storage, and network charges. The cleanup section removes the deployment after your evidence pack is complete.
- Accept the Marketplace terms shown on the review page.
- Select Create after validation passes.
You should see the FortiGate deployment begin while vng-azure continues provisioning in the first tab.
Deploy the Windows test VMs
The two Windows Server VMs provide endpoints on opposite sides of the future VPN. Their placement makes a successful private TCP test meaningful.
Each test VM uses a Standard public IP as an explicit outbound path to Azure public endpoints. Both VMs reject public inbound connections because their Public inbound ports setting remains None.
- Create another Azure portal tab.
- Use the portal search bar to open Virtual machines.
- Select Create.
- Choose Azure virtual machine.
The first VM form now targets the Azure workload side of the lab.
- Select rg-fgt-vpn-lab as the resource group.
- Enter vm-azure as the virtual machine name.
The VM is now associated with the lab resource group.
- Select East US as the region.
- Select Windows Server 2022 Datacenter: Azure Edition - x64 Gen 2 as the image.
The form should show the chosen Windows Server image in East US.
- Select Standard_B2ts_v2 as the VM size.
- Create administrator credentials for vm-azure.
Keep these credentials private. Azure Run Command uses the VM agent, so you do not enter the credentials during routine testing.
- Store the vm-azure administrator credentials securely.
- Select vnet-azure as the virtual network.
The network options should now show the subnets inside vnet-azure.
- Select snet-workload as the subnet.
- Create a Standard public IP for vm-azure to provide explicit outbound connectivity.
The VM now has a private address in the workload subnet and a Standard public IP for outbound connectivity. No public inbound management port is open.
- Set Public inbound ports to None.
- Select Review + create.
The review should show vm-azure in snet-workload with a Standard public IP and no public inbound ports.
- Select Create after validation passes.
You should see the vm-azure deployment begin.
- Return to vm-azure after its deployment succeeds.
- Open its Networking settings.
- Add an inbound NSG rule that permits TCP 3389 from 10.20.2.0/24.
The private rule makes vm-azure available as the reverse test endpoint from the protected subnet. Public inbound access remains blocked.
- Return to Virtual machines in another portal tab.
- Select Create.
- Choose Azure virtual machine.
- Select rg-fgt-vpn-lab as the resource group.
The second VM form now targets the protected branch workload.
- Enter vm-branch as the virtual machine name.
- Select East US as the region.
The branch VM now shares the same region as the FortiGate appliance.
- Select Windows Server 2022 Datacenter: Azure Edition - x64 Gen 2 as the image.
- Select Standard_B2ts_v2 as the VM size.
The form should show the same Windows image and VM size used for vm-azure.
- Create administrator credentials for vm-branch.
- Store the vm-branch administrator credentials securely.
The branch credentials stay private. Its Standard public IP supports outbound Azure Run Command traffic without opening a public inbound port.
- Select vnet-branch as the virtual network.
- Select snet-protected as the subnet.
The network summary should place vm-branch behind the FortiGate in the protected subnet.
- Create a Standard public IP for vm-branch to provide explicit outbound connectivity.
- Set Public inbound ports to None.
- Select Review + create.
The review should show vm-branch in snet-protected with a Standard public IP and no public inbound ports.
- Select Create after validation passes.
You should see the vm-branch deployment begin.
- Return to vm-branch after its deployment succeeds.
- Open its Networking settings.
- Add an inbound NSG rule that permits TCP 3389 from 10.10.1.0/24.
The private rule now exposes TCP 3389 only to the Azure workload subnet. Public inbound access remains blocked on vm-branch.
- Return to rg-fgt-vpn-lab.
- Check the resource group's deployment list.
You should see successful deployments for both VNets and both Windows VMs. Each test VM has a Standard public IP for outbound connectivity, while vng-azure can still be provisioning.
- Keep the deployment list available until the FortiGate deployment shows Succeeded.
- Open the deployed FortiGate-VM resource.
Before you connect, what should a successful FortiGate deployment let you reach through its public IP?
- Copy the FortiGate public IP from the resource overview.
- Paste the copied public IP into the Microsoft Edge address bar.
- Continue through the browser certificate warning after confirming the address matches the FortiGate public IP.
- Sign in with the FortiGate administrator credentials you created.
You should see the FortiOS dashboard in Microsoft Edge. The active-active Azure VPN gateway may still be provisioning in the background.
FortiOS dashboard not loading?
- Confirm the FortiGate deployment shows Succeeded before retrying the public IP.
- Confirm you copied the public IP associated with port1 instead of a private branch address.
- Confirm Microsoft Edge did not stop at the appliance certificate warning.
Help me troubleshoot access to the FortiOS dashboard through my FortiGate public IP.
You used the gateway's long provisioning window to build the branch firewall and both test endpoints. Next, you'll record their private addresses and prove the two networks are still isolated.
Prove the Networks Are Isolated
Your parallel deployment paid off. The Azure networks now contain the FortiGate appliance plus both Windows test VMs.
Private reachability needs a clean baseline before any VPN configuration exists. This test reveals whether Azure already provides a path between the isolated address spaces.
In this step, get ready to:
- Record the private and public endpoints used by the lab.
- Verify the 10.10.1.0/24 route uses the FortiGate virtual appliance while the AzureCloud route uses the Internet next hop.
- Run a private TCP baseline test from vm-azure.
Record the lab endpoints
The next step needs fixed addresses for two tunnel definitions. This endpoint map keeps every later field grounded in a value from your own lab.
- Return to the Azure portal tab from earlier.
- Select vm-azure from rg-fgt-vpn-lab.
- On Overview, record the Private IP address: vm-azure private IP.
- Return to rg-fgt-vpn-lab.
- Select vm-branch.
- On Overview, record the Private IP address: vm-branch private IP.
- Return to rg-fgt-vpn-lab.
- Select FortiGate-VM.
How the FortiGate ports map to Azure
Port1 faces snet-external. Its public IP is the peer address Azure uses for the branch device.
Port2 faces snet-internal. Its private IP becomes the next hop for traffic leaving snet-protected.
- On Overview, record the Public IP address as the FortiGate port1 public IP: FortiGate port1 public IP.
- Select Network settings under Networking.
- Select the network interface connected to snet-internal.
- Select IP configurations under Settings.
- Record the private IPv4 address as the FortiGate port2 private IP: FortiGate port2 private IP.
- Return to rg-fgt-vpn-lab.
- Select vng-azure.
Why are there two gateway addresses?
An active-active Azure VPN gateway runs two gateway instances.
Each instance exposes a unique public IP address. These addresses become the two tunnel targets.
- Select Properties under Settings.
- Record the first listed public IP address: first Azure gateway public IP.
- Record the second listed public IP address: second Azure gateway public IP.
Two gateway addresses not listed?
- Return to rg-fgt-vpn-lab.
- Select the first Standard public IP resource created for vng-azure.
- Record its assigned address from Overview.
- Repeat this check for the second Standard public IP resource.
Ask for help if the gateway public IP resources are unclear: help me identify both vng-azure public IP addresses.
That endpoint map removes the most common source of tunnel-target mistakes.
Verify the protected-subnet route
A user-defined route controls where snet-protected sends traffic for 10.10.1.0/24. The Virtual appliance next hop points that traffic at FortiGate port2.
- Return to rg-fgt-vpn-lab.
- Select vnet-branch.
- Select Subnets.
- Select snet-protected.
The Route table field should name the route table created during the FortiGate deployment.
✔️ A route table is attached
- Record the name shown in Route table: FortiGate route table name.
- Return to rg-fgt-vpn-lab.
- Select FortiGate route table name.
ⓧ The Route table field is empty
- Select the route table created by the FortiGate deployment in the Route table field.
- Select Save.
- Record the attached route table name: FortiGate route table name.
- Return to rg-fgt-vpn-lab.
- Select FortiGate route table name.
- Select Routes under Settings.
- Inspect the route list for a destination of 10.10.1.0/24.
✔️ The 10.10.1.0/24 route matches
- Confirm the route destination is 10.10.1.0/24.
- Confirm Next hop type shows Virtual appliance.
- Confirm Next hop address matches FortiGate port2 private IP.
ⓧ The route is missing
- Select + Add.
- Enter to-azure-workload in Route name.
- Select IP Addresses for Destination type.
- Enter 10.10.1.0/24 in Destination IP addresses/CIDR ranges.
- Select Virtual appliance for Next hop type.
- Enter FortiGate port2 private IP in Next hop address.
- Select Add.
ⓧ The route has different values
- Select the existing route for 10.10.1.0/24.
- Set Destination type to IP Addresses.
- Enter 10.10.1.0/24 in Destination IP addresses/CIDR ranges.
- Set Next hop type to Virtual appliance.
- Enter FortiGate port2 private IP in Next hop address.
- Select Save.
The workload route handles private Azure traffic. The route table still needs an AzureCloud exception so Azure public-service traffic can use Azure's Internet next hop instead of the FortiGate default route.
- Return to Routes under Settings.
- Select + Add.
- Enter to-azure-cloud in Route name.
- Select Service tag for Destination type.
- Select AzureCloud as the destination service tag.
- Select Internet for Next hop type.
- Select Add.
You should see to-azure-cloud with an AzureCloud destination and an Internet next hop.
What Does This Route Bypass?
The AzureCloud service tag contains Azure datacenter public IP ranges that Microsoft maintains. Its route takes precedence over the broader 0.0.0.0/0 route when the destination matches.
This exception does not provide unrestricted internet access. Other public destinations still follow the FortiGate default route until you configure an outbound firewall policy with NAT.
Azure still checks whether each network interface may forward packets addressed to another host. IP forwarding grants that permission to the NICs used by the FortiGate network virtual appliance.
- Return to FortiGate-VM.
- Select Network settings under Networking.
- Select the first attached network interface used for forwarding.
- Select IP configurations.
- Set IP forwarding to Enabled.
- Select Save.
- Repeat the IP forwarding setting for every remaining FortiGate NIC used for forwarding.
Why enable every forwarding NIC?
Azure evaluates forwarding separately for each NIC. Enabling one interface can still leave traffic blocked on another interface in the path.
- Return to FortiGate route table name.
- Select Subnets under Settings.
- Confirm snet-protected is listed under vnet-branch.
- Select Routes.
- Confirm the private route destination shows 10.10.1.0/24.
- Confirm the private route uses Virtual appliance with FortiGate port2 private IP as its next hop.
- Confirm the service-tag route destination shows AzureCloud.
- Confirm the service-tag route uses Internet as its next hop.
Route missing or not saving?
- Check that the route table is associated with snet-protected.
- Check that 10.10.1.0/24 appears only once and uses the FortiGate port2 private IP as its next hop.
- Check that the AzureCloud route uses Internet as its next hop.
Help me verify both protected-subnet routes.
Capture the pre-VPN baseline
Azure Run Command executes PowerShell inside vm-azure through the VM agent. This keeps the baseline test inside the workload subnet without opening a public inbound port.
- Return to vm-azure in the Azure portal.
- Confirm the VM agent status shows READY on the VM overview.
- Select Run command under Operations.
- Choose RunPowerShellScript.
Before you run this, do you expect private TCP port 3389 reachability to succeed? Your prediction gets tested in the next command.
- Confirm the command below shows vm-branch private IP as one value immediately after -ComputerName.
- Do not run the command while the placeholder words remain.
- Enter the pre-VPN connectivity test in the script box by pasting this command:
Test-NetConnection -ComputerName [[VM_BRANCH_PRIVATE_IP="vm-branch private IP"]] -Port 3389 -InformationLevel "Detailed"
- Select Run to execute the baseline test.
What does this test prove?
You'll see TcpTestSucceeded : False. That result is the intended baseline.
The Test-NetConnection command tests TCP port 3389 on the private branch address. The detailed output records the target plus the connection result in one place.
The failed connection proves that the two private address spaces remain isolated before the IPsec paths exist.
- Capture a screenshot showing the Run Command script and its full output.
- Save the screenshot in your evidence pack.
- Confirm the screenshot clearly shows TcpTestSucceeded : False.
Run Command not returning the baseline?
- Confirm the VM agent for vm-azure reports READY.
- Confirm vm-azure has outbound connectivity to Azure public IP addresses on TCP port 443.
- Confirm the -ComputerName value matches vm-branch private IP.
Help me troubleshoot the Run Command baseline test.
You now have a clean before-state that proves private connectivity is missing. Next, you'll build the two IPsec paths that close this gap.
Build the Two IPsec Paths
Your saved Azure Run Command output from vm-azure proved that the two private networks are still isolated. The existing route table already sends Azure-bound branch traffic to the FortiGate.
The active-active Azure VPN Gateway now needs two matching IPsec paths. Each route-based tunnel interface uses IKEv2 to negotiate its encrypted path.
Matching firewall policies permit private traffic through each tunnel. Equal-cost multipath routing gives the FortiGate two equal routes to the Azure workload subnet.
In this step, get ready to:
- Create the Azure local network gateway and site-to-site connection.
- Configure two matching FortiGate route-based tunnels.
- Build the FortiGate forwarding path and verify both tunnels.
Create the Azure VPN connection
A local network gateway represents the branch endpoint and its protected address space inside Azure. The site-to-site connection binds that definition to vng-azure.
Azure VPN Gateway creation can take 45 minutes or more. A long provisioning wait here is expected.
- Return to the vng-azure resource in the Azure portal session from earlier.
- Confirm its deployment status shows Succeeded.
- Start a local network gateway deployment in rg-fgt-vpn-lab.
- Enter lng-fgt as the resource name.
- Set Endpoint to IP address.
- Enter the recorded FortiGate port1 public IP in the IP address field.
- Enter 10.20.2.0/24 in the Address space field.
- Submit the local network gateway deployment.
You should see lng-fgt listed in rg-fgt-vpn-lab with the FortiGate public endpoint and protected branch prefix.
Understand the Azure VPN Connection
Understand the local network gateway
The local network gateway tells Azure which public endpoint represents the remote VPN device. Its address space tells Azure that 10.20.2.0/24 sits behind that endpoint.
Azure includes both active-active tunnels in one connection. Each Azure gateway instance uses its own public IP to reach the same FortiGate endpoint.
Protect the shared key
The pre-shared key authenticates Azure and both FortiGate tunnels. Anyone with this credential could attempt to impersonate a VPN peer.
- Store the generated key in secure password storage.
- Exclude the key from screenshots and shared notes.
- Return to vng-azure.
- Start adding a new connection to the gateway.
- Enter conn-azure-fgt as the connection name.
- Set Connection type to Site-to-site (IPSec).
- Select lng-fgt as the local network gateway.
- Generate a unique pre-shared key.
- Save the generated key in your secure password storage.
- Enter the generated key as the connection's pre-shared key.
Use Azure's Static Route Settings
- The IKE Protocol setting is IKEv2.
- The Enable BGP setting remains unselected.
- The IPsec/IKE policy setting is Default.
- The Use policy based traffic selector setting is Disable.
- The DPD timeout in seconds setting is 45.
- The Connection Mode setting is Default.
- Apply every connection setting shown above.
- Submit the connection deployment.
- Confirm conn-azure-fgt appears as a resource in rg-fgt-vpn-lab.
The new connection gives Azure a defined path to the FortiGate. Tunnel negotiation begins when the FortiGate configurations match it.
Create two FortiGate tunnel interfaces
Both FortiGate tunnels use the same cryptographic settings and protected prefixes. Each tunnel points to a different recorded vng-azure public endpoint.
Match the IPsec Settings
Match the phase 1 settings
Phase 1 authenticates each VPN peer. It creates the secure channel used for later negotiation.
- The tunnel style is custom route-based.
- The Remote Gateway setting is Static IP Address.
- The Interface setting is port1.
- The authentication method uses the generated pre-shared key.
- The IKE setting is 2.
- The NAT Traversal setting is Enable.
- Dead Peer Detection is set to On Idle.
- Diffie-Hellman Group is set to 2.
- The phase 1 key lifetime is 28800 seconds.
- The phase 1 proposals are AES256 and SHA1, 3DES and SHA1, and AES256 and SHA256.
Match the phase 2 settings
Phase 2 defines which private prefixes can use the encrypted channel. Matching selectors prevent either side from rejecting protected traffic.
- The local selector is 10.20.2.0/24.
- The remote selector is 10.10.1.0/24.
- The phase 2 proposals are AES256 and SHA1, 3DES and SHA1, and AES256 and SHA256.
- Perfect Forward Secrecy is disabled.
- The phase 2 key lifetime is 27000 seconds.
Why enable NAT Traversal?
Azure maps the FortiGate public IP to its external interface through network address translation. NAT Traversal wraps encrypted traffic in UDP so packets can cross that mapping.
Azure supports this mode when the VPN device initiates the tunnel. That makes Enable the correct setting for this FortiGate-VM deployment.
- Switch back to the FortiOS dashboard session from earlier.
- Select VPN in the left navigation.
- Select IP Wizard.
- Create to-az-gw1 with the first recorded Azure gateway public IP and every setting shown above.
- Submit the to-az-gw1 tunnel configuration.
- Confirm to-az-gw1 appears in the FortiGate tunnel list.
You should see to-az-gw1 as a route-based tunnel interface pointing to the first Azure gateway endpoint.
- Return to IP Wizard.
- Create to-az-gw2 with the second recorded Azure gateway public IP and the same settings.
- Submit the to-az-gw2 tunnel configuration.
- Confirm to-az-gw2 appears in the FortiGate tunnel list.
You should now see two separate route-based interfaces. Each interface targets one active-active Azure gateway instance.
Add policies and equal-cost routes
The tunnel interfaces provide the encrypted paths. Address objects define the private prefixes that can use those paths.
Map the Protected Traffic
- The Azure workload address object covers 10.10.1.0/24.
- The protected branch address object covers 10.20.2.0/24.
- Each outbound policy uses the FortiGate port2 protected-side interface as its source interface.
- Each outbound policy uses one IPsec tunnel as its destination interface.
- Each inbound policy reverses those interfaces and address objects.
- Every policy accepts traffic with NAT disabled.
- Create an address object covering 10.10.1.0/24.
- Create an address object covering 10.20.2.0/24.
- Confirm both prefixes appear in the FortiGate address-object list.
You should see one object for the Azure workload prefix and one object for the protected branch prefix.
- Create the bidirectional no-NAT policy pair for to-az-gw1 using the traffic map above.
- Confirm the policy list shows one accepted direction into to-az-gw1 and one accepted direction back to port2.
The first tunnel now has an explicit policy in each direction. NAT remains disabled so both VMs keep their private source addresses.
- Create the bidirectional no-NAT policy pair for to-az-gw2 using the same traffic map.
- Confirm the policy list shows one accepted direction into to-az-gw2 and one accepted direction back to port2.
Both tunnel interfaces now permit the same protected traffic. The final forwarding decision comes from the static route table.
- Create a static route for 10.10.1.0/24 through to-az-gw1.
- Record the displayed distance and priority for the first route.
- Confirm the first route appears in the FortiGate static route list.
You should see one route sending Azure workload traffic through to-az-gw1.
- Create a second static route for 10.10.1.0/24 through to-az-gw2.
- Match the second route's distance to the value recorded from the first route.
- Match the second route's priority to the value recorded from the first route.
- Confirm both routes appear with equal distance and priority.
You should see two equal-cost static routes for 10.10.1.0/24. One route uses each tunnel interface.
- Set the FortiGate to allow both equal-cost paths by opening the CLI console and running:
config system settings
set ecmp-max-paths 2
end
What Does This Setting Do?
ecmp-max-paths controls how many equal-cost next hops FortiGate can install. A value of 1 disables ECMP, while 2 allows both lab tunnels to participate.
- Verify that both tunnel routes are active by running:
get router info routing-table all
You should see two active entries for 10.10.1.0/24. One entry uses to-az-gw1, while the other uses to-az-gw2.
Only One Route Active?
- Confirm both tunnels show an up state in IPsec Monitor.
- Confirm both static routes use the same distance.
- Confirm both static routes use the same priority.
Help me find why only one ECMP route is active.
Before the check, do you expect both gateway instances to negotiate once their policies and routes match? The next status view tests your prediction.
- Select Monitor in FortiOS.
- Select IPsec Monitor.
- Initiate any tunnel that remains down by using the control beside it.
- Confirm to-az-gw1 shows an up state.
- Confirm to-az-gw2 shows an up state.
You should see both tunnel paths up in FortiGate IPsec Monitor. Each active Azure gateway instance now has a matching FortiGate peer.
- Return to the Azure portal session from earlier.
- Open conn-azure-fgt.
- Confirm Status shows Connected.
You should see Connected for the Azure connection. That is the hard part complete: both encrypted paths are negotiated and ready for private traffic.
Tunnel Status Not Healthy?
- Check that each tunnel uses a different recorded vng-azure public IP.
- Confirm Azure and both tunnels use the same generated pre-shared key.
- Verify NAT Traversal is set to Enable on both tunnels.
- Compare the local selector 10.20.2.0/24 with the remote selector 10.10.1.0/24.
- Check that lng-fgt uses the FortiGate port1 public IP.
Ask for help with the tunnel that is still down: help me diagnose my FortiGate-to-Azure IPsec tunnel settings
The encrypted paths are ready. Next, you will send private TCP traffic across them and watch the connection counters rise.
Prove End-to-End Connectivity
Both route-based tunnels are live. The Azure VPN Gateway reports conn-azure-fgt as Connected.
A connected status only proves tunnel negotiation. Successful private TCP traffic plus rising counters proves the complete path through your routes, security rules, and FortiGate policies.
In this step, get ready to:
- Prove private TCP 3389 connectivity from vm-azure to vm-branch.
- Prove the reverse private path through Azure Run Command.
- Capture tunnel health, traffic counters, and routing evidence.
Prove the forward private path
The failed Azure Run Command test from earlier is your baseline. Repeating the same probe now isolates the VPN configuration as the change that restored connectivity.
- Return to vm-azure in the Azure portal.
- Confirm the VM agent status shows READY.
- Select Run command under Operations.
- Choose RunPowerShellScript.
Before you rerun the test, do you expect the same private endpoint to remain blocked or accept TCP 3389 now?
- Confirm the command below shows vm-branch private IP as one value immediately after -ComputerName.
- Do not run the command while the placeholder words remain.
- Enter the forward TCP probe in the script box by pasting this command:
Test-NetConnection -ComputerName [[VM_BRANCH_PRIVATE_IP="vm-branch private IP"]] -Port 3389 -InformationLevel "Detailed"
- Select Run to execute the forward test.
What does this test prove?
The command attempts a TCP connection from vm-azure to port 3389 on the private address of vm-branch. Success means the VPN selectors, routes, security rules, and no-NAT policies support the complete forward path.
You should now see TcpTestSucceeded : True. That is the central proof that private application traffic crosses your encrypted path.
- Capture the successful Run Command output as a screenshot.
- Save the screenshot in your evidence pack.
Private path still blocked?
- Confirm the command uses the recorded private IP for vm-branch.
- Confirm the branch NSG permits TCP 3389 from 10.10.1.0/24.
- Confirm both IPsec tunnels remain up in FortiGate.
- Confirm the VM agent for vm-azure reports READY and has outbound TCP 443 connectivity.
Help me diagnose a failed private TCP 3389 test across my FortiGate-to-Azure VPN.
Prove the reverse private path
The forward test proves traffic can enter the protected branch subnet. A reverse probe through Azure Run Command proves the return direction also works without opening public inbound access to vm-branch.
- Return to the Microsoft Azure portal tab from earlier.
- Open vm-branch in rg-fgt-vpn-lab.
- Select Run command under Operations.
- Choose RunPowerShellScript.
- Confirm the command below shows vm-azure private IP as one value immediately after -ComputerName.
- Do not run the command while the placeholder words remain.
- Enter the reverse TCP probe in the script box by pasting this command:
Test-NetConnection -ComputerName [[VM_AZURE_PRIVATE_IP="vm-azure private IP"]] -Port 3389 -InformationLevel "Detailed"
What does the reverse probe prove?
This test originates on vm-branch. A successful result proves the protected subnet route sends Azure-bound traffic through the FortiGate before the VPN carries it to vm-azure.
Before you run the script, do you expect the reverse path to reach TCP 3389 through the same VPN?
- Select Run to execute the reverse test.
You should see TcpTestSucceeded : True in the Run Command output. Both private directions now carry TCP 3389 traffic.
Reverse test did not succeed?
- Confirm the VM agent for vm-branch reports READY.
- Confirm vm-branch has outbound connectivity on port 443 for Azure Run Command.
- Confirm vm-azure is running if the script executes but the TCP result is false.
Help me troubleshoot the reverse TCP test from vm-branch to vm-azure.
- Capture the successful Run Command output as a screenshot.
- Save the screenshot in your evidence pack.
Complete the VPN evidence pack
Your two successful tests prove application reachability in both directions. Tunnel health, byte counters, and route evidence explain how the traffic reached its destination.
- Return to the FortiOS session from earlier.
- Select Monitor in the FortiOS navigation.
- Select IPsec Monitor.
You should see to-az-gw1 and to-az-gw2 up after the connectivity tests.
- Capture the IPsec Monitor as a screenshot.
- Save the screenshot in your evidence pack.
- Return to the Azure portal tab from earlier.
- Open conn-azure-fgt in rg-fgt-vpn-lab.
Before you refresh the connection details, do you expect the ingress counter, the egress counter, or both counters to have increased?
- Refresh the connection details to load the current status and counters.
You should still see Connected as the status. Both ingress and egress byte counters should be higher after the forward and reverse tests.
- Capture the connected status with its byte counters as a screenshot.
- Save the screenshot in your evidence pack.
Counters have not increased?
- Wait briefly for the Azure connection metrics to update.
- Refresh the connection details again.
- Repeat the forward TCP test if both counters remain unchanged.
Help me understand why my Azure VPN connection byte counters are not increasing.
- Return to the route table attached to snet-protected.
- Open the route list for the protected subnet.
You should see destination 10.10.1.0/24 with next hop type Virtual appliance. The next-hop address should match the recorded FortiGate port2 private IP.
- Capture the protected subnet route as a screenshot.
- Save the screenshot in your evidence pack.
- Keep the pre-VPN failure evidence from earlier in the evidence pack.
What your evidence pack proves
- The pre-VPN TcpTestSucceeded : False result establishes the isolated before-state.
- The forward TcpTestSucceeded : True result proves private traffic reaches vm-branch.
- The reverse TcpTestSucceeded : True result proves traffic returns to vm-azure.
- The FortiGate IPsec Monitor screenshot proves both active-active tunnels remain up.
- The Azure connection screenshot proves conn-azure-fgt remains connected with increased byte counters.
- The route screenshot proves snet-protected sends Azure workload traffic to the FortiGate port2 private IP.
You have proven the VPN as a complete system. Your evidence now connects private reachability with tunnel health, traffic counters, and protected-subnet routing.
Secret mission
Diagnose a One-Tunnel Authentication Failure
Break authentication on one FortiGate tunnel while preserving the other path. Diagnose the mismatch from live evidence before restoring both tunnels.
Clean Up Your Resources
Clean Up Your Resources
Billable Microsoft Azure resources remain active after the lab ends. The options below make the cost trade-off clear before you choose to keep, pause, or delete the lab.
Cost warning
The Azure VPN Gateway continues billing while vng-azure remains provisioned. Deallocating the VMs does not stop that gateway charge.
The Fortinet FortiGate Next-Generation Firewall Marketplace usage can continue billing while FortiGate-VM runs.
Standard public IP addresses can continue billing. Managed disks can continue billing.
The estimated cost of $3 to $5 assumes deletion within 2 to 4 hours in East US. Prompt cleanup keeps the lab closest to that estimate.
Resources you used:
- The rg-fgt-vpn-lab resource group in East US.
- Two virtual networks named vnet-azure and vnet-branch.
- Five subnets named snet-workload, GatewaySubnet, snet-external, snet-internal, and snet-protected.
- The route-based active-active VpnGw1AZ gateway named vng-azure with two Standard static public IP addresses.
- Site-to-site IPsec resources named lng-fgt and conn-azure-fgt.
- The FortiGate-VM deployment with its managed disk, network interfaces, Standard public IP address, route table, and network security resources.
- Two Windows Server VMs named vm-azure and vm-branch with their managed disks, network interfaces, network security groups, and outbound-only Standard public IP addresses.
Keep everything running
Keeping the lab deployed preserves the working VPN demonstration and both healthy tunnels. All hourly charges continue while these resources remain provisioned.
- Leave rg-fgt-vpn-lab deployed to keep the complete active-active VPN lab available.
- Retain your evidence pack as the record of tunnel health, private connectivity, routing, traffic counters, fault isolation, and recovery.
Pause - I'll come back to this later
Pausing the three virtual machines reduces compute and FortiGate Marketplace usage. The VPN gateway, public IP addresses, managed disks, and network resources remain provisioned, so this option still incurs charges.
- In the Azure portal from earlier, open FortiGate-VM from rg-fgt-vpn-lab.
- Stop and deallocate FortiGate-VM.
- Open vm-azure from rg-fgt-vpn-lab.
- Stop and deallocate vm-azure.
- Open vm-branch from rg-fgt-vpn-lab.
- Stop and deallocate vm-branch.
- Return to the virtual machine list in the Azure portal to confirm all three VMs are deallocated.
You'll see all three VMs in a deallocated state. Both tunnels become unavailable because FortiGate-VM is stopped.
Delete - I don't want to use this again
Deletion removes every Azure resource listed above in one operation. Your saved evidence pack remains your record of the working VPN and its recovery test.
- In the Azure portal from earlier, search for rg-fgt-vpn-lab.
- Open the matching rg-fgt-vpn-lab resource group.
- Select Delete resource group.
- Type rg-fgt-vpn-lab when Azure asks for the resource group name.
- Confirm the deletion.
- Wait until Azure reports that the deletion is complete.
- Search for rg-fgt-vpn-lab again to verify the cleanup.
You'll see no matching resource group. That confirms the gateway, VMs, networks, public IP addresses, disks, routing resources, and security resources were removed.
Nice Work!
Nice Work!
You did it! Your active-active Azure VPN Gateway connection now carries private traffic through two encrypted paths to the FortiGate-VM.
You've learned how to:
- Design two non-overlapping Azure network environments. Send protected branch traffic through the FortiGate with a user-defined route.
- Configure two route-based IKEv2/IPsec tunnels between the active-active gateway and the FortiGate-VM. Apply bidirectional no-NAT firewall policies. Add equal-cost static routes to enable ECMP forwarding.
- Prove end-to-end private connectivity with successful TCP 3389 tests in both directions. Assemble an evidence pack showing tunnel health. Include the protected route. Include rising connection byte counters.
- Secret Mission: Diagnose a wrong pre-shared key on to-az-gw2. Show that to-az-gw1 preserved private TCP 3389 connectivity. Restore the correct key to recover both tunnels.
Ready to quiz yourself?