Creating a key vault, key, and disk encryption set in Azure via an ARM template

In Azure you have two types of encryption for VMs:

  1. Azure Disk Encryption (ADE) – which is basically encryption of your Linux or Windows VMs using the OS encryption options – dm-crypt or BitLocker respectively. You can store the key in Key Vault but the limitation is that not all OSes are supported, and even with supported OSes like Linux it is only supported on a subset. Even in Windows, for instance, it only supports premium storage and no A-series VMs (which is what you could be using if you are using for test/ dev).
  2. Azure Storage Encryption or Server Side Encryption (SSE) – which encrypts the underlying disks itself and is hence OS agnostic. Again, the keys are stored in Key Vault and you can either let Microsoft manage these (aka platform managed keys) or do it yourself (aka customer managed keys, abbreviated as CMK coz who doesn’t love acronyms).

SSE encryption requires RSA keys (2048, 3072, or 4096 bits) and has some restrictions of its own to be aware of. But, you can use it with an OS and any VM sizes or storage so it’s the better option in my mind. One thing to be aware of with SSE is that your data is not actually encrypted using the key you provide. No, the data is encrypted using an AES 256 key and that key is encrypted using the key you provide. In that respect it’s like Self-Encrypting Drives (SEDs) – the drive encrypts all data by default, irrespective of you choosing to encrypt or not; and if you do decide to encrypt, all BitLocker (or any encryption program that’s aware of the standard) does is it encrypts the keys used by the drive. Thus encryption is super fast as it’s just a matter of encrypting the keys rather than the entire drive.

With SSE you create a key vault, an RSA key, and a disk encryption set which has access to this key. The disk encryption set is assigned an identity by Azure AD, which you need to give access to on the key vault, and this way it can access the key and use it for encryption. There’s a full walkthrough here and this should just be something you do by default for all your VMs. Maybe have a common disk encyption set for all the VMs in one region, rather than a separate disk encryption set per VM as there’s a limit of 1000 disk encryption sets per subscription per region.

Anyways, as part of a template I was creating recently I wanted to deploy the disk encryption set and keys etc. as part of the template itself. I had given this a shot previously but I couldn’t crack it and thought I’d always have to create the disk encyption set manually – mainly coz 1) I couldn’t figure out how to generate the keys and give their URL to the disk encryption set, and 2) I couldn’t figure out how to authorize the disk encryption set against the key vault. I asked the question on StackOverflow recently and in one of those twists where you ask/ frame the question aloud and then things click in your head and you figure out the answer yourself I cracked it. You can read the answer in that StackOverflow thread, or continue on here.

I blogged about the first piece of the puzzle in a previous post (which, turns out I forgot to click “Publish” so I just published it now). The reference() function is your friend in such cases. Something like the following will give me the keyURL:

The second piece of the puzzle was solved once I realized I don’t have to create the key vault and assign permissions at the same time. I can create the key vault, a key, the disk encryption set, hook it up with the key, and then define the access policies so it has permissions (again, thanks to the reference() function which lets me find the Azure AD identity of the disk encryption set).

Here’s a snippet that does all the above.