# Backup and Restore Azure Firewall


# Issue

{{< admonition warning "Azure Firewall has no backup feature. Yes, really." true  >}}
Surprisingly, there is no config back facility within Azure Firewall. It is typical to regularly create a backup of the config and also to perform backup prior to a change.
{{< /admonition >}} 

Let's address that with some PowerShell.

<br>

# Solution
We can leverage the [Export-AzResourceGroup](https://docs.microsoft.com/en-us/powershell/module/az.resources/export-azresourcegroup) cmdlet to create an effective backup by exporting a deployment JSON template. 

This post will create a local backup useful for:
1. A restore point for an adhoc change.
2. Documenting a recent deployment.

A future post will address automating a backup.

{{< admonition note "" true  >}}
Note, I am using [PoshLog](https://github.com/PoShLog/PoShLog) for logging. <br>
Check out my previous [post](https://siliconwolf.net/powershell-logging-snippet/) on PowerShell logging. 
{{< /admonition >}} 

<br>

## Backup

Create a backup of the firewall and store to the local machine.

<br>

```powershell
# BACKUP AZURE FIREWALL RESOURCE: #############################################
# DEFINITIONS: ################################################################
# Tenancy: --------------------------------------------------------------------
$SubscriptionId         = "[REDACTED]"
$TenantId               = "[REDACTED]"

# Firewall: -------------------------------------------------------------------
$AzFwName               = "fw-hub-ase-01"
$AzFwBackupFileName     = "Backup-$AzFwName-$(Get-Date -Format 'yyyy-MM-dTHH-mm-ss').json"
$FirewallBackup         = [System.IO.Path]::Combine($BackupFilePath, $AzFwBackupFileName)

# Backup Location: ------------------------------------------------------------
$BackupFilePath         = "C:\Temp\" 

# Logging: --------------------------------------------------------------------
$LogPath                = "C:\Temp\"
$LogFilename            = "Log-$(Get-Date -Format 'yyyy-MM-dTHH-mm-ss').log"
$Log                    = [System.IO.Path]::Combine($LogPath, $LogFilename  )

$Logger = New-Logger |
     Set-MinimumLevel -Value Verbose |
     Add-EnrichWithProperty -Name UserName -Value $($env:USERNAME).ToLower() |
     Add-EnrichWithEnvironment -UserName -MachineName |
     Add-EnrichWithProcessId | Add-EnrichWithProcessName |
     Add-EnrichWithExceptionDetails |
     Add-SinkFile -Path $Log -OutputTemplate '[ {Level:u3} ] [ {UserName}@{MachineName} ] [ PID: {ProcessName}:{ProcessId} ] [ {Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} ] {Message:lj}{NewLine}{Exception}' |
     Add-SinkConsole -OutputTemplate "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" | 
     Start-Logger -PassThru

Write-InfoLog "Log File Location: {log}" -PropertyValues $Log

# CONNECTION: #################################################################
# Connect to Tenancy: ---------------------------------------------------------
try {
    Write-InfoLog "Connecting to Azure Subscription [ {SubscriptionID} ] on tenancy [ {TenantId} ]..." -PropertyValues $SubscriptionID, $TenantId
    Connect-AzAccount -Subscription $SubscriptionId -Tenant $TenantId -ErrorAction Stop
}
catch {
    Write-WarningLog "Connecting to Azure Subscription [ {SubscriptionID} ] on tenancy [ {TenantId} ] failed!" -PropertyValues $SubscriptionID, $TenantId
    Write-ErrorLog -Exception $_
    exit

} # END try/catch

# BACKUP: #####################################################################
try {
    # Capture the firewall object.
    Write-InfoLog "Capturing Azure Firewall Object [ {AzFwName} ]..." -PropertyValues $AzFwName
    $AzFw = Get-AzFirewall -Name $AzFwName -ErrorAction Stop

    # Export the JSON template.
    Write-InfoLog "Backing up [ $($AzFw.Name) ] firewall config to {FirewallBackup}" -PropertyValues $FirewallBackup
    Export-AzResourceGroup -ResourceGroupName $AzFw.ResourceGroupName -Resource $AzFw.Id -SkipAllParameterization -Path $FirewallBackup -ErrorAction Stop

}
catch {
    Write-WarningLog "Backing up [ $($AzFw.Name) ] firewall config to ${FirewallBackup} failed." -PropertyValues $FirewallBackup
    Write-ErrorLog -Exception $_
    exit
    
} # END try/catch

Close-Logger
```
<br>

With a successful backup changes can be made to the firewall with the option of a rollback.

<br>

## Rollback  
The rollback assumes maintaining the current PowerShell session with the loaded variables.

<br>

```powershell
# Restore Firewall Object: ####################################################
# Restart the Logger: ---------------------------------------------------------
$Logger = New-Logger |
     Set-MinimumLevel -Value Verbose |
     Add-EnrichWithProperty -Name UserName -Value $($env:USERNAME).ToLower() |
     Add-EnrichWithEnvironment -UserName -MachineName |
     Add-EnrichWithProcessId | Add-EnrichWithProcessName |
     Add-EnrichWithExceptionDetails |
     Add-SinkFile -Path $Log -OutputTemplate '[ {Level:u3} ] [ {UserName}@{MachineName} ] [ PID: {ProcessName}:{ProcessId} ] [ {Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} ] {Message:lj}{NewLine}{Exception}' |
     Add-SinkConsole -OutputTemplate "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" | 
     Start-Logger -PassThru

try {
   # Deploy the rollback JSON template: ---------------------------------------
   Write-InfoLog "Restoring [ $($AzFw.Name) ] from [ {FirewallBackup} ]..." -PropertyValues $FirewallBackup
   New-AzResourceGroupDeployment -Name "FirewallRestoreJob" -ResourceGroupName $AzFw.ResourceGroupName -TemplateFile "$FirewallBackup" -ErrorAction Stop
   Write-InfoLog "Restore [ $($AzFw.Name) ] from [ {FirewallBackup} ] complete." -PropertyValues $FirewallBackup   
}
catch {
   Write-InfoLog "Restoring [ $($AzFw.Name) ] from [ {FirewallBackup} ] failed!" -PropertyValues $FirewallBackup
   Write-ErrorLog -Exception $_
   
} # END try/catch

Close-Logger $Logger
```

<br>
{{< admonition note "" true  >}}
A backup and restore has been tested and functions as at the time of writing. Azure Firewall is a developing product so always test in development to ensure the expected behaviour.
{{< /admonition >}} 

<br>

# Summary

{{< admonition success "Done!" true  >}}
Hopefully this post shows you how simply you can create a backup and restore your way out of trouble.
{{< /admonition >}} 

Hope that helps! 


