BrownField/Networking/VPN-SDWAN/NSX-T/Scripts/New-IfNotExist-IPSecSessionRouteBased.ps1 (375 lines of code) (raw):
function New-IfNotExist-IPSecSession-RouteBased {
param(
[string]$avsnsxTmanager,
[string]$nsxtUserName,
[SecureString]$nsxtPassword,
[string]$tier1GatewayName,
[string]$vpnServiceName,
[string]$localEndpointPath,
[string]$remoteGatewayIP,
[string]$localAddress,
[string]$sessionName
)
if (Get-IPSecSession-RouteBased -avsnsxTmanager $avsnsxTmanager `
-nsxtUserName $nsxtUserName `
-nsxtPassword $nsxtPassword `
-tier1GatewayName $tier1GatewayName `
-vpnServiceName $vpnServiceName `
-sessionName $sessionName) {
Write-Host "IPSec Session with name '$sessionName' already exists."
} else {
try {
Write-Host "IPSec Session '$sessionName' not found. Creating..."
New-IPSecSession-RouteBased -avsnsxTmanager $avsnsxTmanager `
-nsxtUserName $nsxtUserName `
-nsxtPassword $nsxtPassword `
-tier1GatewayName $tier1GatewayName `
-vpnServiceName $vpnServiceName `
-localEndpointPath $localEndpointPath `
-remoteGatewayIP $remoteGatewayIP `
-localAddress $localAddress `
-sessionName $sessionName
write-host "IPSec Session '$sessionName' created successfully."
} catch {
Write-Error "Failed to create IPSec Session '$sessionName': $_"
}
}
}
function Get-IPSecSession-RouteBased {
param(
[string]$avsnsxTmanager,
[string]$nsxtUserName,
[SecureString]$nsxtPassword,
[string]$tier1GatewayName,
[string]$vpnServiceName,
[string]$sessionName
)
$ipsecSessionUrl = [string]::Format(
"$avsnsxTmanager/policy/api/v1/infra/tier-1s/{0}" +
"/ipsec-vpn-services/{1}/sessions",
$tier1GatewayName,
$vpnServiceName
)
try {
$response = Invoke-APIRequest -method "Get" `
-url $ipsecSessionUrl `
-avsnsxtUrl $avsnsxTmanager `
-avsnsxtUserName $nsxtUserName `
-avsnsxtPassword $nsxtPassword
$ipsecSessions = $response.results | Where-Object { $_.display_name -eq $sessionName }
if ($ipsecSessions) {
return $true
} else {
return $false
}
} catch {
Write-Error "Failed to get IPSec Sessions: $_"
}
}
function New-IPSecSession-RouteBased {
param(
[string]$avsnsxTmanager,
[string]$nsxtUserName,
[SecureString]$nsxtPassword,
[string]$tier1GatewayName,
[string]$vpnServiceName,
[string]$localEndpointPath,
[string]$remoteGatewayIP,
[string]$localAddress,
[string]$ikeProfileName = "nsx-default-l3vpn-ike-profile",
[string]$ipsecProfileName = "nsx-default-l3vpn-tunnel-profile",
[string]$dpdProfileName = "nsx-default-l3vpn-dpd-profile",
[string]$sessionName
)
$ike_profile_path = Get-IKEProfilePath -avsnsxTmanager $avsnsxTmanager `
-nsxtUserName $nsxtUserName `
-nsxtPassword $nsxtPassword `
-ikeProfileName $ikeProfileName
$ipsec_profile_path = Get-IPSecProfilePath -avsnsxTmanager $avsnsxTmanager `
-nsxtUserName $nsxtUserName `
-nsxtPassword $nsxtPassword `
-ipsecProfileName $ipsecProfileName
$dpd_profile_path = Get-DPDProfilePath -avsnsxTmanager $avsnsxTmanager `
-nsxtUserName $nsxtUserName `
-nsxtPassword $nsxtPassword `
-dpdProfileName $dpdProfileName
$psk = New-PSK -length 8
$tunnelAddressSpace = Get-Tunnel-AddressSpace -baseNetworkAddress $localAddress
if (-not $ike_profile_path -or
-not $ipsec_profile_path -or
-not $dpd_profile_path -or
-not $psk -or
-not $tunnelAddressSpace) {
Write-Error "Failed to get IKE Profile,IPSec, DPD Profile, PSK or Tunnel Interface Address."
return $null
}
$ipsecSessionUrl = [string]::Format(
"$avsnsxTmanager/policy/api/v1/infra/tier-1s/{0}" +
"/ipsec-vpn-services/{1}/sessions/{2}",
$tier1GatewayName,
$vpnServiceName,
$sessionName
)
$body = @{
resource_type = "RouteBasedIPSecVpnSession"
enabled = $true
display_name = $sessionName
local_endpoint_path = $localEndpointPath
peer_address = $remoteGatewayIP
authentication_mode = "PSK"
psk = $psk
peer_id = $remoteGatewayIP
ike_profile_path = $ike_profile_path
tunnel_profile_path = $ipsec_profile_path
dpd_profile_path = $dpd_profile_path
connection_initiation_mode = "INITIATOR"
tunnel_interfaces = @(
@{
ip_subnets = @(
@{
ip_addresses = @($tunnelAddressSpace.split("/")[0])
prefix_length = $tunnelAddressSpace.split("/")[-1]
}
)
}
)
compliance_suite = "NONE"
id = $sessionName
}
$jsonBody = $body | ConvertTo-Json -Depth 10
try {
$response = Invoke-APIRequest -method "Put" `
-url $ipsecSessionUrl `
-body $jsonBody `
-avsnsxtUrl $avsnsxTmanager `
-avsnsxtUserName $nsxtUserName `
-avsnsxtPassword $nsxtPassword
} catch {
Write-Error "Failed to create IPSec Session '$sessionName': $_"
}
}
function Get-IKEProfilePath {
param(
[string]$avsnsxTmanager,
[string]$nsxtUserName,
[SecureString]$nsxtPassword,
[string]$ikeProfileName
)
$ikeProfileUrl = [string]::Format(
"$avsnsxTmanager/policy/api/v1/search/aggregate?page_size=50" +
"&cursor=0&sort_by=display_name&sort_ascending=true"
)
$body = @{
primary = @{
resource_type = "IPSecVpnIkeProfile"
}
related = @(
@{
resource_type = "PolicyBasedIPSecVpnSession OR RouteBasedIPSecVpnSession"
join_condition = "ike_profile_path:path"
alias = "sessions"
size = 0
}
)
}
try {
$response = Invoke-APIRequest -method "Post" `
-url $ikeProfileUrl `
-body ($body | ConvertTo-Json) `
-avsnsxtUrl $avsnsxTmanager `
-avsnsxtUserName $nsxtUserName `
-avsnsxtPassword $nsxtPassword
$ikeProfilePath = $response.results |
Where-Object {
$_.primary -and
$_.primary.display_name -and
$_.primary.display_name -eq $ikeProfileName
} |
Select-Object -ExpandProperty primary |
Select-Object -ExpandProperty path
if ($ikeProfilePath) {
return $ikeProfilePath
} else {
Write-Error "IKE Profile '$ikeProfileName' not found."
return $null
}
} catch {
Write-Error "Failed to get IKE Profile: $_"
return $null
}
}
function Get-IPSecProfilePath {
param(
[string]$avsnsxTmanager,
[string]$nsxtUserName,
[SecureString]$nsxtPassword,
[string]$ipsecProfileName
)
$ipsecProfileUrl = [string]::Format(
"$avsnsxTmanager/policy/api/v1/search/aggregate?page_size=50" +
"&cursor=0&sort_by=display_name&sort_ascending=true"
)
$body = @{
primary = @{
resource_type = "IPSecVpnTunnelProfile"
}
related = @(
@{
resource_type = "PolicyBasedIPSecVpnSession OR RouteBasedIPSecVpnSession"
join_condition = "tunnel_profile_path:path"
alias = "sessions"
size = 0
}
)
}
try {
$response = Invoke-APIRequest -method "Post" `
-url $ipsecProfileUrl `
-body ($body | ConvertTo-Json) `
-avsnsxtUrl $avsnsxTmanager `
-avsnsxtUserName $nsxtUserName `
-avsnsxtPassword $nsxtPassword
$ipsecProfilePath = $response.results |
Where-Object {
$_.primary -and
$_.primary.display_name -and
$_.primary.display_name -eq $ipsecProfileName
} |
Select-Object -ExpandProperty primary |
Select-Object -ExpandProperty path
if ($ipsecProfilePath) {
return $ipsecProfilePath
} else {
Write-Error "IPSec Profile '$ipsecProfileName' not found."
return $null
}
} catch {
Write-Error "Failed to get IPSec Profile: $_"
return $null
}
}
function Get-DPDProfilePath {
param(
[string]$avsnsxTmanager,
[string]$nsxtUserName,
[SecureString]$nsxtPassword,
[string]$dpdProfileName
)
$dpdProfileUrl = [string]::Format(
"$avsnsxTmanager/policy/api/v1/search/aggregate?page_size=50" +
"&cursor=0&sort_by=display_name&sort_ascending=true"
)
$body = @{
primary = @{
resource_type = "IPSecVpnDpdProfile"
}
related = @(
@{
resource_type = "PolicyBasedIPSecVpnSession OR RouteBasedIPSecVpnSession"
join_condition = "dpd_profile_path:path"
alias = "sessions"
size = 0
}
)
}
try {
$response = Invoke-APIRequest -method "Post" `
-url $dpdProfileUrl `
-body ($body | ConvertTo-Json) `
-avsnsxtUrl $avsnsxTmanager `
-avsnsxtUserName $nsxtUserName `
-avsnsxtPassword $nsxtPassword
$dpdProfilePath = $response.results |
Where-Object {
$_.primary -and
$_.primary.display_name -and
$_.primary.display_name -eq $dpdProfileName
} |
Select-Object -ExpandProperty primary |
Select-Object -ExpandProperty path
if ($dpdProfilePath) {
return $dpdProfilePath
} else {
Write-Error "DPD Profile '$dpdProfileName' not found."
return $null
}
} catch {
Write-Error "Failed to get DPD Profile: $_"
return $null
}
}
function New-PSK {
param (
[int]$length = 8
)
if ($length -lt 8) {
throw "PSK length must be at least 8 characters."
}
# Define character sets
$upperCase = 'A'..'Z'
$lowerCase = 'a'..'z'
$digits = '0'..'9'
$specialChars = ('!'..'/' + ':'..'@' + '['..'`' + '{'..'~')
# Ensure at least one character from each set
$psk = @(
$upperCase | Get-Random
$lowerCase | Get-Random
$digits | Get-Random
$specialChars | Get-Random
)
# Fill the remaining characters
$allChars = $upperCase + $lowerCase + $digits + $specialChars
for ($i = $psk.Count; $i -lt $length; $i++) {
$psk += $allChars | Get-Random
}
# Shuffle the result
$psk = $psk | Sort-Object { Get-Random }
# Convert to string and return
return -join $psk
}
function Get-Tunnel-AddressSpace {
param (
[string]$baseNetworkAddress
)
# Helper function to ensure the new network is within RFC1918 address space
function Test-RFC1918Address {
param (
[uint32]$addressUInt32
)
$rfc1918Ranges = @(
@{ Start = [BitConverter]::ToUInt32([System.Net.IPAddress]::Parse("10.0.0.0").GetAddressBytes(), 0); End = [BitConverter]::ToUInt32([System.Net.IPAddress]::Parse("10.255.255.255").GetAddressBytes(), 0) },
@{ Start = [BitConverter]::ToUInt32([System.Net.IPAddress]::Parse("172.16.0.0").GetAddressBytes(), 0); End = [BitConverter]::ToUInt32([System.Net.IPAddress]::Parse("172.31.255.255").GetAddressBytes(), 0) },
@{ Start = [BitConverter]::ToUInt32([System.Net.IPAddress]::Parse("192.168.0.0").GetAddressBytes(), 0); End = [BitConverter]::ToUInt32([System.Net.IPAddress]::Parse("192.168.255.255").GetAddressBytes(), 0) }
)
foreach ($range in $rfc1918Ranges) {
if ($addressUInt32 -ge $range.Start -and $addressUInt32 -le $range.End) {
return $true
}
}
return $false
}
# Extract the base network address and subnet mask
$originalNetwork, $prefixLength = $baseNetworkAddress -split '/'
$prefixLength = [int]$prefixLength
# Convert the base network address to an array of bytes
$baseAddressBytes = [System.Net.IPAddress]::Parse($originalNetwork).GetAddressBytes()
# Increment the third octet
$baseAddressBytes[2] = ($baseAddressBytes[2] + 1) % 256
# Set the fourth octet to 1
$baseAddressBytes[3] = 1
# Convert the byte array to an integer
$newSubnetStartUInt32 = [BitConverter]::ToUInt32($baseAddressBytes, 0)
# Ensure the new network is within RFC1918 address space
while (-not (Test-RFC1918Address -addressUInt32 $newSubnetStartUInt32)) {
$baseAddressBytes[2] = ($baseAddressBytes[2] + 1) % 256
$newSubnetStartUInt32 = [BitConverter]::ToUInt32($baseAddressBytes, 0)
}
# Convert the integer back to a byte array
$newSubnetStartBytes = [BitConverter]::GetBytes($newSubnetStartUInt32)
# Set the prefix length for the new subnet
$newPrefixLength = 30
# Convert the byte array back to an IP address string
$newAddress = [System.Net.IPAddress]::new($newSubnetStartBytes).ToString()
# Return the new subnet address with the new prefix length
return "$newAddress/$newPrefixLength"
}