Configuring failover for user-defined routing in Azure
A failover configuration enables traffic to bypass Cloud Accelerator in the event of a failure and go directly to client networks. When the Cloud Accelerator becomes available again, traffic reroutes through it. Failover requires an Azure API management service, runbook, and logic app. These are the general steps for setting up failover for user-defined routing. Consult Microsoft Azure documentation for details about its user-defined routing feature.
1. In Azure, create an API management service.
2. Add the Cloud Accelerator’s key certificate as the root certificate. You’ll need to copy the PEM certificate, save it with the file extension .cer, and then upload the .cer file as the root certificate.
3. Enter a name and suffix for the API.
4. Add a GET method.
5. Point the front end URL to #.
6. Point the back end URL to https://<device-ip>/api/common/1.0/ping. Replace <device-ip> with the Cloud Accelerator’s public IP address or DNS name.
7. Disable Subscription required.
8. Create a standalone Azure automation account.
9. Create a Run As account in the automation account.
10. Open PowerShell, and then define the runbook parameters.
11. Create acceleration routes using runbook using the following script. You’ll need to change parameters for your specific configuration:
.\scripts\Create-AccelerationRoutes-Runbook.ps1 -ProjectName "azk" -Location "koreacentral" ` -AutomationAccountName "azk-automation-koreacentral" -searchResourcesDetailByName @parameters
12. Start the runbook. The main parameters are: BYPASSACCELERATION and VERBOSE. By default, the runbook attaches the acceleration route tables to subnets in order to chain the acceleration service. If BYPASSACCELERATION=true, then the runbook will bypass the acceleration routes. VERBOSE=true enables capture of the runbook output.
13. Create Logic apps
14. Add Recurrence timer. Set the time interval to 10-30 seconds.
15. Select the API management service, and then disable retry policy.
16. Define an if-else condition based on the status code of the Body attribute in the HTTP response packet. The True and False conditions call the web hook defined for the job in the runbook automation.
17. Select all run-after conditions.
Example runbook parameters
### Create the runbook for the sample AZK
$parameters = @{
>> VirtualNetworkName = "Vnet-server"
>> VirtualNetworkResourceGroupName = "Vnet-to-Vnet-LB"
>> RouteTablesResourceGroupName = "Vnet-to-Vnet-LB"
>> subnetName_transit = "GatewaySubnet"
>> subnetName_servernetwork = "server-nw"
>> subnetName_acceleration = "server-SH-LB"
>> routeTableName_servernetwork = ""
>> routeTableName_acceleration = ""
>> routeTableName_transit_ACCELERATION = "lb-gw-to-server"
>> routeTableName_transit = ""
>> routeTableName_servernetwork_ACCELERATION = "lb-to-vpnbgp"
>> }
Example runbook
<#
.DESCRIPTION
Riverbed Community Toolkit
Cloud Community Cookbooks for Acceleration in Azure
Set or Bypass Acceleration Routes, attaching/detaching Route Tables to subnets: transit, servernetwork and acceleration.
This is a script template to be used as a PowerShell Runbook. It requires configuration in the Customization region, setting variables for VNET, resource group, routes details.
By default, the execution of the script will enable acceleration attaching Acceleration Route Tables.
Setting parameter $BypassAcceleration will detach acceleration route tables and attach bypass routes instead.
Usage in Azure Automation Runbook
Requirements in Automation Account, Shared Resources
* Modules: Az.Accounts, Az.Automation, Az.Network
* Connections: AzureRunAsAccount
Runbook definition
* name: Set-AccelerationRoutes
* type: PowerShell
* description: Set or Bypass Acceleration
* edit PowerShell runbook: copy and paste, configure the Customization region if needed
* Save and Publish
.EXAMPLE
# Set acceleration
Run job without parameters to enable Acceleration
.EXAMPLE
# Bypass Acceleration
Run job with BypassAcceleration = true ("true" is correct. It is not "$true", as there Azure PowerShell RunBook does not take $ sign)
.EXAMPLE
# Verbose
Run job with Verbose = true
#>
# parameters
param(
[switch][bool]$BypassAcceleration = $false,
[switch][bool]$Verbose = $false,
[switch][bool]$WhatIf = $false
)
#region Customization
$virtualNetworkName = "Vnet-server" # VNET, ex. "azu-hub-westus"
$virtualNetworkResourceGroupName = "Vnet-to-Vnet-LB" # ex. "azu-hub-westus"
$AccelerationRoutes = @{
"server-nw" = @{
AddressPrefix = "10.8.2.0/24" # ex. "10.1.1.0/24"
RouteTableId = "/subscriptions/4c29628e-bd15-4877-b8ac-61be9439e3d0/resourceGroups/Vnet-to-Vnet-LB/providers/Microsoft.Network/routeTables/lb-to-vpnbgp" # ex. "/subscriptions/1234-12341243-1243-12341324/resourceGroups/azu-acceleration/providers/Microsoft.Network/routeTables/azu-servernetwork-ACCELERATION"
}
GatewaySubnet = @{
AddressPrefix = "10.8.3.0/24" # ex. "10.1.0.0/24"
RouteTableId = "/subscriptions/4c29628e-bd15-4877-b8ac-61be9439e3d0/resourceGroups/Vnet-to-Vnet-LB/providers/Microsoft.Network/routeTables/lb-gw-to-server" # ex."/subscriptions/1234-12341243-1243-12341324/resourceGroups/azu-acceleration/providers/Microsoft.Network/routeTables/azu-transit-ACCELERATION"
}
}
$BypassRoutes = @{
"server-nw" = @{
AddressPrefix = "10.8.2.0/24" # ex. "10.1.1.0/24"
RouteTableId = "" # ex. "/subscriptions/1234-12341243-1243-12341324/resourceGroups/azu-acceleration/providers/Microsoft.Network/routeTables/azu-servernetwork"
}
GatewaySubnet = @{
AddressPrefix = "10.8.3.0/24" # ex. "10.1.0.0/24"
RouteTableId = "" # ex. empty to detach the Route Table
}
}
#endregion
#region lib
Import-Module Az.Accounts
Import-Module Az.Network
Import-Module Az.Automation
try
{
$connectionName = "AzureRunAsConnection"
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId
-ApplicationId $servicePrincipalConnection.ApplicationId
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch
{
"IN catch"
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName failed."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
#endregion
#variables
$routes = $AccelerationRoutes
if ($BypassAcceleration) {
$routes = $BypassRoutes
}
$vnet = Get-AzVirtualNetwork -ResourceGroupName $virtualNetworkResourceGroupName -Name $virtualNetworkName
#verbose
if ($Verbose) {
# Check subnet name, prefix and route table id
Write-Output "-----------------"
Write-Output "INITIAL STATE"
Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet | % { "$($_.Name) , $($_.AddressPrefix) , $($_.RouteTable.Id)" }
Write-Output "-----------------"
if ($BypassAcceleration) { Write-Output "BYPASS ACCELERATION ROUTES:" }
else { Write-Output "SET ACCELERATION ROUTES:" }
foreach ($subnetName in $routes.Keys) { "$subnetName $($routes[$subnetName].AddressPrefix ; $routes[$subnetName].RouteTableId)" }
}
# Prepare and apply config on the vnet
foreach ($subnetName in $routes.Keys) {
$routeTableId = $routes[$subnetName].RouteTableId
$addressPrefix = $routes[$subnetName].AddressPrefix
if (!$routeTableId) {
#Disassociate"
$subnet = ($vnet.Subnets | Where-Object { $_.Name -eq $subnetName })
$subnet.RouteTable = $null
}
else {
# Prepare config to associate Route tables to subnets
$output = Set-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet -Name $subnetName -AddressPrefix $addressPrefix -RouteTableId $routeTableId -WarningAction SilentlyContinue
}
}
#verbose
if ($Verbose) {
# Check subnet name, prefix and route table id
Write-Output "-----------------"
Write-Output "VNET NEW CONFIG TO APPLY"
Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet | % { "$($_.Name) , $($_.AddressPrefix) , $($_.RouteTable.Id)" }
}
# Apply
if (!$WhatIf) {
Write-Output "-----------------"
Write-Output "APLYING VNET NEW CONFIG"
$output = Set-AzVirtualNetwork -VirtualNetwork $vnet
}
#verbose
if ($Verbose) {
# Check subnet name, prefix and route table id
Write-Output "-----------------"
Write-Output "END STATE"
$vnet = Get-AzVirtualNetwork -ResourceGroupName $virtualNetworkResourceGroupName -Name $virtualNetworkName
Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet | % { "$($_.Name) , $($_.AddressPrefix) , $($_.RouteTable.Id)" }
}