Back to Checks
azure

Virtual Machine OS or data disk is encrypted with a customer-managed key (CMK)

vm_ensure_attached_disks_encrypted_with_cmk
Service: vmSeverity: medium
OfficialBuilt-inVerified
Categories:encryption
Resource Type:microsoft.compute/disks

Attached Azure managed disks (OS and data) are assessed to confirm encryption uses customer-managed keys (CMK) via disk encryption sets rather than platform-managed keys. Scope includes disks currently attached to VMs, evaluating their encryption type to verify CMK is applied.

Risk

Without CMK, you lose control over key lifecycle and access. This weakens confidentiality and compliance: you can't enforce independent rotation, promptly revoke keys to crypto-lock stolen copies/snapshots, or separate duties. Misuse or compromise may keep data readable beyond your trust boundary.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks vm_ensure_attached_disks_encrypted_with_cmk

Recommendation

Use CMK with disk encryption sets for all attached OS and data disks.

  • Enforce least privilege on key usage and scope
  • Enable periodic key rotation and auditing
  • Store keys in HSM-backed vaults; separate key and data admins
  • Combine with encryption at host to cover temp disks and caches

Remediation

CLI

az disk update -g <RESOURCE_GROUP> -n <DISK_NAME> --encryption-type EncryptionAtRestWithCustomerKey --disk-encryption-set <DES_ID>

Terraform

# Encrypt a managed disk with a customer-managed key via Disk Encryption Set (DES)
resource "azurerm_managed_disk" "<example_resource_name>" {
  name                = "<example_resource_name>"
  location            = "<LOCATION>"
  resource_group_name = "<example_resource_name>"
  storage_account_type = "Standard_LRS"
  create_option        = "Empty"
  disk_size_gb         = 32

  # CRITICAL: Attach DES to enable SSE with CMK and pass the check
  disk_encryption_set_id = "<example_resource_id>" # critical: DES ID
}

NativeIaC

// Encrypt a managed disk with a customer-managed key via Disk Encryption Set (DES)
resource disk 'Microsoft.Compute/disks@2023-10-02' = {
  name: '<example_resource_name>'
  location: '<LOCATION>'
  sku: {
    name: 'Standard_LRS'
  }
  properties: {
    creationData: {
      createOption: 'Empty'
    }
    diskSizeGB: 32

    // CRITICAL: Use CMK by attaching a Disk Encryption Set (DES)
    // This switches encryption from platform-managed to customer-managed
    encryption: {
      type: 'EncryptionAtRestWithCustomerKey' // critical: CMK
      diskEncryptionSetId: '<example_resource_id>' // critical: DES resource ID
    }
  }
}

Other

1In Azure Portal, open the target VM and click Stop to deallocate it.
2For each data disk: Go to VM > Disks > select the data disk > Detach > Save.
3In the portal search box, open Disks, select the detached disk > Encryption.
4Set Encryption type to Customer-managed key (Disk encryption set), select your Disk Encryption Set, then Save.
5Reattach the disk: VM > Disks > Add data disk (select the same disk) > Save.
6For OS disk, use Swap OS disk: create a new managed disk from a snapshot/image with Encryption type = Customer-managed key (select the same DES), then VM > Disks > Swap OS disk and choose that disk.
7Start the VM.

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_attached_disks_encrypted_with_cmk(Check):
    def execute(self) -> Check_Report_Azure:
        findings = []

        for subscription_id, disks in vm_client.disks.items():
            subscription_name = vm_client.subscriptions.get(
                subscription_id, subscription_id
            )
            for disk_id, disk in disks.items():
                if disk.vms_attached:
                    report = Check_Report_Azure(metadata=self.metadata(), resource=disk)
                    report.subscription = subscription_id
                    report.status = "PASS"
                    report.status_extended = f"Disk '{disk_id}' is encrypted with a customer-managed key in subscription {subscription_name} ({subscription_id})."

                    if (
                        not disk.encryption_type
                        or disk.encryption_type == "EncryptionAtRestWithPlatformKey"
                    ):
                        report.status = "FAIL"
                        report.status_extended = f"Disk '{disk_id}' is not encrypted with a customer-managed key in subscription {subscription_name} ({subscription_id})."

                    findings.append(report)

        return findings