Azure Disk Encryption with AAD (aka v1 or dual pass) to without AAD (aka v2 or single pass)



Issue description:-

The scenario is that you have your disks (OS disks or Data disks) encrypted with v1 ie ADE with AAD (Azure Active Directory) and now you want to change this to the newly encryption strategy ie with v2 (without AAD and also known as single pass).
Once you change it from v1 to v2 and try to add a new data disk, you may encounter below error:

Failed to update disks for the virtual machine 'XXXX'. Error: User encryption settings in the VM model are not supported. Please upgrade Azure Disk Encryption extension version and clear encryption settings in the VM model.
User encryption settings in the VM model are not supported. Please upgrade Azure Disk Encryption extension version and clear encryption settings in the VM model.
Failed to update disks for the virtual machine 'XXXX'. Error: User encryption settings in the VM model are not supported. Please upgrade Azure Disk Encryption extension version and clear encryption settings in the VM model.



 Steps to repro the issue:
         
Create a Windows  VM and encrypt the OS disk and Data disks using AAD Client-id and Client secret.

1. Create a SPN
2. Create a KeyVault
  • Create a secret
  • Create a Key
3. Create a Windows Virtual Machine and attach a Data disk to it.
4. Initialize the data disk
5. RDP to the VM and ensure encryption has been completed successfully.Can be checked through        GUI or using below command
  •       manage-bde status
6. Log in the Azure portal and ensure all disks have been encrypted.
7. Disable the V1 encryption (with AAD Client ID and Client secret)
8.  Remove the extension.  It is important to do this.
9. Encrypt the VM (OS and data Disks) again with V2 (without AAD Client id and secret) that is by         single pass.
10. Ensure disks (OS and Data disk) have been encrypted successfully.
11. Ensure through portal that Azure Disk encryption extension for V2 has been provision            successfully.
12. Create a data disk and try to attach it to VM, the disk attachment operation will fail with error              specified in issue description.
13. To attach the disk successfully, below is the remediation steps which need to be implemented:
  • set value of EncryptionSetting   = null which means VM has never been encrypted before. value 'False' means it has,you just disabled ADE.

          A. Stop the VM
          
$vmName='VMName'
$rg='Resource group name'
$vm3 = get-azureRMvm -VMName $vmName -ResourceGroupName $rg
stop-azureRMvm -ResourceGroupName $vm3.ResourceGroupName -Name $vm3.Name

     
          B. Set encryption setting to null from VM model and start the VM

$vm3 = get-azureRMvm -VMName $vmName -ResourceGroupName $rg
$vm3.StorageProfile.OsDisk.EncryptionSettings = $null
#Null means the VM has never been encrypted before. 
Update-AzureRMVM -ResourceGroupName $vm3.ResourceGroupName -VM $vm3
Start-AzureRMVM -name $vmname -ResourceGroupName $rg -Verbose

   
14. Now try to Add the Disk to the VM using Terraform or Powershell (ensure you do not do it                  through GUI)
   
resource "azurerm_managed_disk" "external_1" {
  name                 = "${var.web_server_name}-disk-02"
  location             = var.web_server_location
  resource_group_name  = azurerm_resource_group.web_server_rg.name
  storage_account_type = "Standard_LRS"
  create_option        = "Empty"
  disk_size_gb         = "10"
}

resource "azurerm_virtual_machine_data_disk_attachment" "external_1" {
  managed_disk_id    = azurerm_managed_disk.external_1.id
  virtual_machine_id = azurerm_virtual_machine.web_server.id
  lun                = "2"
  caching            = "ReadWrite"
}


15. You will observe Disk has been added successfully to the VM.
16. RDP to the VM and Initialize the Disk
17. Reboot the VM



 ~~~~Lets perform all of the above activities step by step through Terraform~~~~~~~~ 

>> From Step 1 to 8 is to provision a KEY Vault and create a client secret


1.Create an Application Registration in AAD. 
 
resource "azurerm_azuread_application" "diskencryptionapp" {
  name = "diskencryptionapp"
   }

 2. Create a SPN

resource "azurerm_azuread_service_principal" "diskencryptionapp" {
  application_id = azurerm_azuread_application.diskencryptionapp.application_id
}


 3. Create a random password for Application registration Client Secret
resource "random_string" "password" {
  length  = 32
  special = false
}

 4.Create a client secret
resource "azuread_application_password" "azureadspnpassword" {
  application_id = azurerm_azuread_application.diskencryptionapp.id
  value          = random_string.password.result
  end_date       = "2022-01-01T01:00:00Z"
}

 5. Generate the output of client secret
output "client_secret" {
  description = "Client Secret"
  value       = random_string.password.result
}


 6. Create a key vault and provide proper access policy.
resource "azurerm_key_vault" "mykeyvault" {
  name                            = var.keyvaultname
  location                        = var.web_server_location
  resource_group_name             = azurerm_resource_group.web_server_rg.name
  enabled_for_deployment          = true
  enabled_for_disk_encryption     = true
  enabled_for_template_deployment = true
  tenant_id                       = var.tenant_id
  sku {
    name = "standard"
  }
  access_policy {
    tenant_id = var.tenant_id
    object_id = data.azurerm_azuread_service_principal.diskencryptionapp.object_id
    secret_permissions = [
      "Get",
      "List",
      "Set",
      "Delete",
      "Recover",
      "Backup",
      "Restore",
      "Purge",
    ]
    key_permissions = [
      "Get",
      "List",
      "Update",
      "Create",
      "Import",
      "Delete",
      "Recover",
      "Backup",
      "Restore",
      "WrapKey",
      "UnwrapKey",
    ]
    certificate_permissions = [
      "Get",
      "List",
      "Update",
      "Create",
      "Import",
      "Delete",
      "Recover",
      "Backup",
      "Restore",
      "ManageContacts",
      "ManageIssuers",
      "GetIssuers",
      "ListIssuers",
      "SetIssuers",
      "DeleteIssuers",
    ]
  }
  access_policy {
    tenant_id = var.tenant_id
    object_id = var.personalobjectid
    secret_permissions = [
      "Get",
      "List",
      "Set",
      "Delete",
      "Recover",
      "Restore",
      "Purge",
    ]
    key_permissions = [
      "Get",
      "List",
      "Update",
      "Create",
      "Import",
      "Delete",
      "Recover",
      "Backup",
      "Restore",
      "WrapKey",
      "UnwrapKey",
    ]
  }

  network_acls {
    default_action = "Allow"
    bypass         = "AzureServices"
  }
  tags = {
    environment = "Production"
  }
}

 7.Create a Secret in the key vault 
resource "azurerm_key_vault_secret" "secret-sauce" {
  name         = var.secretname
  value        = "password@123"
  key_vault_id = azurerm_key_vault.hpvault01.id
  tags = {
    environment = "Production"
  }
}

 8. Create a key in the key vault


resource "azurerm_key_vault_key" "diskencryptionkey" {
  name         = "diskencryptionkey"
  key_vault_id = azurerm_key_vault.hpvault01.id
  key_type     = "RSA"
  key_size     = 2048

  key_opts = [
    "decrypt",
    "encrypt",
    "sign",
    "unwrapKey",
    "verify",
    "wrapKey",
  ]
}


 >> Step 9 to 16 for creating windows VM

9. Create a Resource Group
resource "azurerm_resource_group" "web_server_rg" {
  name     = var.web_server_rg
  location = var.web_server_location
}



10. Create a VNET
resource "azurerm_virtual_network" "web_server_vnet" {
  name                = "${var.resource_prefix}-vnet"
  location            = var.web_server_location
  resource_group_name = azurerm_resource_group.web_server_rg.name
  address_space       = [var.web_server_address_space]
}


11. Create a Subnet

resource "azurerm_subnet" "web_server_subnet" {
  name                 = "${var.resource_prefix}-subnet"
  resource_group_name  = azurerm_resource_group.web_server_rg.name
  virtual_network_name = azurerm_virtual_network.web_server_vnet.name
  address_prefix       = var.web_server_address_prefix[0]
}


12. Create a Network interface card
resource "azurerm_network_interface" "web_server_nic" {
  name                      = "${var.web_server_name}-nic"
  location                  = var.web_server_location
  resource_group_name       = azurerm_resource_group.web_server_rg.name
  network_security_group_id = azurerm_network_security_group.web_server_nsg.id

  ip_configuration {
    name                          = "${var.web_server_name}-ip"
    subnet_id                     = azurerm_subnet.web_server_subnet.id
    private_ip_address_allocation = "dynamic"
    public_ip_address_id          = azurerm_public_ip.web_server_public_ip.id
  }
}


13. Create a Public IP

resource "azurerm_public_ip" "web_server_public_ip" {
  name                = "${var.web_server_name}-public-ip"
  location            = var.web_server_location
  resource_group_name = azurerm_resource_group.web_server_rg.name
  allocation_method   = var.environment == "production" ? "Static" : "Dynamic"
}


14.Create a NSG
resource "azurerm_network_security_group" "web_server_nsg" {
  name                = "${var.web_server_name}-nsg"
  location            = var.web_server_location
  resource_group_name = azurerm_resource_group.web_server_rg.name
}


15. Create NSG rule for RDP to the VM

resource "azurerm_network_security_rule" "web_server_nsg_rule_rdp" {
  name                        = "RDP Inbound"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "3389"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.web_server_rg.name
  network_security_group_name = azurerm_network_security_group.web_server_nsg.name
}


16. Create a Windows VM

resource "azurerm_virtual_machine" "web_server" {
  name                             = var.web_server_name
  location                         = var.web_server_location
  resource_group_name              = azurerm_resource_group.web_server_rg.name
  network_interface_ids            = [azurerm_network_interface.web_server_nic.id]
  vm_size                          = "Standard_D4s_v3"
  availability_set_id              = azurerm_availability_set.avset.id
  delete_os_disk_on_termination    = true
  delete_data_disks_on_termination = true

  storage_image_reference {
    publisher = "MicrosoftSQLServer"
    offer     = "sql2019-ws2019"
    sku       = "sqldev"
    version   = "latest"
  }

  storage_os_disk {
    name              = "${var.web_server_name}-os"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
    os_type           = "Windows"
    disk_size_gb      = 127
  }

  os_profile {
    computer_name  = var.web_server_name
    admin_username = "admina"
    admin_password = data.azurerm_key_vault_secret.secret-sauce.value
  }

  os_profile_windows_config {
    enable_automatic_upgrades = true
    provision_vm_agent        = true
  }
}



>>  Step 17 to 20 to create data disk and encrypt it with V1


17. Create a  external Data disk


resource "azurerm_managed_disk" "external" {
  name                 = "${var.web_server_name}-disk-01"
  location             = var.web_server_location
  resource_group_name  = azurerm_resource_group.web_server_rg.name
  storage_account_type = "Standard_LRS"
  create_option        = "Empty"
  disk_size_gb         = "10"
}


18. Attach  the Disk to the VM

resource "azurerm_virtual_machine_data_disk_attachment" "external" {
  managed_disk_id    = azurerm_managed_disk.external.id
  virtual_machine_id = azurerm_virtual_machine.web_server.id
  lun                = "1"
  caching            = "ReadWrite"
}


 19. Initialize the Disk 
  
resource "null_resource" "Azurediskinitialization_1" {
  provisioner "local-exec" {
    command = "az vm extension set --resource-group ${azurerm_resource_group.web_server_rg.name}   --vm-name ${azurerm_virtual_machine.web_server.name} --name CustomScriptExtension --publisher Microsoft.Compute --settings qq.json --version 1.9"
  }
}


20. Enable Disk encryption using AAD Client ID and Secret and Key vault (ie V1)


resource "null_resource" "AzureDiskEncryption_ext_rakserver01_v1" {
 
  provisioner "local-exec" {
    command = "az vm encryption enable --name ${azurerm_virtual_machine.web_server.name}  --resource-group ${azurerm_resource_group.web_server_rg.name} --aad-client-id ${data.azurerm_azuread_service_principal.diskencryptionapp.application_id} --aad-client-secret ${random_string.password.result} --disk-encryption-keyvault ${data.azurerm_key_vault.hpvault01.name} --volume-type all"
  }
 }

   
  You will find Disks (OS and data Disks has been encrypted and you will find screenshot like below.




 21. Now, we have to disable encryption v1 and remove the respective extension.

resource "null_resource" "AzureDiskEncryption_disable" {
  provisioner "local-exec" {
    command = "az vm encryption disable --name ${azurerm_virtual_machine.web_server.name}  --resource-group ${azurerm_resource_group.web_server_rg.name}  --volume-type all"
  }
}






22. Remove the Extension AzureDiskEncryption 

resource "null_resource" "AzureDiskEncryption_extensionRemove" {
  provisioner "local-exec" {
    command = "az vm extension delete --vm-name ${azurerm_virtual_machine.web_server.name}  -g ${azurerm_resource_group.web_server_rg.name}  -n ${var.extensionName}"
  }
}


RDP to virtual Machine and ensure manage-bde -status C: shows 0.0% and Conversion Status Fully Decrypted



22. Now remove StorageProfile encryption using powershell.
     
       A. Stop the VM
$vmName='rakdbserver01'
$rg='web-rg'
$vm3 = get-azureRMvm -VMName $vmName -ResourceGroupName $rg
stop-azureRMvm -ResourceGroupName $vm3.ResourceGroupName -Name $vm3.Name

 Or through Azure CLI

$vmName="rakdbserver01"
$rg="web-rg"
$vm3 = get-azVM -Name $vmName -ResourceGroupName $rg
Stop-AzVM -ResourceGroupName $rg -Name $vmName

      
         B.Remove encryption settings from VM model and start the VM
$vm3 = get-azureRMvm -VMName $vmName -ResourceGroupName $rg
$vm3.StorageProfile.OsDisk.EncryptionSettings = $null
#Null means the VM has never been encrypted before. False means it has,you just disabled ADE.
Update-AzureRMVM -ResourceGroupName $vm3.ResourceGroupName -VM $vm3
Start-AzureRMVM -name $vmname -ResourceGroupName $rg -Verbose

    or through Azure CLI

$vmName="rakdbserver01"
$rg="web-rg"
$vm3 = get-azVM -Name $vmName -ResourceGroupName $rg

$vm3.StorageProfile.OsDisk.EncryptionSettings = $null
Update-AzVM -ResourceGroupName $vm3.ResourceGroupName -VM $vm3

Start-AzVM -name $vmName -ResourceGroupName $rg -Verbose

   
23. Enable Disk encryption with v2

       
resource "azurerm_virtual_machine_extension" "vmextensionwindows" {
  count                      = "${lower(var.vm_os_type) == "windows" ? 1 : 0}"
  name                       = "AzureDiskEncryption"
  location                   = "${var.web_server_location}"
  resource_group_name        = "${azurerm_resource_group.web_server_rg.name}"
  virtual_machine_name       = "${azurerm_virtual_machine.web_server.name}"
  publisher                  = "Microsoft.Azure.Security"
  type                       = "AzureDiskEncryption"
  type_handler_version       = "${var.type_handler_version == "" ? "2.2" : var.type_handler_version}"
  
  auto_upgrade_minor_version = true

  settings = <<SETTINGS
    {
        "EncryptionOperation": "${var.encrypt_operation}",
        "KeyVaultURL": "${data.azurerm_key_vault.hpvault01.vault_uri}",
        "KeyVaultResourceId": "${data.azurerm_key_vault.hpvault01.id}",                                                                                                                                    
        "KeyEncryptionKeyURL": "${data.azurerm_key_vault_key.diskencryptionkey.id}",
        "KekVaultResourceId": "${data.azurerm_key_vault.hpvault01.id}",                                                                                                                                    
        "KeyEncryptionAlgorithm": "${var.encryption_algorithm}",
        "SequenceVersion": "random_id.my_id.b64",
        "VolumeType": "${var.volume_type}"
    }
SETTINGS

}
 resource "azurerm_virtual_machine_extension" "vmextensionlinux" {
  count                      = "${lower(var.vm_os_type) == "linux" ? 1 : 0}"
   name                       = "diskencryptionv2"
  location                   = "${var.web_server_location}"
  resource_group_name        = "${azurerm_resource_group.web_server_rg.name}"
  virtual_machine_name       = "${azurerm_virtual_machine.web_server.name}"
  publisher                  = "Microsoft.Azure.Security"
  type                       = "AzureDiskEncryptionForLinux"
  type_handler_version       = "${var.type_handler_version == "" ? "1.1" : var.type_handler_version}"
  auto_upgrade_minor_version = true

  settings = <<SETTINGS
    {
         "EncryptionOperation": "${var.encrypt_operation}",
        "KeyVaultURL": "${data.azurerm_key_vault.hpvault01.vault_uri}",
        "KeyVaultResourceId": "${data.azurerm_key_vault.hpvault01.id}",                                                                                                                                    
        "KeyEncryptionKeyURL": "${data.azurerm_key_vault_key.diskencryptionkey.id}",
        "KekVaultResourceId": "${data.azurerm_key_vault.hpvault01.id}",                                                                                                                                    
        "KeyEncryptionAlgorithm": "${var.encryption_algorithm}",
        "VolumeType": "${var.volume_type}"
    }
SETTINGS

}






We can clearly see that the VM has been encrypted using V2 ie single pass. We have not used AAD but used Key vault key to store the respective encryption key.

24. RDP to the VM and ensure manage-bde -status C: -- shows 100%.



25. Try to add a disk using portal which may get failed with error 

  "Failed to update disks for the virtual machine 'XXXX'. Error: User encryption settings in the VM model are not supported. Please upgrade Azure Disk Encryption extension version and clear encryption settings in the VM model."




26. To fix above error and to attach disk successfully, implement below steps:

 A. Stop the VM
$vmName='rakdbserver01'
$rg='web-rg'
$vm3 = get-azureRMvm -VMName $vmName -ResourceGroupName $rg
stop-azureRMvm -ResourceGroupName $vm3.ResourceGroupName -Name $vm3.Name

      
 B. set StorageProfile EncryptionSettings to NULL from VM model and start the VM
$vm3 = get-azureRMvm -VMName $vmName -ResourceGroupName $rg
$vm3.StorageProfile.OsDisk.EncryptionSettings = $null
#Null means the VM has never been encrypted before. False means it has,you just disabled ADE.
Update-AzureRMVM -ResourceGroupName $vm3.ResourceGroupName -VM $vm3
Start-AzureRMVM -name $vmname -ResourceGroupName $rg -Verbose

   
27. Add disk using terraform or powershell, you will observe disk has been added successfully.


resource "azurerm_managed_disk" "external_1" {
  name                 = "${var.web_server_name}-rakesh-data-disk-03"
  location             = var.web_server_location
  resource_group_name  = azurerm_resource_group.web_server_rg.name
  storage_account_type = "Standard_LRS"
  create_option        = "Empty"
  disk_size_gb         = "10"
}

resource "azurerm_virtual_machine_data_disk_attachment" "external_1" {
  managed_disk_id    = azurerm_managed_disk.external_1.id
  virtual_machine_id = azurerm_virtual_machine.web_server.id
  lun                = "2"
  caching            = "ReadWrite"
}


28. Initialize and format the disk

29. Reboot the VM and check encryption status for newly added disks

-- if all the above steps are done as mentioned then the disk should get encrypted



Supporting code for above TERRAFORM implemetation


DataSource_output.tf File

data "azurerm_azuread_service_principal" "diskencryptionapp" {
  display_name = "diskencryptionapp"
}

data "azurerm_key_vault" "hpvault01" {
  name                = var.keyvaultname
  resource_group_name = azurerm_resource_group.web_server_rg.name
}

data "azurerm_key_vault_secret" "secret-sauce" {
  name      = var.secretname
  vault_uri = data.azurerm_key_vault.hpvault01.vault_uri
}

data "azurerm_key_vault_key" "diskencryptionkey" {
  name         = "diskencryptionkey"
  key_vault_id = "${data.azurerm_key_vault.hpvault01.id}"
   
}


output "serviceprincipalApplicationid" {
  value = data.azurerm_azuread_service_principal.diskencryptionapp.application_id
}


output "serviceprincipalobjectid" {
  value = data.azurerm_azuread_service_principal.diskencryptionapp.object_id
}



output "vaultname" {
  value = data.azurerm_key_vault.hpvault01.name
}


output "vaultsecretname" {
  value = data.azurerm_key_vault_secret.secret-sauce.name
}

output "keyvaultsecretpassword" {
  value = data.azurerm_key_vault_secret.secret-sauce.value
}


output "kekname" {

    value ="${data.azurerm_key_vault_key.diskencryptionkey.name}"
  
}

output "key_type" {

    value ="${data.azurerm_key_vault_key.diskencryptionkey.key_type}"
  
}

output "kek_vault_id" {

    value ="${data.azurerm_key_vault_key.diskencryptionkey.key_vault_id}"
  
}

output "kek_uri" {

    value ="${data.azurerm_key_vault_key.diskencryptionkey.id}"
  
}


output "client_secret" {
  description = "Client Secret"
  value       = random_string.password.result
}



terraform apply -auto-approve --target=azurerm_azuread_service_principal.diskencryptionapp
terraform apply -auto-approve --target=azuread_application_password.azureadspnpassword
terraform apply -auto-approve --target=azurerm_key_vault_secret.secret-sauce
terraform apply -auto-approve --target=azurerm_key_vault_key.diskencryptionkey
terraform apply -auto-approve --target=azurerm_virtual_machine_data_disk_attachment.external
terraform apply -auto-approve --target=azurerm_network_security_rule.web_server_nsg_rule_rdp
terraform apply -auto-approve --target=null_resource.Azurediskinitialization_1
terraform apply -auto-approve --target=null_resource.AzureDiskEncryption_ext_rakserver01_v1"


  • wait for 20 minutes
  •  VM will reboot and disk encryption will start
  • disable encryption settings and remove the extension

terraform apply -auto-approve --target=null_resource.AzureDiskEncryption_disable
wait for 10~15 minutes --
terraform apply -auto-approve --target=null_resource.AzureDiskEncryption_extensionRemove


  • upgrade to V2

terraform apply -auto-approve --target=azurerm_virtual_machine_extension.vmextensionwindows


  • Add a disk using Powershell and ensure disk added in the VM
  • RDP to the portal, initialize and format the disk
  • Restart the VM, and ensure disk has been encrypted.



Comments

Popular posts from this blog

How to use Custom Script Extensions for windows using Azure PowerShell - AZ CLI and from Terraform

How to create a Resource group in Azure using Terraform Part -1

Error inspecting states in the "azurerm" backend: storage: service returned error: StatusCode=403, ErrorCode=AuthenticationFailed