|
| 1 | +# Azure Virtual Network Gateway Construct |
| 2 | + |
| 3 | +This construct provides a CDK for Terraform (CDKTF) implementation of Azure Virtual Network Gateway using the AzapiResource framework. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +Azure Virtual Network Gateway is used to send encrypted traffic between Azure virtual networks and on-premises locations over the public Internet (VPN Gateway) or through Azure ExpressRoute circuits (ExpressRoute Gateway). |
| 8 | + |
| 9 | +This construct supports: |
| 10 | +- **VPN Gateways**: Site-to-Site, Point-to-Site, and VNet-to-VNet connections |
| 11 | +- **ExpressRoute Gateways**: Private connections to Azure through ExpressRoute circuits |
| 12 | +- **BGP Support**: Border Gateway Protocol for dynamic routing |
| 13 | +- **Active-Active Mode**: High availability with dual gateway instances |
| 14 | +- **Multiple SKUs**: From Basic to high-performance VpnGw5/ErGw3AZ |
| 15 | + |
| 16 | +## Features |
| 17 | + |
| 18 | +- ✅ Automatic latest API version resolution |
| 19 | +- ✅ Explicit version pinning for stability |
| 20 | +- ✅ Schema-driven validation and transformation |
| 21 | +- ✅ Full backward compatibility |
| 22 | +- ✅ JSII compliance for multi-language support |
| 23 | +- ✅ Comprehensive TypeScript type definitions |
| 24 | + |
| 25 | +## Supported API Versions |
| 26 | + |
| 27 | +- `2024-01-01` (Active) |
| 28 | +- `2024-05-01` (Active, Latest - Default) |
| 29 | + |
| 30 | +## Installation |
| 31 | + |
| 32 | +```bash |
| 33 | +npm install @cdktf-constructs/azure-virtualnetworkgateway |
| 34 | +``` |
| 35 | + |
| 36 | +## Basic Usage |
| 37 | + |
| 38 | +### Simple VPN Gateway |
| 39 | + |
| 40 | +```typescript |
| 41 | +import { VirtualNetworkGateway } from '@cdktf-constructs/azure-virtualnetworkgateway'; |
| 42 | +import { ResourceGroup } from '@cdktf-constructs/azure-resourcegroup'; |
| 43 | +import { VirtualNetwork } from '@cdktf-constructs/azure-virtualnetwork'; |
| 44 | +import { Subnet } from '@cdktf-constructs/azure-subnet'; |
| 45 | +import { PublicIPAddress } from '@cdktf-constructs/azure-publicipaddress'; |
| 46 | + |
| 47 | +// Create resource group |
| 48 | +const resourceGroup = new ResourceGroup(this, 'rg', { |
| 49 | + name: 'rg-network', |
| 50 | + location: 'eastus', |
| 51 | +}); |
| 52 | + |
| 53 | +// Create virtual network |
| 54 | +const vnet = new VirtualNetwork(this, 'vnet', { |
| 55 | + name: 'vnet-main', |
| 56 | + location: 'eastus', |
| 57 | + resourceGroupId: resourceGroup.id, |
| 58 | + addressSpace: { |
| 59 | + addressPrefixes: ['10.0.0.0/16'] |
| 60 | + }, |
| 61 | +}); |
| 62 | + |
| 63 | +// Create GatewaySubnet (must be named "GatewaySubnet") |
| 64 | +const gatewaySubnet = new Subnet(this, 'gateway-subnet', { |
| 65 | + name: 'GatewaySubnet', |
| 66 | + virtualNetworkId: vnet.id, |
| 67 | + addressPrefix: '10.0.1.0/24', |
| 68 | +}); |
| 69 | + |
| 70 | +// Create public IP for gateway |
| 71 | +const publicIp = new PublicIPAddress(this, 'pip', { |
| 72 | + name: 'pip-gateway', |
| 73 | + location: 'eastus', |
| 74 | + resourceGroupId: resourceGroup.id, |
| 75 | + sku: { |
| 76 | + name: 'Standard', |
| 77 | + tier: 'Regional' |
| 78 | + }, |
| 79 | + publicIPAllocationMethod: 'Static', |
| 80 | +}); |
| 81 | + |
| 82 | +// Create VPN Gateway |
| 83 | +const vpnGateway = new VirtualNetworkGateway(this, 'vpn-gateway', { |
| 84 | + name: 'vng-main', |
| 85 | + location: 'eastus', |
| 86 | + resourceGroupId: resourceGroup.id, |
| 87 | + gatewayType: 'Vpn', |
| 88 | + vpnType: 'RouteBased', |
| 89 | + sku: { |
| 90 | + name: 'VpnGw1', |
| 91 | + tier: 'VpnGw1' |
| 92 | + }, |
| 93 | + ipConfigurations: [{ |
| 94 | + name: 'default', |
| 95 | + subnetId: gatewaySubnet.id, |
| 96 | + publicIPAddressId: publicIp.id |
| 97 | + }] |
| 98 | +}); |
| 99 | +``` |
| 100 | + |
| 101 | +### VPN Gateway with BGP |
| 102 | + |
| 103 | +```typescript |
| 104 | +const vpnGateway = new VirtualNetworkGateway(this, 'vpn-gateway-bgp', { |
| 105 | + name: 'vng-bgp', |
| 106 | + location: 'eastus', |
| 107 | + resourceGroupId: resourceGroup.id, |
| 108 | + gatewayType: 'Vpn', |
| 109 | + vpnType: 'RouteBased', |
| 110 | + sku: { |
| 111 | + name: 'VpnGw1', |
| 112 | + tier: 'VpnGw1' |
| 113 | + }, |
| 114 | + enableBgp: true, |
| 115 | + bgpSettings: { |
| 116 | + asn: 65515, |
| 117 | + peerWeight: 0 |
| 118 | + }, |
| 119 | + ipConfigurations: [{ |
| 120 | + name: 'default', |
| 121 | + subnetId: gatewaySubnet.id, |
| 122 | + publicIPAddressId: publicIp.id |
| 123 | + }], |
| 124 | + tags: { |
| 125 | + environment: 'production', |
| 126 | + purpose: 'site-to-site-vpn' |
| 127 | + } |
| 128 | +}); |
| 129 | +``` |
| 130 | + |
| 131 | +### Active-Active VPN Gateway |
| 132 | + |
| 133 | +```typescript |
| 134 | +// Create second public IP for active-active |
| 135 | +const publicIp2 = new PublicIPAddress(this, 'pip2', { |
| 136 | + name: 'pip-gateway-2', |
| 137 | + location: 'eastus', |
| 138 | + resourceGroupId: resourceGroup.id, |
| 139 | + sku: { |
| 140 | + name: 'Standard', |
| 141 | + tier: 'Regional' |
| 142 | + }, |
| 143 | + publicIPAllocationMethod: 'Static', |
| 144 | +}); |
| 145 | + |
| 146 | +const vpnGateway = new VirtualNetworkGateway(this, 'vpn-gateway-aa', { |
| 147 | + name: 'vng-active-active', |
| 148 | + location: 'eastus', |
| 149 | + resourceGroupId: resourceGroup.id, |
| 150 | + gatewayType: 'Vpn', |
| 151 | + vpnType: 'RouteBased', |
| 152 | + sku: { |
| 153 | + name: 'VpnGw1', |
| 154 | + tier: 'VpnGw1' |
| 155 | + }, |
| 156 | + activeActive: true, |
| 157 | + ipConfigurations: [ |
| 158 | + { |
| 159 | + name: 'config1', |
| 160 | + subnetId: gatewaySubnet.id, |
| 161 | + publicIPAddressId: publicIp.id |
| 162 | + }, |
| 163 | + { |
| 164 | + name: 'config2', |
| 165 | + subnetId: gatewaySubnet.id, |
| 166 | + publicIPAddressId: publicIp2.id |
| 167 | + } |
| 168 | + ] |
| 169 | +}); |
| 170 | +``` |
| 171 | + |
| 172 | +### Point-to-Site VPN Gateway |
| 173 | + |
| 174 | +```typescript |
| 175 | +const vpnGateway = new VirtualNetworkGateway(this, 'vpn-gateway-p2s', { |
| 176 | + name: 'vng-point-to-site', |
| 177 | + location: 'eastus', |
| 178 | + resourceGroupId: resourceGroup.id, |
| 179 | + gatewayType: 'Vpn', |
| 180 | + vpnType: 'RouteBased', |
| 181 | + sku: { |
| 182 | + name: 'VpnGw1', |
| 183 | + tier: 'VpnGw1' |
| 184 | + }, |
| 185 | + ipConfigurations: [{ |
| 186 | + name: 'default', |
| 187 | + subnetId: gatewaySubnet.id, |
| 188 | + publicIPAddressId: publicIp.id |
| 189 | + }], |
| 190 | + vpnClientConfiguration: { |
| 191 | + vpnClientAddressPool: { |
| 192 | + addressPrefixes: ['172.16.0.0/24'] |
| 193 | + }, |
| 194 | + vpnClientProtocols: ['IkeV2', 'OpenVPN'], |
| 195 | + vpnClientRootCertificates: [ |
| 196 | + { |
| 197 | + name: 'RootCert', |
| 198 | + publicCertData: 'MIIC5zCCAc+gAwIBAgI...' // Your certificate data |
| 199 | + } |
| 200 | + ] |
| 201 | + } |
| 202 | +}); |
| 203 | +``` |
| 204 | + |
| 205 | +### ExpressRoute Gateway |
| 206 | + |
| 207 | +```typescript |
| 208 | +const erGateway = new VirtualNetworkGateway(this, 'er-gateway', { |
| 209 | + name: 'vng-expressroute', |
| 210 | + location: 'eastus', |
| 211 | + resourceGroupId: resourceGroup.id, |
| 212 | + gatewayType: 'ExpressRoute', |
| 213 | + sku: { |
| 214 | + name: 'ErGw1AZ', |
| 215 | + tier: 'ErGw1AZ' |
| 216 | + }, |
| 217 | + ipConfigurations: [{ |
| 218 | + name: 'default', |
| 219 | + subnetId: gatewaySubnet.id, |
| 220 | + publicIPAddressId: publicIp.id |
| 221 | + }], |
| 222 | + tags: { |
| 223 | + environment: 'production', |
| 224 | + purpose: 'expressroute' |
| 225 | + } |
| 226 | +}); |
| 227 | +``` |
| 228 | + |
| 229 | +### Generation 2 VPN Gateway |
| 230 | + |
| 231 | +```typescript |
| 232 | +const vpnGateway = new VirtualNetworkGateway(this, 'vpn-gateway-gen2', { |
| 233 | + name: 'vng-generation2', |
| 234 | + location: 'eastus', |
| 235 | + resourceGroupId: resourceGroup.id, |
| 236 | + gatewayType: 'Vpn', |
| 237 | + vpnType: 'RouteBased', |
| 238 | + sku: { |
| 239 | + name: 'VpnGw2', |
| 240 | + tier: 'VpnGw2' |
| 241 | + }, |
| 242 | + vpnGatewayGeneration: 'Generation2', |
| 243 | + ipConfigurations: [{ |
| 244 | + name: 'default', |
| 245 | + subnetId: gatewaySubnet.id, |
| 246 | + publicIPAddressId: publicIp.id |
| 247 | + }] |
| 248 | +}); |
| 249 | +``` |
| 250 | + |
| 251 | +## Configuration Options |
| 252 | + |
| 253 | +### VirtualNetworkGatewayProps |
| 254 | + |
| 255 | +| Property | Type | Required | Default | Description | |
| 256 | +|----------|------|----------|---------|-------------| |
| 257 | +| `name` | string | No | CDK ID | Name of the virtual network gateway | |
| 258 | +| `location` | string | Yes | - | Azure region | |
| 259 | +| `gatewayType` | "Vpn" \| "ExpressRoute" | Yes | - | Type of gateway | |
| 260 | +| `vpnType` | "RouteBased" \| "PolicyBased" | No | "RouteBased" | VPN routing type | |
| 261 | +| `sku` | VirtualNetworkGatewaySku | Yes | - | Gateway SKU configuration | |
| 262 | +| `ipConfigurations` | VirtualNetworkGatewayIpConfiguration[] | Yes | - | IP configurations (1 or 2) | |
| 263 | +| `enableBgp` | boolean | No | false | Enable BGP | |
| 264 | +| `activeActive` | boolean | No | false | Enable active-active mode | |
| 265 | +| `bgpSettings` | VirtualNetworkGatewayBgpSettings | No | - | BGP configuration | |
| 266 | +| `vpnGatewayGeneration` | string | No | - | Gateway generation (Gen1/Gen2) | |
| 267 | +| `vpnClientConfiguration` | VirtualNetworkGatewayVpnClientConfiguration | No | - | Point-to-site config | |
| 268 | +| `customRoutes` | VirtualNetworkGatewayCustomRoutes | No | - | Custom routing | |
| 269 | +| `enablePrivateIpAddress` | boolean | No | false | Enable private IP | |
| 270 | +| `gatewayDefaultSite` | VirtualNetworkGatewayDefaultSite | No | - | Default site for tunneling | |
| 271 | +| `resourceGroupId` | string | No | - | Resource group ID | |
| 272 | +| `tags` | Record<string, string> | No | {} | Resource tags | |
| 273 | +| `apiVersion` | string | No | "2024-05-01" | API version to use | |
| 274 | +| `ignoreChanges` | string[] | No | [] | Properties to ignore | |
| 275 | + |
| 276 | +### SKU Options |
| 277 | + |
| 278 | +#### VPN Gateway SKUs |
| 279 | +- `Basic`: Legacy SKU (limited features) |
| 280 | +- `VpnGw1`, `VpnGw2`, `VpnGw3`: Generation 1 |
| 281 | +- `VpnGw1AZ`, `VpnGw2AZ`, `VpnGw3AZ`: Zone-redundant Generation 1 |
| 282 | +- `VpnGw4`, `VpnGw5`: Generation 2 high-performance |
| 283 | +- `VpnGw4AZ`, `VpnGw5AZ`: Zone-redundant Generation 2 |
| 284 | + |
| 285 | +#### ExpressRoute Gateway SKUs |
| 286 | +- `Standard`, `HighPerformance`, `UltraPerformance`: Classic SKUs |
| 287 | +- `ErGw1AZ`, `ErGw2AZ`, `ErGw3AZ`: Zone-redundant SKUs |
| 288 | + |
| 289 | +## Important Notes |
| 290 | + |
| 291 | +### Provisioning Time |
| 292 | + |
| 293 | +- **Provisioning Time**: VPN and ExpressRoute gateways typically take 30-45 minutes to provision. The construct is configured with 60-minute timeouts to accommodate this. |
| 294 | + |
| 295 | +### GatewaySubnet Requirements |
| 296 | + |
| 297 | +1. **Name**: The subnet MUST be named exactly "GatewaySubnet" |
| 298 | +2. **Size**: Minimum /29, recommended /27 or larger |
| 299 | +3. **Delegation**: Must not be delegated to any service |
| 300 | +4. **NSG**: Network Security Groups are not recommended on GatewaySubnet |
| 301 | + |
| 302 | +### Deployment Time |
| 303 | + |
| 304 | +- **VPN Gateways**: 30-45 minutes to deploy |
| 305 | +- **ExpressRoute Gateways**: 30-45 minutes to deploy |
| 306 | +- Plan accordingly in CI/CD pipelines |
| 307 | + |
| 308 | +### Active-Active Mode |
| 309 | + |
| 310 | +- Requires 2 IP configurations |
| 311 | +- Requires 2 public IP addresses |
| 312 | +- Both configurations must reference the same GatewaySubnet |
| 313 | +- Only supported with VpnGw1 or higher SKUs |
| 314 | + |
| 315 | +### BGP Configuration |
| 316 | + |
| 317 | +- Required for ExpressRoute |
| 318 | +- Recommended for Site-to-Site VPN with dynamic routing |
| 319 | +- Not supported with Basic SKU |
| 320 | +- ASN must be valid (not 65515 for on-premises) |
| 321 | + |
| 322 | +## Outputs |
| 323 | + |
| 324 | +The construct provides the following outputs: |
| 325 | + |
| 326 | +```typescript |
| 327 | +vpnGateway.id // Gateway resource ID |
| 328 | +vpnGateway.name // Gateway name |
| 329 | +vpnGateway.location // Gateway location |
| 330 | +vpnGateway.resourceId // Alias for id |
| 331 | +vpnGateway.subscriptionId // Extracted subscription ID |
| 332 | +``` |
| 333 | + |
| 334 | +## API Version Support |
| 335 | + |
| 336 | +To use a specific API version: |
| 337 | + |
| 338 | +```typescript |
| 339 | +const vpnGateway = new VirtualNetworkGateway(this, 'vpn-gateway', { |
| 340 | + apiVersion: '2024-01-01', |
| 341 | + // ... other properties |
| 342 | +}); |
| 343 | +``` |
| 344 | + |
| 345 | +## Related Resources |
| 346 | + |
| 347 | +- [Azure Resource Group](../azure-resourcegroup) |
| 348 | +- [Azure Virtual Network](../azure-virtualnetwork) |
| 349 | +- [Azure Subnet](../azure-subnet) |
| 350 | +- [Azure Public IP Address](../azure-publicipaddress) |
| 351 | + |
| 352 | +## Azure Documentation |
| 353 | + |
| 354 | +- [Virtual Network Gateway Overview](https://learn.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpngateways) |
| 355 | +- [VPN Gateway SKUs](https://learn.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsku) |
| 356 | +- [ExpressRoute Gateways](https://learn.microsoft.com/en-us/azure/expressroute/expressroute-about-virtual-network-gateways) |
| 357 | +- [BGP Configuration](https://learn.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-bgp-overview) |
| 358 | +- [Point-to-Site VPN](https://learn.microsoft.com/en-us/azure/vpn-gateway/point-to-site-about) |
| 359 | + |
| 360 | +## License |
| 361 | + |
| 362 | +This construct is part of the CDKTF Azure Constructs library. |
0 commit comments