What happened?
AZ-CMP-002 ("Virtual machine disk not protected by customer-managed key or ADE") is fail-open: it can never produce a finding against real Azure data, under any configuration. It always reports a guaranteed PASS for CIS 7.2, and, via the framework map in FRAMEWORKS, for SOC2 CC6.7, ISO 27001 A.10.1.1 and NIST PR.DS-1 as well.
The bug is in _disk_needs_flagging() in scanner/rules/az_cmp_002.py:
encryption = getattr(managed_disk, "security_profile", None)
if encryption is None:
encryption = getattr(managed_disk, "encryption", None)
encryption_type = getattr(encryption, "type", None)
managed_disk here is the azure.mgmt.compute.models.ManagedDiskParameters object embedded in a VM's storage_profile.os_disk / storage_profile.data_disks. Its actual constructor signature (azure-mgmt-compute==30.0.0, matching requirements.txt) is:
ManagedDiskParameters(*, id=None, storage_account_type=None, disk_encryption_set=None, security_profile=None, **kwargs)
There is no encryption attribute at all. security_profile, when present, is a VMDiskSecurityProfile:
VMDiskSecurityProfile(*, security_encryption_type=None, disk_encryption_set=None, **kwargs)
which carries security_encryption_type, not type.
So both branches of _disk_needs_flagging() resolve encryption_type to None for every disk on every VM, _disk_needs_flagging() unconditionally returns False, and scan() never appends a finding — regardless of what encryption is actually configured on the disk.
What did you expect?
A disk using only EncryptionAtRestWithPlatformKey (no CMK, no Azure Disk Encryption) should produce a HIGH finding for AZ-CMP-002, mapped through to CIS 7.2 / SOC2 CC6.7 / ISO 27001 A.10.1.1 / NIST PR.DS-1.
Steps to reproduce
-
In a Python shell with azure-mgmt-compute==30.0.0 installed (as pinned in requirements.txt), inspect the real attribute surface:
import inspect
import azure.mgmt.compute.models as m
print(inspect.signature(m.ManagedDiskParameters.__init__))
# (self, *, id=None, storage_account_type=None, disk_encryption_set=None, security_profile=None, **kwargs) -> None
print(inspect.signature(m.VMDiskSecurityProfile.__init__))
# (self, *, security_encryption_type=None, disk_encryption_set=None, **kwargs) -> None
Neither exposes encryption or .type respectively — confirming _disk_needs_flagging() can never see a non-None encryption_type.
-
Run the existing rule against a disk shaped like the real SDK object (not the test fixture, which is checked in step 3):
from types import SimpleNamespace as R
from scanner.rules.az_cmp_002 import _disk_needs_flagging
managed_disk = R(id="/subscriptions/x/resourceGroups/rg/providers/Microsoft.Compute/disks/d1",
storage_account_type="Standard_LRS", disk_encryption_set=None, security_profile=None)
print(_disk_needs_flagging(managed_disk)) # False — even though the disk may be platform-key-only
-
Note that tests/test_rules_compute.py does not catch this because its fixtures build an object the SDK never returns:
managed_disk=make_resource(encryption=make_resource(type="EncryptionAtRestWithPlatformKey"))
make_resource (tests/helpers/mock_azure.py) accepts arbitrary keyword arguments, so the test asserts against a shape that cannot exist in production — the test passes while the rule is fail-open against real data.
Environment
- OpenShield version: current
dev (commit 6ed2530)
- Python version: 3.11
- OS: N/A (server-side scanner rule, not environment-specific)
Logs or screenshots
N/A — this is a logic defect, not a runtime crash. scan() returns [] for every VM regardless of actual disk encryption configuration, and no error or warning is logged, so the false PASS is silent.
What happened?
AZ-CMP-002 ("Virtual machine disk not protected by customer-managed key or ADE") is fail-open: it can never produce a finding against real Azure data, under any configuration. It always reports a guaranteed PASS for CIS 7.2, and, via the framework map in
FRAMEWORKS, for SOC2 CC6.7, ISO 27001 A.10.1.1 and NIST PR.DS-1 as well.The bug is in
_disk_needs_flagging()inscanner/rules/az_cmp_002.py:managed_diskhere is theazure.mgmt.compute.models.ManagedDiskParametersobject embedded in a VM'sstorage_profile.os_disk/storage_profile.data_disks. Its actual constructor signature (azure-mgmt-compute==30.0.0, matchingrequirements.txt) is:There is no
encryptionattribute at all.security_profile, when present, is aVMDiskSecurityProfile:which carries
security_encryption_type, nottype.So both branches of
_disk_needs_flagging()resolveencryption_typetoNonefor every disk on every VM,_disk_needs_flagging()unconditionally returnsFalse, andscan()never appends a finding — regardless of what encryption is actually configured on the disk.What did you expect?
A disk using only
EncryptionAtRestWithPlatformKey(no CMK, no Azure Disk Encryption) should produce a HIGH finding for AZ-CMP-002, mapped through to CIS 7.2 / SOC2 CC6.7 / ISO 27001 A.10.1.1 / NIST PR.DS-1.Steps to reproduce
In a Python shell with
azure-mgmt-compute==30.0.0installed (as pinned inrequirements.txt), inspect the real attribute surface:Neither exposes
encryptionor.typerespectively — confirming_disk_needs_flagging()can never see a non-Noneencryption_type.Run the existing rule against a disk shaped like the real SDK object (not the test fixture, which is checked in step 3):
Note that
tests/test_rules_compute.pydoes not catch this because its fixtures build an object the SDK never returns:make_resource(tests/helpers/mock_azure.py) accepts arbitrary keyword arguments, so the test asserts against a shape that cannot exist in production — the test passes while the rule is fail-open against real data.Environment
dev(commit6ed2530)Logs or screenshots
N/A — this is a logic defect, not a runtime crash.
scan()returns[]for every VM regardless of actual disk encryption configuration, and no error or warning is logged, so the false PASS is silent.