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.