Enabling Azure Site Recovery with encrypted disks

As per (https://docs.microsoft.com/en-us/azure/site-recovery/azure-to-azure-support-matrix) as of September 2018 replication VMs which are using encrypted disks is not supported for ASR scenarios.

chrome_2018-09-06_10-11-26

This is due to the fact that KeyVault which contains encryption key is not being part of ASR replication mechanism and hence it’s impossible to decrypt volumes upon failover.

If you would ASR encrypted machine and boot it up in failover location you will be presented with following screen informing that encryption keys are missing from boot configuration.

vmconnect_2018-09-05_18-01-54

Solution presented below will allow you to use ASR in conjuction with encrypted disks. Solution works around ASR inability to work with encrypted disks by establishing alternative KeyVault in the same location of ASR and replicating neccessary secrets for volume decryption. Subsequent recovery plan remaps keys from original keyvault to failover keyvault which allows machine to boot properly.

Steps

  • Create KeyVault in Failover location.
  • Create automation account in Failover location.
  • Add Azure KeyVault module to automation accountvmconnect_2018-09-05_15-52-55
  • Allow Automation account to access keyvault. For this:
    1. Navigation to automation account and not what is Azure Run As Account isvmconnect_2018-09-05_16-00-30vmconnect_2018-09-05_16-01-54
    2. Add this account to both Source Kevault and Failover keyvault with all permissions in accessing Secretsvmconnect_2018-09-05_16-07-45
  • Create following runbook in Automation account. Purpouse of this runbook is to replicate all secrets between Source and Failover kevault
param(
[Parameter(Mandatory=$true)]
$sourceKeyVaultName,
[Parameter(Mandatory=$true)]
$destinationKeyvaultName
)
Function ExportAllKeys
{
param ($sourceKeyVaultName, $destinationKeyVaultName)
Write-Output "Exporting from $sourceKeyVaultName to $destinationKeyVaultName"
$destinationKeyVault = Get-AzureRMKeyVault name $destinationKeyVaultName
$secrets = Get-AzureKeyVaultSecret VaultName $sourceKeyVaultName
write-Output "Found $secrets in $sourceKeyVaultName"
foreach ($secretin$secrets)
{
Write-Output "Exporting $secret"
$secret = Get-AzureKeyVaultSecret VaultName $sourceKeyVaultName Name $secret.Name
Set-AzureKeyVaultSecret VaultName $destinationKeyVault.VaultName Name $secret.Name SecretValue $secret.SecretValue Tag $secret.Tags ContentType $secret.ContentType
}
}
"Logging in to Azure…"
$Conn = Get-AutomationConnection Name AzureRunAsConnection
Add-AzureRMAccount ServicePrincipal Tenant $Conn.TenantID ApplicationId $Conn.ApplicationID CertificateThumbprint $Conn.CertificateThumbprint
"Selecting Azure subscription…"
Select-AzureRmSubscription SubscriptionId $Conn.SubscriptionID TenantId $Conn.tenantid
ExportAllKeys sourceKeyVaultName $sourceKeyVaultName destinationKeyVaultName $destinationKeyvaultName

view raw
replicatesecrets.ps1
hosted with ❤ by GitHub

  • Start runbook and pass names of Source and Failover Keyvault as parameters

vmconnect_2018-09-05_15-49-40

  • Make sure it completes successfully by examining output of a Job and Status

vmconnect_2018-09-05_16-12-59

Verify that secrets exist now in failover keyvault

PS C:\Users\artis> Get-AzureKeyVaultSecret VaultName "CentralUS-Keyvault" | select Name
Name
—-
013F4325EAEC4ADEBDE4C933053E4F9C
1C66CC2906144047B4A341A9F03F3393
2D984DA0562F43708AE826210DC16176
4CD2F8808FDE47EDA10B52B2AD499B77
5BCD27573DE24B4EA37FDC3DD844B03A
5EE3D1EB4D2E455F9C35F1887B8E7444
6899641A374B474398EAC29919081ACB
B4D6888B10024D36BADBB1C55A247C44
BAC00BB5BE344067AD3F9774A2404393
CF8FBACBA9B1440D94626F176AB43D75
F5FD4AF53171444FB3EEF00A8C957751

view raw
get-keyvault.ps1
hosted with ❤ by GitHub

  • Create 2 additional runbooks. ReencryptVMrunbook contains procedure for post-action for failover plan covering encrypted machines and runs after failover completed.

ReEncryptVM.ps1

param (
[Object]$RecoveryPlanContext # = ('{"RecoveryPlanName":"RecoverSQLservers","FailoverType":"Test","FailoverDirection":"PrimaryToSecondary","GroupId":"Group1","VmMap":{"79b0a60c-a71f-4c0f-a6ec-e62287200466":{"SubscriptionId":"4c120485-e0cd-4787-8dc9-d3608a41fde3","ResourceGroupName":"WestUS-RG","CloudServiceName":null,"RoleName":"sql1-test","RecoveryPointId":"e734ce77-5753-476c-974b-23d50dd2c177","RecoveryPointTime":"\/Date(1535766878775)\/"}}}' | convertfrom-json)
)
Write-output $RecoveryPlanContext
$RecoveryPlanContext = $RecoveryPlanContext | convertfrom-json ErrorAction Ignore
$VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select ExpandProperty Name
$vmMap = $RecoveryPlanContext.VmMap
Write-Output $VMInfo
"Logging in to Azure…"
$Conn = Get-AutomationConnection Name AzureRunAsConnection
Add-AzureRMAccount ServicePrincipal Tenant $Conn.TenantID ApplicationId $Conn.ApplicationID CertificateThumbprint $Conn.CertificateThumbprint
"Selecting Azure subscription…"
Select-AzureRmSubscription SubscriptionId $Conn.SubscriptionID TenantId $Conn.tenantid
foreach($VMID in $VMinfo)
{
$VM = $vmMap.$VMID
if( !(($VM -eq $Null) -Or ($VM.ResourceGroupName -eq $Null) -Or ($VM.RoleName -eq $Null))) {
$keyVaultName = Get-AutomationVariable Name 'FailoverKeyVaultName'
Write-Output "Calling reencrypt OS disk with following parameters vmName:$($Vm.RoleName), rgName:$($VM.ResourceGroupName), keyVaultName:$($keyVaultName)"
.\EncryptVMOSDisk.ps1 VMName $($VM.RoleName) rgName $($VM.ResourceGroupName) keyVaultName $keyVaultName
}
}

view raw
ReEncryptVM.ps1
hosted with ❤ by GitHub

EncryptVMOSDisk runbook is script which performs actual process of shutting down VM and updating location of secret key for decryption to point to location of Failover keyvault

EncryptVMOSDisk.ps1

param (
$VMName, $RGName, $KeyVaultName
)
Function ChangeEncryption{
param (
[Parameter(Mandatory=$true)]
$VMName,
[Parameter(Mandatory=$true)]
$RGName,
[Parameter(Mandatory=$true)]
$KeyVaultName)
$vm = Get-AzureRMVM Name $VMName ResourceGroupName $RGName
Write-Output "Stopping VM $($vm.Name)"
Stop-AzureRmVM Name $VMName ResourceGroupName $RGName Force
$secretValue = Get-AzureKeyVaultSecret VaultName $keyvaultName | Where-Object {$vm.Name -match $_.tags.MachineName }| where-object {$_.tags.VolumeLetter -match "C"}
$secretValue = Get-AzureKeyVaultSecret VaultName $KeyVaultName SecretName $secretValue.Name
Write-Output "Getting secrets from Vault"
$secretURL = $secretValue.Id
$secretID = (Get-AzureRmKeyVault Name $KeyVaultName ResourceGroupName $RGName).ResourceID
$OSdisk = Get-AzureRmDisk ResourceGroupName $RGName name $vm.StorageProfile.OsDisk.Name
$diskupdateconfig = New-AzureRmDiskUpdateConfig EncryptionSettingsEnabled $true
$diskupdateconfig = Set-AzureRmDiskUpdateDiskEncryptionKey DiskUpdate $diskupdateconfig SecretUrl $secretURL SourceVaultId $secretID
Write-Output "Updating OSDisk $($OsDisk.Name)"
Update-AzureRmDisk DiskName $OSdisk.Name ResourceGroupName $OSdisk.ResourceGroupName DiskUpdate $diskupdateconfig
Set-AzureRmVMOSDisk Vm $vm ManagedDiskId $OSdisk.Id CreateOption "Attach" Windows DiskEncryptionKeyURL $secretURL DiskEncryptionKeyVaultID $secretID
Update-AzureRMVM VM $vm ResourceGroupName $vm.ResourceGroupName
Write-Output "Starting VM $($vm.Name)"
Start-AzureRmVM Name $vm.Name ResourceGroupName $RGName
}
"Logging in to Azure…"
$Conn = Get-AutomationConnection Name AzureRunAsConnection
Add-AzureRMAccount ServicePrincipal Tenant $Conn.TenantID ApplicationId $Conn.ApplicationID CertificateThumbprint $Conn.CertificateThumbprint
"Selecting Azure subscription…"
Select-AzureRmSubscription SubscriptionId $Conn.SubscriptionID TenantId $Conn.tenantid
ChangeEncryption VmName $Vmname RGName $RGName KeyVaultName $KeyVaultName

view raw
EncryptVMOSDisk.ps1
hosted with ❤ by GitHub

  • Create recovery plan as usual

vmconnect_2018-09-05_16-19-10

  • Create separate group for encrypted machines (in this case it’s sql and app servers)

vmconnect_2018-09-05_16-33-42

  • Choose post action for Group2 and set it to reencrypt VM

vmconnect_2018-09-05_16-35-42

  • Create variable in Automation Account with name of Failover KeyVault holding keys

vmconnect_2018-09-05_18-19-30

  • Perform test failover to test functionality. If procedure worked as expected you shall be output of the job successful in automation account and you can verify disk encryption status by executing powershell statement ​`​Get-BitLockerVolume -MountPoint c: | fl * -force`

vmconnect_2018-09-05_20-29-05

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s