Managing Azure VPN Gateway with Terraform
Learn how to set up and manage Azure VPN Gateway using Terraform, including site-to-site and point-to-site configurations
Managing Azure VPN Gateway with Terraform
Azure VPN Gateway provides secure cross-premises connectivity between your virtual network and on-premises networks. This guide demonstrates how to set up and manage VPN Gateway using Terraform.
Video Tutorial
Learn more about managing Azure VPN Gateway with Terraform in this comprehensive video tutorial:
Prerequisites
- Azure CLI configured with appropriate permissions
- Terraform installed (version 1.0.0 or later)
- Resource group created
- Understanding of networking concepts
Project Structure
terraform-azure-vpngateway/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── vpngateway/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── configs/
└── vpn.json
VPN Gateway Configuration
Create modules/vpngateway/main.tf
:
# Virtual Network
resource "azurerm_virtual_network" "main" {
name = "${var.project_name}-vnet"
location = var.location
resource_group_name = var.resource_group_name
address_space = ["10.0.0.0/16"]
tags = var.tags
}
# Gateway Subnet
resource "azurerm_subnet" "gateway" {
name = "GatewaySubnet"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.255.0/24"]
}
# Public IP
resource "azurerm_public_ip" "vpn" {
name = "${var.project_name}-vpn-pip"
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Static"
sku = "Standard"
zones = ["1", "2", "3"]
tags = var.tags
}
# VPN Gateway
resource "azurerm_virtual_network_gateway" "main" {
name = "${var.project_name}-vpn"
location = var.location
resource_group_name = var.resource_group_name
type = "Vpn"
vpn_type = "RouteBased"
sku = "VpnGw2AZ"
active_active = true
enable_bgp = true
generation = "Generation2"
ip_configuration {
name = "vnetGatewayConfig1"
public_ip_address_id = azurerm_public_ip.vpn.id
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gateway.id
}
ip_configuration {
name = "vnetGatewayConfig2"
public_ip_address_id = azurerm_public_ip.vpn_secondary.id
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gateway.id
}
bgp_settings {
asn = 65515
}
vpn_client_configuration {
address_space = ["172.16.0.0/24"]
root_certificate {
name = "VPNRoot"
public_cert_data = file("${path.module}/certs/root.cer")
}
revoked_certificate {
name = "Revoked"
thumbprint = "ABC123..."
}
aad_tenant = "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}"
aad_audience = "41b23e61-6c1e-4545-b367-cd054e0ed4b4"
aad_issuer = "https://sts.windows.net/${data.azurerm_client_config.current.tenant_id}/"
radius_server_address = var.radius_server_address
radius_server_secret = var.radius_server_secret
vpn_client_protocols = ["OpenVPN", "IkeV2"]
}
custom_route {
address_prefixes = ["10.0.0.0/8"]
}
tags = var.tags
}
# Local Network Gateway
resource "azurerm_local_network_gateway" "onprem" {
name = "${var.project_name}-lng"
location = var.location
resource_group_name = var.resource_group_name
gateway_address = var.onprem_gateway_address
address_space = ["192.168.0.0/16"]
bgp_settings {
asn = 65516
bgp_peering_address = "192.168.1.1"
}
tags = var.tags
}
# Connection
resource "azurerm_virtual_network_gateway_connection" "onprem" {
name = "${var.project_name}-connection"
location = var.location
resource_group_name = var.resource_group_name
type = "IPsec"
virtual_network_gateway_id = azurerm_virtual_network_gateway.main.id
local_network_gateway_id = azurerm_local_network_gateway.onprem.id
connection_protocol = "IKEv2"
routing_weight = 10
enable_bgp = true
express_route_gateway_bypass = true
shared_key = var.vpn_shared_key
ipsec_policy {
dh_group = "DHGroup14"
ike_encryption = "AES256"
ike_integrity = "SHA256"
ipsec_encryption = "AES256"
ipsec_integrity = "SHA256"
pfs_group = "PFS14"
sa_datasize = 102400000
sa_lifetime = 27000
}
traffic_selector_policy {
local_address_cidrs = ["10.0.0.0/24"]
remote_address_cidrs = ["192.168.0.0/24"]
}
tags = var.tags
}
# NAT Rules
resource "azurerm_virtual_network_gateway_nat_rule" "main" {
name = "${var.project_name}-nat-rule"
resource_group_name = var.resource_group_name
gateway_name = azurerm_virtual_network_gateway.main.name
mode = "EgressSnat"
type = "Static"
internal_mapping {
address_space = "10.0.0.0/24"
}
external_mapping {
address_space = "192.168.0.0/24"
}
}
## Network Configuration
1. **Network Security Groups**
```hcl
resource "azurerm_network_security_group" "gateway" {
name = "${var.project_name}-gateway-nsg"
location = var.location
resource_group_name = var.resource_group_name
security_rule {
name = "AllowVPNGateway"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "GatewayManager"
destination_address_prefix = "*"
}
tags = var.tags
}
resource "azurerm_subnet_network_security_group_association" "gateway" {
subnet_id = azurerm_subnet.gateway.id
network_security_group_id = azurerm_network_security_group.gateway.id
}
Route Configuration
- Route Table
resource "azurerm_route_table" "main" {
name = "${var.project_name}-rt"
location = var.location
resource_group_name = var.resource_group_name
route {
name = "ToOnPremise"
address_prefix = "192.168.0.0/16"
next_hop_type = "VirtualNetworkGateway"
}
tags = var.tags
}
resource "azurerm_subnet_route_table_association" "main" {
subnet_id = azurerm_subnet.main.id
route_table_id = azurerm_route_table.main.id
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "vpn" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_virtual_network_gateway.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "GatewayDiagnosticLog"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "vpn" {
name = "${var.project_name}-tunnel-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_virtual_network_gateway.main.id]
description = "Alert when VPN tunnel is down"
criteria {
metric_namespace = "Microsoft.Network/virtualNetworkGateways"
metric_name = "TunnelAverageBandwidth"
aggregation = "Average"
operator = "LessThan"
threshold = 1
}
action {
action_group_id = var.action_group_id
}
}
Advanced Features
- Custom IPSec/IKE Policy
resource "azurerm_virtual_network_gateway_connection" "custom_policy" {
name = "${var.project_name}-custom-policy"
location = var.location
resource_group_name = var.resource_group_name
type = "IPsec"
virtual_network_gateway_id = azurerm_virtual_network_gateway.main.id
local_network_gateway_id = azurerm_local_network_gateway.onprem.id
ipsec_policy {
dh_group = "DHGroup14"
ike_encryption = "AES256"
ike_integrity = "SHA256"
ipsec_encryption = "AES256"
ipsec_integrity = "SHA256"
pfs_group = "PFS2048"
sa_datasize = 102400000
sa_lifetime = 27000
}
shared_key = var.vpn_shared_key
tags = var.tags
}
## Best Practices
1. **Performance**
- Use appropriate SKU
- Enable active-active
- Configure BGP
- Optimize routing
2. **High Availability**
- Use zone-redundant gateways
- Configure active-active
- Implement failover
- Monitor connections
3. **Security**
- Use strong IPSec policies
- Implement encryption
- Configure authentication
- Monitor traffic
4. **Cost Optimization**
- Choose appropriate SKU
- Monitor bandwidth usage
- Optimize connections
- Use appropriate zones
## Conclusion
You've learned how to set up and manage Azure VPN Gateway using Terraform. This setup provides:
- Secure cross-premises connectivity
- Site-to-site VPN
- Point-to-site VPN
- High availability
Remember to:
- Monitor tunnel status
- Review security policies
- Update certificates
- Maintain connections