AWS Route 53 is the DNS service provided by Amazon. It stores all hosted zones for your organization and stores different DNS record types. It performs name resolution of devices and applications. A backup of these records is very important. Therefore, any issue or disaster, you can quickly restore those and keep your name resolution process running.
Recently, I came across a requirement where customer wanted to create an Azure Automation Runbook to take a backup of Route 53 DNS record. They also wanted to restore them on Microsoft Azure DNS as the they are using Azure as their main Cloud Platform.
This script is using Azure Blob to store the backup of AWS Route 53 in a JSON file format, and, this is the first part of the 2 step process. Here I am taking backup of DNS records to Azure blob storage. For second part, refer to my blog post here.
We need to have following prerequisites to run this Runbook :
- AWS Credentials (Access Key, Secret Access Key with proper permissions on Route 53)
- An Azure Key Vault to store AWS credentials (This is a security Best Practice. Instead of hard coding credentials in script or passing as plain text parameter).
- Azure Blob storage container to store backup JSON file. You may refer Microsoft documentations on how to create Storage Account and Container
- An Azure Automation account with permission to the Key Vault and Storage Account
- AWS PowerShell and Azure RM PowerShell Modules configured
In the Second Part, I will share script to restore those records from Blob storage to Azure DNS. Whatever reason you might have, if you just want to backup AWS DNS records, you can use this script. However, if you want to use S3 Bucket or some other file server to store it, you may achieve this with small changes to the script.
Param(
[Parameter(Mandatory=$true)]
[String]$saResourceGroup,
[Parameter(Mandatory=$true)]
[String]$storageAccount,
[Parameter(Mandatory=$true)]
[String]$storageContainer,
[Parameter(Mandatory=$true)]
[String]$kvName
)
#region - Importing Powershell module if it is missing
if((Get-Module -Name AwsPowershell).count -gt 0){
Write-Output "AWS Powershell module is already installed"
}else{
Write-Output "AWS Powershell module missing.Installing the module now"
Import-Module -Name AwsPowershell -Force
}
#endregion
#region - login to Azure from the Automation Account.Setup Automation account as prerequisite.
$connectionName = "AzureRunAsConnection"
try{
#Get the connection 'AzureRunAsConnection'
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch{
if(!$ServicePrincipalConnection){
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
}else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
#endregion
#region - get AWS Route53 user credentials
$awsR53AccessKey = (Get-AzureKeyVaultSecret -VaultName $kvName -Name AWSR53AccessKey).SecretValueText
$awsR53SecretKey = (Get-AzureKeyVaultSecret -VaultName $kvName -Name AWSR53SecretKey).SecretValueText
$region = "US-EAST-2" # Set it to whatever region you have your AWS Region setup
#endregion
#region - Connecting to AWS Account
Set-AWSCredentials -AccessKey $awsR53AccessKey -SecretKey $awsR53SecretKey -StoreAs AWSProfile
Initialize-AWSDefaults -ProfileName AWSProfile -Region $region
#endregion
#region - Collect R53 Data from AWS Account and dump into JSON file
#Find All R53 Hosted Zones
$date = Get-Date -UFormat "%m-%d-%Y_%H%M%S"
$outFileName = "r53Backup-$($date).json"
$outJsonFile = "$($env:TEMP)\$outFileName"
if(Test-Path $outJsonFile){
Remove-Item $outJsonFile -Force
}
New-Item -Path $outJsonFile -ItemType File
$jsonData = @{}
try{
$Zones = Get-R53HostedZones -ProfileName AWSProfile
foreach ($zone in $Zones)
{
#Iterate through each hosted zone and generate JSON file with each record
$recordDataSets = @()
foreach ($Recordset in (Get-R53ResourceRecordSet -ProfileName AWSProfile -HostedZoneId $zone.Id).ResourceRecordSets)
{
$data = ""
if ($Recordset.ResourceRecords.Count -gt 1)
{
foreach ($entry in $Recordset.ResourceRecords)
{
$data += $($entry.value) + ";"
}
}
else
{
$data = $Recordset.ResourceRecords.Value
}
if($data){$data = $data.TrimEnd(";")}
#Generate Custom Object of record sets
$recordDataSet = @{}
$recordDataSet.Add('RecordSetName',$Recordset.Name)
$recordDataSet.Add('CallerReference',$Recordset.CallerReference)
$recordDataSet.Add('Type',$Recordset.Type)
$recordDataSet.Add('SetIdentifier',$Recordset.SetIdentifier)
$recordDataSet.Add('Weight',$Recordset.Weight)
$recordDataSet.Add('Region',$Recordset.Region)
$recordDataSet.Add('GeoLocation',$Recordset.GeoLocation)
$recordDataSet.Add('TTL',$Recordset.TTL)
$recordDataSet.Add('ResourceRecord',$data)
$recordDataSet.Add('AliasTarget',$Recordset.AliasTarget)
$recordDataSet.Add('TrafficPolicyInstanceID',$Recordset.TrafficPolicyInstanceId)
$recordDataSets += $recordDataSet
}
$jsonData | Add-Member -Type NoteProperty -Name $zone.Name -Value $recordDataSets
}
$jsonData | ConvertTo-Json | Out-File $outJsonFile
}
catch{
Write-Error -Message $_.Exception
throw $_.Exception
}
#endregion
#region - Connect to a storage account and dump R53 backup JSON to a blob
try{
$saContext = (Get-AzureRmStorageAccount -ResourceGroupName $saResourceGroup -Name $storageAccount).Context
if(!(Get-AzureStorageContainer -Container $storageContainer -Context $saContext -ErrorAction 'SilentlyContinue')){
New-AzureStorageContainer -Name $storageContainer -Permission Container -Context $saContext
}
Set-AzureStorageBlobContent -Container $storageContainer -Context $saContext -File $outJsonFile -Blob "route53\$outFileName" -Force
}
catch{
Write-Error -Message $_.Exception
throw $_.Exception
}
#endregion
Login to Azure Portal using https://portal.azure.com and open Azure Automation Accounts from left pane.
Once logged in, open configured Azure Automation account and select Runbooks from Process Automation option in the left pane.
Create a new Runbook using the script above and save it. Once, it is saved run the Runbook from the list.