Step by step - Creating Shielded VMs without VMM
Hi, I’m Jane, one of the newest members of the Windows Server Security Product Team. My very first hands-on experience is to deploy Shielded VMs with the minimum amount of hardware. It was fun and a great learning experience. I followed the comprehensive TP5 deployment guide on Shielded VM and Guarded Fabric guide with one deviation: I deployed it without VMM. If you are just like me, trying out the scenario end to end, this blog post will provide you the step by step instructions to use just the PowerShell cmdlets to create shielded VMs.
This blog post doesn’t cover any of the gory details or the building blocks for this scenario, etc. For that, I highly recommend that you first read through the deployment guide which also covers terminology descriptions, scenario overview and architectural designs.
Before you start, you should have completed the deployment of both the guarded host and the Host Guardian Service (HGS) server. For your reference, you can follow the deploying HGS server blog to setup the HGS server as well as deploying guarded host guide to configure the guarded hosts.
As a way to quickly check and verify your deployment, run the following cmdlet on each guarded host:
The output of the cmdlet should display that IsHostGuarded is True, and AttestationStatus is Passed.
There are 2 ways to create shielded VMs:
- Shielding an existing VM (a.k.a grandfathering)
- Provisioning a shielded VM from a template
I’ll illustrate both approaches in this blog post.
Shielding an existing VM
Let’s start with the simpler approach. This requires you to have a running VM on a host which is not the guarded host. This is important to distinguish, because you are simulating the scenario where a tenant wants to take an existing, unprotected VM and shield it before moving it to a guarded host. For clarity, the host machine which is not the guarded host will be referred as the tenant host below. A shielded VM can only run on a trusted guarded host. The trust is established by the adding the HGS guardian (retrieved from the HGS server) to the Key Protector which is used to shield the VM. That way, the shielded VM can only be started after the guarded host successfully attest against the HGS server.
In this example, the running VM is named SVM. This VM must be generation 2 and have a supported OS installed with remote desktop enabled. You should verify the VM can be connected through RDP first, as it will almost certainly be the primary way to access the VM once it is shielded (unless you have installed other remoting capabilities).
Retrieve the HGS guardian
As explained above, the first step is to get the HGS guardian metadata from the HGS server, and use it to create the Key protector. To do this, run the following PowerShell command on a guarded host or any machine that can reach the HGS server:
Invoke-WebRequest http://<HGSServer">FQDN>/KeyProtection/service/metadata/2014-07/metadata.xml -OutFile C:\HGSGuardian.xml
Copy the file C:\HGSGuardian.xml to the tenant host.
Shield the VM
Each shielded VM has a Key Protector which contains one owner guardian, and one or more HGS guardians. The steps below illustrate the process of getting the guardians, create the Key Protector in order to shield the VM.
Run the following cmdlets on a tenant host:
[snippet slug=shield-a-vm-by-tenant-admin line_numbers=false lang=bsh]
Typically, you would logon to the VM and enable BitLocker before moving it to the guarded host. Since this is only for testing purposes, we’ll skip this step here.
To complete the process, perform the following steps:
- shut down the shielded VM
- export the VM from the tenant host
- copy the exported file to the guarded host and import them
- start the VM on the guarded host
As shown above, this approach is quite manual and easy to make mistakes (such as not running BitLocker to encrypt data). Therefore, it is not recommended in production. For that, you should use the second approach illustrated in the following section: Provisioning Shielded VMs using the template disk.
Provisioning Shielded VMs using shielded templates
In production, you would typically use a fabric manager (e.g. VMM) to deploy shielded VMs. However, the steps illustrated below allow you to deploy and validate the entire scenario without a fabric manager.
In a nutshell, you will create a template disk, a shielding data file, a Windows unattend.xml file and other security artifacts on the tenant host, then copy these files to a guarded host and provision shielded VMs.
In order to create the template disk and the shielding data file, you will need to install the “Shielded VM Tools” feature under the Remote Server Administration Tools -> Feature Administration Tools on the tenant host machine. You can do this either in Server Manager or by running the following cmdlet:
Next, you will also need a VHDX file with a fully installed and sysprepped OS—we’ll call it ServerOS.vhdx.
Create a signed template disk
In order to create the signed template disk, you will need to have a certificate to sign it. For simplicity, let’s create a self-signed certificate for this purpose. Run the following PowerShell commands on the tenant host:
$cert = New-SelfSignedCertificate -DnsName 'signing.contoso.com'
Now, we sign the disk:
Protect-TemplateDisk -Path ‘C:\ServerOS.vhdx’ -TemplateName "ServerOSTemplate" -Version 18.104.22.168 -Certificate $cert
Create Shielding Data (PDK) file
Shielding Data is created/owned by tenants/VM owners and contains secrets that must be protected from the fabric admin and that is needed to create shielded VMs, e.g. the shielded VM’s administrator password. Shielding Data is contained in a PDK file which is also encrypted. Once created by the tenant/VM owner, the resulting PDK file must be copied to the guarded fabric. The deployment guide has much more detailed explanation of shielding data and why it is necessary.
In addition, you will also need a Windows unattend.xml file; a working sample is also included in the deployment guide.
During deployment, you will need to import the HGS guardian, you can follow the steps described in the section above titled Retrieve the HGS guardian—it will be referenced as ‘C:\HGSGuardian.xml’ below.
Run the following cmdlets on the tenant host to create the PDK:
[snippet slug=create-pdk lang=bsh]
Provision shielded VM on a guarded host
Copy the template disk file (ServerOS.vhdx) and the PDK file (contoso.pdk) to the guarded host, to get ready for deployment.
The Windows unattend.xml file has some placeholder settings that need to be substituted during deployment to ensure the resulting VM is unique and fully configured, e.g. it contains a computer name and a timezone. These unique values are specified in a FSK (Fabric Specialization Key) file. To create one, run the following cmdlet on the guarded host to create the FSK file, and provision a shielded VM using the signed template disk:
[snippet slug=creating-shielded-vm-using-template-disk lang=bsh]
While the shielded VM is being provisioned, you can use the following cmdlet to check the progress:
Get-ShieldedVMProvisioningStatus -VMName $vmname
Once it’s completed, make sure the shielded VM has the correct Network Adapter configured so it can be accessed through RDP.
Running Shielded VMs on a Hyper-V cluster
If you are trying to deploy shielded VMs on clustered guarded hosts (using a Windows Failover Cluster), you can configure the shielded VM to be highly available using the following cmdlet:
Add-ClusterVirtualMachineRole -VMName 'contososvm1' -Cluster <guarded host cluster name>
The shielded VM can now be live migrated within the cluster.
In summary, this blog post walked you through the steps to create shielded VMs without a fabric manager such as VMM. This enables you to deploy and validate the scenario with a simpler topology (at the expense of a more complex administration experience).