Skip to content

poroping/terraform-azurerm-secure-vnet-nva

Repository files navigation

terraform-azurerm-secure-vnet-nva

The following module will spin up the infrastructure needed to simplify Azure network routing and allow routing towards the VNETs to be controlled by an NVA of your choice. This could be a Firewall/Router/SDWAN device.

-> As of initial release the only NVA option is a pair of Fortigates.

Caveats

  • The NVA must support BGP
  • The NVA must support eBGP multihop
  • Traffic between VNETs will route via the NVA
  • Traffic within the VNET will not route via the NVA
  • The NVA pair should be able to deal with asymmetric routing

NVA configuration

  • Suggest keeping the advertisement interval short so routing changes are pushed down to the VNETs quickly or add summary routes to the NVA. An alternative is to have the NVA advertise the routes with the ILB frontend IP as the next hop.
  • If routing is required between more than one RouteServer this must be done via the NVAs.
  • You may also need to manipulate the AS path of routes from the RouteServers so that the same ASN doesn't appear twice from separate AS.
  • This is due to BGPs route-loop prevention and Azure's inflexibility in setting the ASN used by the RouteServer.

Example Usage:

terraform {
  required_version = "~> 1.0"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">= 3.2.0"
    }
  }
}

provider "azurerm" {
  features {}
}

module "azure_fortigate_pair" {
  source  = "poroping/secure-vnet-nva/azurerm"
  version = "~> 0.0.1"

  location            = "North Europe"
  name_prefix         = "advpn-hub-01"
  resource_group_name = "rsg-dev-transit"
  vnet_prefix         = "10.255.0.0/22"
  nva_bgp_asn         = 64420
  nva_type            = "fortigate"

  username = "fortinet"
  password = "Fortin3t!"
  trusted_hosts = [
    {
      prefix   = "185.62.0.0/32",
      name     = "MGMT-JUMPER",
      priority = 150
    }
  ]

  # module options
  create_sslvpn        = false
  assign_global_reader = false
  use_ilb              = false

}

output "fortigate_public_ips" {
  value = module.azure_fortigate_pair.nva_public_ips
}

## Dev vnet
## Create another vnet to connect to this transit vnet

resource "azurerm_resource_group" "devrsg" {
  name     = "rsg-dev-workload"
  location = "North Europe"
}

locals {
  dev_prefix  = "192.168.8.0/22"
  dev_subnets = cidrsubnets(local.dev_prefix, 2, 2, 2, 2)
}

resource "azurerm_virtual_network" "dev" {

  name                = "dev-vnet"
  address_space       = [local.dev_prefix]
  location            = azurerm_resource_group.devrsg.location
  resource_group_name = azurerm_resource_group.devrsg.name
}

resource "azurerm_subnet" "dev01" {

  name                 = "dev-snet-01"
  resource_group_name  = azurerm_resource_group.devrsg.name
  virtual_network_name = azurerm_virtual_network.dev.name
  address_prefixes     = [local.dev_subnets[0]]
}

## Connections

resource "azurerm_virtual_network_peering" "dev2transit" {
  name                         = "vnet-conn-dev2transit"
  resource_group_name          = azurerm_resource_group.devrsg.name
  virtual_network_name         = azurerm_virtual_network.dev.name
  remote_virtual_network_id    = module.azure_fortigate_pair.transit_vnet_id
  allow_virtual_network_access = true
  allow_forwarded_traffic      = true
  use_remote_gateways          = true # secret sauce

  depends_on = [
    module.azure_fortigate_pair # explicitly depend on module finishing to avoid no gateway error
  ]
}

# Sometimes this VNET connection seems to fail and not propogate the routes from the Route Server. 
# This only appears to be an issue when creating a new Route Server, an existing one will always rx the correct routes.
# Suspect it's race condition with the Route Server completing setup and the peering being completed too early.

resource "azurerm_virtual_network_peering" "transit2dev" {
  name                         = "vnet-conn-transit2dev"
  resource_group_name          = module.azure_fortigate_pair.rsg_name
  virtual_network_name         = module.azure_fortigate_pair.transit_vnet_name
  remote_virtual_network_id    = azurerm_virtual_network.dev.id
  allow_virtual_network_access = true
  allow_forwarded_traffic      = true
  allow_gateway_transit        = true # secret sauce
}

# To validate we should now see this VNET prefix advertised to the NVA via BGP.
# NVA MGMT interface will be accessible on port 10443 from list of trusted hosts.

Providers

Name Version
azurerm >= 3.0.2
random n/a
template n/a

Inputs

Name Description Type Default Required
nva_type Type of NVA. Valid options: fortigate string n/a yes
api_key API key to cloudinit NVA with. string null no
assign_global_reader Assign NVA system identity Global Reader in the subscription NVA is created in. Useful for NVAs that can access Azure metadata to create dynamic objects etc. Requires the Service Principal permissions to modify Roles. bool false no
availability_zone_support Availability zone support. Ensure region supports this feature. bool false no
create_sslvpn Create an ELB and required resources to bootstrap an SSLVPN service. bool true no
fortigate_licenses Licenses for BYOL Fortigates. If not set will use PAYG. list(string) null no
fortigate_sku If SKU changes can overwrite here otherwise can leave as default.
object({
byol = string
payg = string
})
{
"byol": "fortinet_fg-vm",
"payg": "fortinet_fg-vm_payg_20190624"
}
no
fortios_version Target FortiOS version image. string "latest" no
location Azure region for resources. string "North Europe" no
name_prefix Prefix for Azure resource names. string "secure-transit" no
nva_bgp_asn BGP ASN for NVA. number 65514 no
password Initial password for admin access. string "Solarwinds123!" no
resource_group_name Full name for Azure resource group. string "rsg-fortigate-testing" no
trusted_hosts Set of CIDRs to add to NSG for management access to NVA.
set(object({
prefix = string
name = string
priority = number
}))
[] no
use_ilb Create an internal load balancer. Intention is to allow the NVA to advertise BGP routes towards the Route Server with the ILB frontend address as the next-hop. ILB should deal with probe loss failovers within 10 secs. bool false no
username Initial username for admin access. string "fortinet" no
vm_size Azure VM SKU string "Standard_D2ds_v5" no
vnet_prefix Prefix for transit VNET. Will be broken into 4 equal subnets. string "10.255.0.0/22" no

Outputs

Name Description
elb_public_ip Public IP assigned to ELB for SSLVPN.
external_interfaces n/a
external_subnet_prefix Transit VNET external subnet prefix.
internal_interfaces n/a
internal_subnet_prefix Transit VNET internal subnet prefix.
nva_public_ips NVA public IP addresses
resource_group n/a
route_server_ips RouteServer IP addresses.
rsg_name Name of created resource group.
transit_vnet_id Transit VNET ID.
transit_vnet_name Transit VNET name.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published