Skip to content

bug: AZ-CMP-002 is fail-open, never flags platform-key-only disk encryption #236

Description

@parthrohit22

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

  1. 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.

  2. 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
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status
    🔨 In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions