From f036c888f057e552ad2c61c71d025d2962513e78 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 22:45:35 +0100 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20add=20scanner=20rule=20AZ-CMP-002?= =?UTF-8?q?=20=E2=80=94=20VM=20disk=20not=20protected=20by=20CMK=20or=20AD?= =?UTF-8?q?E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This script detects virtual machines whose disks use platform-managed encryption only and provides findings for compliance with CIS 7.2. --- scanner/rules/az_cmp_002.py | 115 ++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 scanner/rules/az_cmp_002.py diff --git a/scanner/rules/az_cmp_002.py b/scanner/rules/az_cmp_002.py new file mode 100644 index 00000000..cefbef43 --- /dev/null +++ b/scanner/rules/az_cmp_002.py @@ -0,0 +1,115 @@ +"""AZ-CMP-002: Virtual machine OS or data disk using platform-managed encryption only.""" + +import logging +from typing import Any, Dict, List + +RULE_ID = "AZ-CMP-002" +RULE_NAME = "Virtual machine disk not protected by customer-managed key or ADE" +SEVERITY = "HIGH" +CATEGORY = "Compute" +FRAMEWORKS = {"CIS": "7.2", "NIST": "PR.DS-1", "ISO27001": "A.10.1.1", "SOC2": "CC6.7"} +DESCRIPTION = ( + "One or more disks attached to this virtual machine are using platform-managed " + "encryption only (EncryptionAtRestWithPlatformKey). CIS 7.2 requires disks to be " + "protected using either Azure Disk Encryption (ADE) or server-side encryption with " + "a customer-managed key (CMK). Platform-managed encryption does not give the " + "organisation control over the encryption keys." +) +REMEDIATION = ( + "Configure server-side encryption with a customer-managed key via a Disk Encryption " + "Set, or enable Azure Disk Encryption on all OS and data disks. Navigate to: " + "Virtual Machine > Disks > Additional settings > Disk encryption set, or use " + "az vm encryption enable with a Key Vault." +) +PLAYBOOK = "playbooks/cli/fix_az_cmp_002.sh" + +logger = logging.getLogger(__name__) + + +def _disk_needs_flagging(managed_disk: Any) -> bool: + """Return True only if the disk uses platform-managed encryption. + + Azure platform-managed encryption (EncryptionAtRestWithPlatformKey) is the + default for all managed disks and does not satisfy CIS 7.2, which requires + customer-managed keys (CMK) or Azure Disk Encryption (ADE). + + Disks using EncryptionAtRestWithCustomerKey or + EncryptionAtRestWithPlatformAndCustomerKeys are compliant and should not + be flagged. + """ + if managed_disk is None: + return False + + encryption = getattr(managed_disk, "security_profile", None) + if encryption is None: + encryption = getattr(managed_disk, "encryption", None) + + encryption_type = getattr(encryption, "type", None) + + if encryption_type is None: + return False + + return encryption_type == "EncryptionAtRestWithPlatformKey" + + +def scan(azure_client: Any, subscription_id: str) -> List[Dict[str, Any]]: + """Detect virtual machines whose disks use platform-managed encryption only.""" + findings: List[Dict[str, Any]] = [] + + for vm in azure_client.get_virtual_machines(): + vm_id = getattr(vm, "id", "") + vm_name = getattr(vm, "name", "") + location = getattr(vm, "location", "") + + if not vm_id or not vm_name: + continue + + parsed = azure_client.parse_resource_id(vm_id) + resource_group = parsed.get("resource_group", "") + + storage_profile = getattr(vm, "storage_profile", None) + if not storage_profile: + continue + + unencrypted_disks = [] + + # Check OS disk + os_disk = getattr(storage_profile, "os_disk", None) + if os_disk: + managed_disk = getattr(os_disk, "managed_disk", None) + if _disk_needs_flagging(managed_disk): + unencrypted_disks.append( + getattr(os_disk, "name", "os-disk") + ) + + # Check data disks + data_disks = getattr(storage_profile, "data_disks", []) or [] + for disk in data_disks: + managed_disk = getattr(disk, "managed_disk", None) + if _disk_needs_flagging(managed_disk): + unencrypted_disks.append( + getattr(disk, "name", f"data-disk-{getattr(disk, 'lun', '?')}") + ) + + if unencrypted_disks: + findings.append({ + "rule_id": RULE_ID, + "rule_name": RULE_NAME, + "severity": SEVERITY, + "category": CATEGORY, + "resource_id": vm_id, + "resource_name": vm_name, + "resource_type": "Microsoft.Compute/virtualMachines", + "description": DESCRIPTION, + "remediation": REMEDIATION, + "playbook": PLAYBOOK, + "frameworks": FRAMEWORKS, + "metadata": { + "resource_group": resource_group, + "location": location, + "unencrypted_disks": unencrypted_disks, + "unencrypted_disk_count": len(unencrypted_disks), + }, + }) + + return findings From 6e45ddda74062a266e1dce764406a8427c7795d5 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 22:47:18 +0100 Subject: [PATCH 2/9] feat: add remediation playbook fix_az_cmp_002.sh This script enables Azure Disk Encryption on a specified virtual machine using a Key Vault for the disk encryption key. --- fix_az_cmp_002.sh | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 fix_az_cmp_002.sh diff --git a/fix_az_cmp_002.sh b/fix_az_cmp_002.sh new file mode 100644 index 00000000..927790d7 --- /dev/null +++ b/fix_az_cmp_002.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# OpenShield Remediation Playbook +# Rule: AZ-CMP-002 — Virtual machine disk not protected by CMK or ADE +# Usage: ./fix_az_cmp_002.sh +# Severity: HIGH + +set -e + +RESOURCE_GROUP=$1 +VM_NAME=$2 +KEYVAULT_NAME=$3 + +if [ -z "$RESOURCE_GROUP" ] || [ -z "$VM_NAME" ] || [ -z "$KEYVAULT_NAME" ]; then + echo "Usage: $0 " + echo "" + echo "Prerequisites:" + echo " 1. Create a Key Vault if one does not exist:" + echo " az keyvault create --resource-group --name --enabled-for-disk-encryption true" + echo " 2. Ensure the VM is running before enabling encryption" + exit 1 +fi + +echo "Enabling Azure Disk Encryption on VM '$VM_NAME'..." + +az vm encryption enable \ + --resource-group "$RESOURCE_GROUP" \ + --name "$VM_NAME" \ + --disk-encryption-keyvault "$KEYVAULT_NAME" \ + --volume-type All + +echo "Waiting for encryption to complete..." + +az vm encryption show \ + --resource-group "$RESOURCE_GROUP" \ + --name "$VM_NAME" + +echo "Disk encryption enabled on all volumes for VM '$VM_NAME'." +echo "The VM may restart during the encryption process." +echo "Encryption of large disks can take several hours to complete." From 6a33d0f17dcbdd83fdc968cdd24f194b7830c4a4 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 22:50:18 +0100 Subject: [PATCH 3/9] feat: add AZ-CMP-002 to CIS compliance framework Added a new control for OS disk encryption requirements. --- compliance/frameworks/cis_azure_benchmark.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compliance/frameworks/cis_azure_benchmark.json b/compliance/frameworks/cis_azure_benchmark.json index 25552aa9..cfe4a84f 100644 --- a/compliance/frameworks/cis_azure_benchmark.json +++ b/compliance/frameworks/cis_azure_benchmark.json @@ -88,6 +88,11 @@ "control_name": "Ensure that 'OS disk' are encrypted", "description": "Virtual machines that are reachable from the internet should have Network Security Groups attached to their network interfaces to control and restrict inbound and outbound traffic, reducing the attack surface." }, + "AZ-CMP-002": { + "control_id": "7.2", + "control_name": "Ensure that 'OS disk' are encrypted", + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CIS 7.2 requires disks to be protected using customer-managed keys or Azure Disk Encryption. Platform-managed encryption does not give the organisation control over the encryption keys and does not satisfy this control." + }, "AZ-KV-001": { "control_id": "8.5", "control_name": "Ensure the Key Vault is Recoverable", From b6c2ac1931f1cd4216dc54f2a295b15e005f7f0b Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 22:52:39 +0100 Subject: [PATCH 4/9] feat: add AZ-CMP-002 to NIST compliance framework --- compliance/frameworks/nist_csf.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compliance/frameworks/nist_csf.json b/compliance/frameworks/nist_csf.json index cd421ed7..b9a75d6f 100644 --- a/compliance/frameworks/nist_csf.json +++ b/compliance/frameworks/nist_csf.json @@ -88,6 +88,11 @@ "control_name": "Remote access is managed", "description": "Virtual machines with public IPs and no NSG have unrestricted network access. NSGs should be attached to control inbound and outbound traffic and manage remote access to compute resources." }, + "AZ-CMP-002": { + "control_id": "PR.DS-1", + "control_name": "Data-at-rest is protected", + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). PR.DS-1 requires that data at rest is protected using appropriate controls. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control." + }, "AZ-KV-001": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", From 0ae7a48cc55704ab6b4bfda93189b7abfc41acbb Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 22:54:36 +0100 Subject: [PATCH 5/9] feat: add AZ-CMP-002 to ISO27001 compliance framework Added control AZ-CMP-002 regarding cryptographic controls policy and its requirements. --- compliance/frameworks/iso27001.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compliance/frameworks/iso27001.json b/compliance/frameworks/iso27001.json index 414d7612..08d87c4f 100644 --- a/compliance/frameworks/iso27001.json +++ b/compliance/frameworks/iso27001.json @@ -88,6 +88,11 @@ "control_name": "Network controls", "description": "Virtual machines with public IPs and no NSG have unrestricted network access. Network controls should be applied to all compute resources accessible from the internet." }, + "AZ-CMP-002": { + "control_id": "A.10.1.1", + "control_name": "Policy on the use of cryptographic controls", + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). A.10.1.1 requires that a policy on the use of cryptographic controls is developed and implemented. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control." + }, "AZ-KV-001": { "control_id": "A.17.2.1", "control_name": "Availability of information processing facilities", From b0aa7e79aefd6cbb9904ce89fd6c92e16aa0b7cd Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 22:56:33 +0100 Subject: [PATCH 6/9] feat: add AZ-CMP-002 to SOC2 compliance framework --- compliance/frameworks/soc2.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compliance/frameworks/soc2.json b/compliance/frameworks/soc2.json index 7de22578..c213c9df 100644 --- a/compliance/frameworks/soc2.json +++ b/compliance/frameworks/soc2.json @@ -93,6 +93,11 @@ "control_name": "Restricts Access from Outside the Network Boundary", "description": "A virtual machine with a public IP and no NSG has unrestricted inbound network access from the internet with no filtering in place. CC6.6 requires that logical access from outside the network perimeter is restricted and controlled. Attaching an NSG with explicit rules enforces the network boundary and controls what traffic can reach the VM." }, + "AZ-CMP-002": { + "control_id": "CC6.7", + "control_name": "Protects Data in Transit and At Rest", + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CC6.7 requires that data is protected using encryption. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control." + }, "AZ-KV-001": { "control_id": "A1.2", "control_name": "Environmental Threats and Recovery", From 6fbe569f6444de4a7ac1fec74ca573b5dfd7e2ae Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 23:05:28 +0100 Subject: [PATCH 7/9] fix: correct indentation in CIS AZ-CMP-002 entry --- compliance/frameworks/cis_azure_benchmark.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compliance/frameworks/cis_azure_benchmark.json b/compliance/frameworks/cis_azure_benchmark.json index cfe4a84f..1ab5a68b 100644 --- a/compliance/frameworks/cis_azure_benchmark.json +++ b/compliance/frameworks/cis_azure_benchmark.json @@ -89,9 +89,9 @@ "description": "Virtual machines that are reachable from the internet should have Network Security Groups attached to their network interfaces to control and restrict inbound and outbound traffic, reducing the attack surface." }, "AZ-CMP-002": { - "control_id": "7.2", - "control_name": "Ensure that 'OS disk' are encrypted", - "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CIS 7.2 requires disks to be protected using customer-managed keys or Azure Disk Encryption. Platform-managed encryption does not give the organisation control over the encryption keys and does not satisfy this control." + "control_id": "7.2", + "control_name": "Ensure that 'OS disk' are encrypted", + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CIS 7.2 requires disks to be protected using customer-managed keys or Azure Disk Encryption. Platform-managed encryption does not give the organisation control over the encryption keys and does not satisfy this control." }, "AZ-KV-001": { "control_id": "8.5", From b83e75822a6d03267caac158e6ab26962768ef96 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 23:22:08 +0100 Subject: [PATCH 8/9] feat: add remediation playbook fix_az_cmp_002.sh to correct location This script enables Azure Disk Encryption on a specified virtual machine using a provided Key Vault for disk encryption. --- playbooks/cli/fix_az_cmp_002.sh | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 playbooks/cli/fix_az_cmp_002.sh diff --git a/playbooks/cli/fix_az_cmp_002.sh b/playbooks/cli/fix_az_cmp_002.sh new file mode 100644 index 00000000..927790d7 --- /dev/null +++ b/playbooks/cli/fix_az_cmp_002.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# OpenShield Remediation Playbook +# Rule: AZ-CMP-002 — Virtual machine disk not protected by CMK or ADE +# Usage: ./fix_az_cmp_002.sh +# Severity: HIGH + +set -e + +RESOURCE_GROUP=$1 +VM_NAME=$2 +KEYVAULT_NAME=$3 + +if [ -z "$RESOURCE_GROUP" ] || [ -z "$VM_NAME" ] || [ -z "$KEYVAULT_NAME" ]; then + echo "Usage: $0 " + echo "" + echo "Prerequisites:" + echo " 1. Create a Key Vault if one does not exist:" + echo " az keyvault create --resource-group --name --enabled-for-disk-encryption true" + echo " 2. Ensure the VM is running before enabling encryption" + exit 1 +fi + +echo "Enabling Azure Disk Encryption on VM '$VM_NAME'..." + +az vm encryption enable \ + --resource-group "$RESOURCE_GROUP" \ + --name "$VM_NAME" \ + --disk-encryption-keyvault "$KEYVAULT_NAME" \ + --volume-type All + +echo "Waiting for encryption to complete..." + +az vm encryption show \ + --resource-group "$RESOURCE_GROUP" \ + --name "$VM_NAME" + +echo "Disk encryption enabled on all volumes for VM '$VM_NAME'." +echo "The VM may restart during the encryption process." +echo "Encryption of large disks can take several hours to complete." From 841d7f1d726b1d013d7fc920fa63b2580390875d Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 12 May 2026 23:29:56 +0100 Subject: [PATCH 9/9] Delete fix_az_cmp_002.sh --- fix_az_cmp_002.sh | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 fix_az_cmp_002.sh diff --git a/fix_az_cmp_002.sh b/fix_az_cmp_002.sh deleted file mode 100644 index 927790d7..00000000 --- a/fix_az_cmp_002.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# OpenShield Remediation Playbook -# Rule: AZ-CMP-002 — Virtual machine disk not protected by CMK or ADE -# Usage: ./fix_az_cmp_002.sh -# Severity: HIGH - -set -e - -RESOURCE_GROUP=$1 -VM_NAME=$2 -KEYVAULT_NAME=$3 - -if [ -z "$RESOURCE_GROUP" ] || [ -z "$VM_NAME" ] || [ -z "$KEYVAULT_NAME" ]; then - echo "Usage: $0 " - echo "" - echo "Prerequisites:" - echo " 1. Create a Key Vault if one does not exist:" - echo " az keyvault create --resource-group --name --enabled-for-disk-encryption true" - echo " 2. Ensure the VM is running before enabling encryption" - exit 1 -fi - -echo "Enabling Azure Disk Encryption on VM '$VM_NAME'..." - -az vm encryption enable \ - --resource-group "$RESOURCE_GROUP" \ - --name "$VM_NAME" \ - --disk-encryption-keyvault "$KEYVAULT_NAME" \ - --volume-type All - -echo "Waiting for encryption to complete..." - -az vm encryption show \ - --resource-group "$RESOURCE_GROUP" \ - --name "$VM_NAME" - -echo "Disk encryption enabled on all volumes for VM '$VM_NAME'." -echo "The VM may restart during the encryption process." -echo "Encryption of large disks can take several hours to complete."