Back to Checks
azure

Virtual Machine uses managed disks for OS and data disks

vm_ensure_using_managed_disks
Service: vmSeverity: high
OfficialBuilt-inVerified
Categories:resilience
Resource Type:microsoft.compute/virtualmachines

Azure virtual machines use managed disks for the OS disk and every data disk, rather than page blob VHDs in storage accounts.

The evaluation confirms that all attached VM disks are managed.

Risk

Using unmanaged disks ties VM data to storage account keys and SAS, increasing exposure of disk contents if those secrets leak (confidentiality/integrity). Limited platform resiliency and quotas increase availability risk. With Azure retiring unmanaged disks on 2026-03-31, such VMs may be stopped and unable to start.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks vm_ensure_using_managed_disks

Recommendation

Adopt managed disks for all VM OS and data volumes.

  • Enforce least privilege via RBAC at disk scope
  • Use encryption at rest; prefer CMEK when mandated
  • Apply backups/snapshots and zone-aware designs for defense in depth
  • After migration, delete orphaned VHD blobs to avoid data exposure and cost.

Remediation

CLI

az vm convert --resource-group <RESOURCE_GROUP> --name <VM_NAME>

Terraform

# VM attached to a managed OS disk
resource "azurerm_virtual_machine" "<example_resource_name>" {
  name                  = "<example_resource_name>"
  location              = "<LOCATION>"
  resource_group_name   = "<RESOURCE_GROUP>"
  network_interface_ids = ["<example_resource_id>"]
  vm_size               = "Standard_DS1_v2"

  storage_os_disk {
    name            = "osdisk"
    create_option   = "Attach"
    managed_disk_id = "<example_resource_id>" # CRITICAL: use a managed disk for the OS disk
  }
}

NativeIaC

// VM configured to use a managed OS disk
resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = {
  name: '<example_resource_name>'
  location: resourceGroup().location
  properties: {
    hardwareProfile: { vmSize: 'Standard_DS1_v2' }
    storageProfile: {
      osDisk: {
        name: 'osdisk'
        osType: 'Linux'
        createOption: 'Attach'
        managedDisk: {
          id: '<example_resource_id>' // CRITICAL: attaching a managed disk makes the VM use managed disks
        }
      }
    }
    networkProfile: { networkInterfaces: [ { id: '<example_resource_id>' } ] }
  }
}

Other

1In Azure Portal, go to Virtual machines > select your VM
2Click Stop to deallocate the VM
3In the VM menu, select Disks
4Click Migrate to managed disks, then click Migrate to start
5After migration completes, click Start to power on the VM
6If the VM is in an availability set: first go to Availability sets > select the set > Convert to managed (SKU: Aligned), then repeat steps 1-5

Check Code

from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.vm.vm_client import vm_client


class vm_ensure_using_managed_disks(Check):
    def execute(self) -> Check_Report_Azure:
        findings = []

        for subscription_id, vms in vm_client.virtual_machines.items():
            subscription_name = vm_client.subscriptions.get(
                subscription_id, subscription_id
            )
            for vm in vms.values():
                report = Check_Report_Azure(metadata=self.metadata(), resource=vm)
                report.status = "PASS"
                report.subscription = subscription_id
                report.status_extended = f"VM {vm.resource_name} is using managed disks in subscription {subscription_name} ({subscription_id})"

                using_managed_disks = (
                    True
                    if getattr(
                        getattr(getattr(vm, "storage_profile", None), "os_disk", None),
                        "managed_disk",
                        None,
                    )
                    else False
                )

                if using_managed_disks and getattr(vm, "storage_profile", None):
                    for data_disk in vm.storage_profile.data_disks:
                        if not getattr(data_disk, "managed_disk", None):
                            using_managed_disks = False
                            break

                if not using_managed_disks:
                    report.status = "FAIL"
                    report.status_extended = f"VM {vm.resource_name} is not using managed disks in subscription {subscription_name} ({subscription_id})"

                findings.append(report)

        return findings