When you are running your home lab you often have to deal with dynamic IP on your ISP. Most of the time you can just live with it and add some noip magic to update a DNS record. But sometimes you just can’t use it as you are asked for an IP and not a FQDN. It’s the case when configuring the Site-to-Site IPSec VPN between Azure and your on premises infrastructure.
So we need to figure out how to allow this setup while having a dynamic IP as my on-premises lab is behind a consumer ISP where there my public IP is changing each time I restart the router.
Azure PowerShell is here to help us!
First of all, I’m using this function (https://gallery.technet.microsoft.com/scriptcenter/Validate-an-Ipaddress-is-03481731):
<# Function IS-InSubnet .Synopsis Validates an ipaddress is in a given subnet based on CIDR notation .DESCRIPTION Clone to the c# code given in http://social.msdn.microsoft.com/Forums/en-US/29313991-8b16-4c53-8b5d-d625c3a861e1/ip-address-validation-using-cidr?forum=netfxnetcom .EXAMPLE IS-InSubnet -ipaddress 10.20.20.0 -Cidr 10.20.20.0/16 .Author Srinivasa Rao Tumarada #> Function IS-InSubnet() { [CmdletBinding()] [OutputType([bool])] Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] [validatescript({([System.Net.IPAddress]$_).AddressFamily -match 'InterNetwork'})] [string]$ipaddress="", [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=1)] [validatescript({(([system.net.ipaddress]($_ -split '/'|select -first 1)).AddressFamily -match 'InterNetwork') -and (0..32 -contains ([int]($_ -split '/'|select -last 1) )) })] [string]$Cidr="" ) Begin{ [int]$BaseAddress=[System.BitConverter]::ToInt32((([System.Net.IPAddress]::Parse(($cidr -split '/'|select -first 1))).GetAddressBytes()),0) [int]$Address=[System.BitConverter]::ToInt32(([System.Net.IPAddress]::Parse($ipaddress).GetAddressBytes()),0) [int]$mask=[System.Net.IPAddress]::HostToNetworkOrder(-1 -shl (32 - [int]($cidr -split '/' |select -last 1))) } Process{ if( ($BaseAddress -band $mask) -eq ($Address -band $mask)) { $status=$True }else { $status=$False } } end { Write-output $status } }
And this is the script I’m currently running from one of the on-prem server:
# Script variables $strAzureResourceGroup = "Tech-Addict-RG" $strTempFolder = "C:\Tempp" # Check if the Temp folder exists, if not create it if(-Not(Test-Path $strTempFolder)){ New-Item -Path $strTempFolder -ItemType Directory -Force } $azcontextFile = "AzContext.json" # Check if there is already an Azure Context File, if yes: Import it; if no: Ask for a Azure logon and save the Context in a file for future use if(Test-Path -Path $strTempFolder\$azcontextFile){ Import-AzContext -Path $azcontextFile } else { Connect-AzAccount Save-AzContext -Path $strTempFolder\$azcontextFile } # Retrieve current Public IP $IPLAB = $(Invoke-RestMethod http://ipinfo.io/json).ip # Retrieve the list of local IP (used to determine wich Gateway we need to update) $LocalIPs = $(Get-NetIPAddress -AddressFamily IPv4).IPAddress # Retrieve all Azure Local Network Gateways in the given Azure ResourceGroup $LocalNetWorkGateways = Get-AzLocalNetworkGateway -ResourceGroupName $strAzureResourceGroup <# Looping to see if : - One of the local IP is included in the Subnet of a Local Gateway - If yes, verify if the Public IP on the Azure Gateway is still the good one - If not, update the public IP #> foreach($LocalNetWorkGateway in $LocalNetWorkGateways){ foreach($LocalSubnet in $LocalNetWorkGateway.LocalNetworkAddressSpace.AddressPrefixes){ foreach($LocalIP in $LocalIPs){ if(IS-InSubnet -ip $LocalIP -Cidr $LocalSubnet){ if(-Not($IPLAB -eq $LocalNetWorkGateway.GatewayIpAddress)){ $LocalNetWorkGateways.GatewayIpAddress = $IPLAB Set-AzLocalNetworkGateway -LocalNetworkGateway $LocalNetWorkGateway } } } } }
You just have to schedule this script on a regular basis!
Thanks for such a beautiful post, very informative and useful article