Setting up Azure Disk Encryption for a Virtual Machine with PowerShell

As I discussed in my previous blog post, I opted to use Azure Disk Encryption for my virtual machines in Azure, rather than Storage Service Encryption. Azure Disk Encryption utilizes Bitlocker inside of the VM. Enabling Azure Disk Encryption involves these Azure services:

  • Azure Active Directory for a service principal
  • Azure Key Vault for a KEK (key encryption key) which wraps around the BEK (bitlocker encryption key)
  • Azure Virtual Machine (IaaS)

Following are 4 scripts which configures encryption for an existing VM. I initially had it all as one single script, but I purposely separated them. Now that they are modular, if you already have a Service Principal and/or a Key Vault, you can skip those steps. I have my 'real' version of these scripts stored in an ARM Visual Studio project (same logic, just with actual names for the Azure services). These PowerShell templates go along with other ARM templates to serve as source control for our Azure infrastructure.

As any expert will immediately know by looking at my scripts below, I'm pretty much a PowerShell novice. So, be kind dear reader. My purpose is to document the steps, the flow,add some commentary, and to pull together a couple pieces I found on different documentation pages. 


Step 1: Set up Service Principal in AAD

<#
.SYNOPSIS
Creates Service Principal in Azure Active Directory
.DESCRIPTION
This script creates a service principal in Azure Active Directory. 
A service principal is required to enable disk encryption for VM.
.NOTES
File Name: CreateAADSvcPrinForDiskEncryption.ps1
Author : Melissa Coates
Notes: Be sure the variables in the input area are completed, following all standard naming conventions.
The $aadSvcPrinAppPassword needs to be removed before saving this script in source control.
.LINK
Supporting information: 
https://blogs.msdn.microsoft.com/azuresecurity/2015/11/16/explore-azure-disk-encryption-with-azure-powershell/
https://docs.microsoft.com/en-us/azure/security/azure-security-disk-encryption 
#>

#-----------------------------------------

#Input Area
$subscriptionName = 'MyAzureSubscriptionDev'
$aadSvcPrinAppDisplayName = 'VMEncryptionSvcPrinDev'
$aadSvcPrinAppHomePage = 'http://FakeURLBecauseItsNotReallyNeededForThisPurpose'
$aadSvcPrinAppIdentifierUri = 'https://DomainName.com/VMEncryptionSvcPrinDev'
$aadSvcPrinAppPassword = ConvertTo-SecureString 'SuperStrongPassword' -AsPlainText -Force

#-----------------------------------------

#Manual login into Azure
Login-AzureRmAccount -SubscriptionName $subscriptionName

#-----------------------------------------

#Create Service Principal App to Use For Encryption of VMs
$aadSvcPrinApplication = New-AzureRmADApplication -DisplayName $aadSvcPrinAppDisplayName -HomePage $aadSvcPrinAppHomePage -IdentifierUris $aadSvcPrinAppIdentifierUri -Password $aadSvcPrinAppPassword
New-AzureRmADServicePrincipal -ApplicationId $aadSvcPrinApplication.ApplicationId

Step 2: Create Azure Key Vault

<#
.SYNOPSIS
Creates Azure Key Vault.
.DESCRIPTION
This script does the following:
1 - Creates a key vault in Azure.
2 - Allows the Azure Backup Service permission to the key vault.
This is required if Recovery Vault will be used for backups.
A key vault is required to enable disk encryption for VM.
.NOTES
File Name: ProvisionAzureKeyVault.ps1
Author : Melissa Coates
Notes: Be sure the variables in the input area are completed, following all standard naming conventions.
The key vault must reside in the same region as the VM which will be encrypted.
A Premium key vault is being provisioned so that an HSM key can be created for the KEK.
The 262044b1-e2ce-469f-a196-69ab7ada62d3 ID refers to the Azure Key Vault (which is why it is not a variable).
.LINK
Supporting information: 
https://blogs.msdn.microsoft.com/azuresecurity/2015/11/16/explore-azure-disk-encryption-with-azure-powershell/
https://docs.microsoft.com/en-us/azure/security/azure-security-disk-encryption 

#>

#-----------------------------------------

#Input Area
$subscriptionName = 'MyAzureSubscriptionDev'
$resourceGroupName = 'MyDevRG'
$keyVaultName = 'KeyVault-Dev'
$keyVaultLocation = 'East US 2'

#-----------------------------------------

#Manual login into Azure
#Login-AzureRmAccount -SubscriptionName $subscriptionName

#-----------------------------------------

#Create Azure Key Vault
New-AzureRmKeyVault -VaultName $keyVaultName -ResourceGroupName $resourceGroupName -Location $keyVaultLocation -Sku 'Premium'

#-----------------------------------------

#Permit the Azure Backup service to access the key vault
Set-AzureRmKeyVaultAccessPolicy -VaultName $keyVaultName -ResourceGroupName $resourceGroupName -PermissionsToKeys backup,get,list -PermissionsToSecrets get,list -ServicePrincipalName 262044b1-e2ce-469f-a196-69ab7ada62d3

Step 3: Connect Service Principal with Key Vault

<#
.SYNOPSIS
Enables the service principal for VM disk encryption to communicate with Key Vault.
.DESCRIPTION
This script does the following:
A - Allows service principal the selective permissions to the key vault so
that disk encryption functionality works.
B - Creates a KEK (Key Encryption Key). For Disk Encryption, a KEK is required 
in addition to the BEK (BitLocker Encryption Key).
Prerequisite 1: Service Principal name (see CreateAADSvcPrinForVMEncryption.ps1)
Prerequisite 2: Azure Key Vault (see ProvisionAzureKeyVault.ps1)
.NOTES
File Name: EnableSvcPrinWithKeyVaultForDiskEncryption.ps1
Author : Melissa Coates
Notes: Be sure the variables in the input area are completed, following all standard naming conventions.
The key vault must reside in the same region as the VM being encrypted.
The key type can be either HSM or Software (HSM offers additional security but does require a Premium key vault). 
.LINK
Supporting information: 
https://blogs.msdn.microsoft.com/azuresecurity/2015/11/16/explore-azure-disk-encryption-with-azure-powershell/
https://docs.microsoft.com/en-us/azure/security/azure-security-disk-encryption 
#>

#Input Area
$subscriptionName = 'MyAzureSubscriptionDev'
$resourceGroupName = 'MyDevRG'
$aadSvcPrinAppDisplayName = 'VMEncryptionSvcPrinDev'
$keyVaultName = 'KeyVault-Dev'
$keyName = 'VMEncryption-KEK'
$keyType = 'HSM'

#-----------------------------------------

#Manual login into Azure
#Login-AzureRmAccount -SubscriptionName $subscriptionName

#-----------------------------------------

#Allow the Service Principal Permissions to the Key Vault
$aadSvcPrinApplication = Get-AzureRmADApplication -DisplayName $aadSvcPrinAppDisplayName
Set-AzureRmKeyVaultAccessPolicy -VaultName $keyVaultName -ServicePrincipalName $aadSvcPrinApplication.ApplicationId -PermissionsToKeys 'WrapKey' -PermissionsToSecrets 'Set' -ResourceGroupName $resourceGroupName

#-----------------------------------------

#Create KEK in the Key Vault
Add-AzureKeyVaultKey -VaultName $keyVaultName -Name $keyName -Destination $keyType

#-----------------------------------------

#Allow Azure platform access to the KEK
Set-AzureRmKeyVaultAccessPolicy -VaultName $keyVaultName -ResourceGroupName $resourceGroupName -EnabledForDiskEncryption

Step 4: Enable Disk Encryption

<#
.SYNOPSIS
Enables disk encryption for a VM.
.DESCRIPTION
This script enables disk encryption for an Azure virtual machine.
Prerequisite 1: Service Principal name (see CreateAADSvcPrinForDiskEncryption.ps1)
Prerequisite 2: Azure Key Vault (see ProvisionAzureKeyVault.ps1)
Prerequisite 3: Permissions to Key Vault for Service Principal (see EnableSvcPrinWithKeyVaultForDiskEncryption.ps1)
.NOTES
File Name: EnableAzureDiskEncryption.ps1
Author : Melissa Coates
Notes: Be sure the variables in the input area are completed, following all standard naming conventions.
Azure Disk Encryption (ADE) 
The Azure VMs must already exist and be running.
To verify when completed: Get-AzureRmVmDiskEncryptionStatus -ResourceGroupName $resourceGroupName -VMName $vmName
.LINK
Supporting information: 
https://blogs.msdn.microsoft.com/azuresecurity/2015/11/16/explore-azure-disk-encryption-with-azure-powershell/
https://docs.microsoft.com/en-us/azure/security/azure-security-disk-encryption 
#>

#-----------------------------------------

#Input Area
$subscriptionName = 'MyAzureSubscriptionDev'
$resourceGroupName = 'MyDevRG'
$keyVaultName = 'KeyVault-Dev'
$keyName = 'VMEncryption-KEK'
$aadSvcPrinAppDisplayName = 'VMEncryptionSvcPrinDev'
$aadSvcPrinAppPassword = ConvertTo-SecureString 'SuperStrongPassword' -AsPlainText -Force
$vmName = 'VMName-Dev'

#-----------------------------------------

#Manual login into Azure
#Login-AzureRmAccount -SubscriptionName $subscriptionName

#-----------------------------------------

#Enable Encryption on Virtual Machine
$keyVault = Get-AzureRmKeyVault -VaultName $keyVaultName -ResourceGroupName $resourceGroupName
$diskEncryptionKeyVaultUrl = $KeyVault.VaultUri
$keyVaultResourceId = $KeyVault.ResourceId
$keyEncryptionKeyUri = Get-AzureKeyVaultKey -VaultName $keyVaultName -KeyName $keyName 
$aadSvcPrinApplication = Get-AzureRmADApplication -DisplayName $aadSvcPrinAppDisplayName 
Set-AzureRmVMDiskEncryptionExtension -ResourceGroupName $resourceGroupName -VMName $vmName -AadClientID $aadSvcPrinApplication.ApplicationId -AadClientSecret $aadSvcPrinAppPassword -DiskEncryptionKeyVaultUrl $diskEncryptionKeyVaultUrl -DiskEncryptionKeyVaultId $KeyVaultResourceId -KeyEncryptionKeyUrl $keyEncryptionKeyUri.Id -KeyEncryptionKeyVaultId $keyVaultResourceId

Step 4 takes around 10 minutes to run; it will prompt you with the following dialog box before it executes:

You'll see this message when step 4 has completed:

And in the portal, the disks associated with the VM will also indicate that encryption is now enabled:


Troubleshooting

One error I had issues with was "Azure Backup Service does not have sufficient permissions to Key Vault for Backup of Encrypted Virtual Machines."  The last cmdlet in Step 2 above resolves this issue. So, watch out for that if you are using a key vault that already exists.

You Might Also Like...

Deciding on Encryption at Rest for an Azure Virtual Machine

Setting Up a PC for Cortana Intelligence Suite Development