fix: resolve real Disk resource for AZ-CMP-002 encryption detection - #237
fix: resolve real Disk resource for AZ-CMP-002 encryption detection#237parthrohit22 wants to merge 2 commits into
Conversation
_disk_needs_flagging() read managed_disk.security_profile.type and managed_disk.encryption.type, neither of which exist on azure.mgmt.compute.models.ManagedDiskParameters (id, storage_account_type, disk_encryption_set, security_profile) or VMDiskSecurityProfile (security_encryption_type, disk_encryption_set). Every branch resolved to None, so the rule never flagged a disk under any configuration. Add AzureClient.get_disk() to resolve the underlying Disk resource from a managed disk's id, cached per subscription, returning None (never treated as compliant) on failure. Classify each disk from Disk.encryption.type (platform key vs customer key vs platform-and-customer keys) and Disk.encryption_settings_collection.enabled (ADE). Disks that cannot be read are reported as indeterminate in finding metadata rather than silently passing. Rebuild the AZ-CMP-002 test fixtures against the real SDK attribute surface and add compliant/non-compliant/indeterminate coverage, including a regression test for the platform-key-only case that the old implementation always missed. Fixes #236 Signed-off-by: PARTH J ROHIT <parthrohit60@gmail.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
TFT444
left a comment
There was a problem hiding this comment.
@parthrohit22 The main fix looks good and all checks passed. Please handle unreadable disks as an unknown scan result instead of a confirmed HIGH finding, and add one test using the real Azure SDK disk model so the original mock-related bug cannot happen again.
Per review on #237: an unreadable Disk resource is not a confirmed CIS 7.2 violation, so it must not carry the same HIGH severity and remediation text as a genuine platform-key-only disk. Indeterminate disks now produce a distinct LOW-severity finding with its own description/remediation pointing at the missing Microsoft.Compute/disks/read grant, while a confirmed non-compliant disk still outweighs any indeterminate sibling on the same VM and keeps HIGH severity. Add regression tests built from genuine azure.mgmt.compute.models.ManagedDiskParameters/Disk/Encryption instances (not the make_resource stand-in, which accepts arbitrary kwargs and would have silently accepted the original bug's invented attribute shape) so the SDK-shape mismatch that caused the original fail-open bug cannot recur unnoticed. One test asserts ManagedDiskParameters has no encryption attribute directly, as a canary against a future SDK shape drift. Refs #236 Signed-off-by: PARTH J ROHIT <parthrohit60@gmail.com>
|
@TFT444 Thanks for the review — both addressed in c0252ad: Unreadable disks as an unknown result, not a confirmed HIGH finding: Agreed, treating "we couldn't read the Disk" the same as "we confirmed platform-key-only" was overstating certainty. Indeterminate disks now produce a distinct Test using the real Azure SDK disk model: Added Also ran the fix against a real Azure subscription (not just mocks) — a throwaway VM with a genuine platform-key-only disk, old implementation returned 0 findings against it, fixed implementation correctly returned 1. Details in the PR description; test resource group has been deleted.
|
What does this PR do?
Fixes AZ-CMP-002, which was fail-open and could never produce a finding against real Azure data under any configuration.
Type of change
Rule details (if applicable)
Testing
Real Azure test: I have an "Azure for Students" subscription authenticated via
az login. I provisioned a throwaway VM (Standard_B2ats_v2, no public IP) in a disposable resource group — its default OS disk isEncryptionAtRestWithPlatformKeywith no ADE, i.e. a genuinely non-compliant disk. I ran the rule against it live viaAzureCliCredential:determination: "non_compliant", correct disk name, correct framework mapping.The resource group was deleted immediately after (
az group delete --yes) — confirmed fully gone before pushing this branch, no lingering billable resources.I also ran
pytest,ruff check,ruff format --check, andbandit -r api/ scanner/ ai/ -lllocally exactly as the CI workflow configures them — 490 passed, 3 skipped. The actual GitHub Actions run on this push has now completed: every required check (lint, rule/compliance validation, secret scan, SAST, SCA, SBOM, container scan, backend tests + coverage, frontend, website, DCO sign-off,CI Summary) is green. The only non-green item issemgrep-cloud-platform/scan, an external app-based check outsideci.yml's own required job set, stillpendingas of this update.Related issue
Closes #236
Checklist
Signed-off-bytrailer (git commit -s; seedocs/dco.md)fix/description(bug fix, per CONTRIBUTING.md)The
FRAMEWORKSdict andcompliance/frameworks/*.jsonentries for AZ-CMP-002 were already correct and are unchanged — the bug was purely that the rule's detection logic could never fire, so every one of those mappings was a guaranteed silent pass. No mapping file changes were needed.The defect
_disk_needs_flagging()inscanner/rules/az_cmp_002.pyreadmanaged_disk.security_profileandmanaged_disk.encryption, then.typeoff whichever was non-None. The object actually passed in isazure.mgmt.compute.models.ManagedDiskParameters, which only exposesid,storage_account_type,disk_encryption_set, andsecurity_profile— there is noencryptionattribute. Itssecurity_profileis aVMDiskSecurityProfile, which carriessecurity_encryption_type, nottype. Every branch resolved toNone, so the function returnedFalsefor every disk on every VM, unconditionally.tests/test_rules_compute.pydidn't catch it because the fixtures builtmanaged_disk=make_resource(encryption=make_resource(type=...))— a shape the SDK never returns, sincemake_resourceaccepts arbitrary kwargs.The fix
AzureClient.get_disk()to resolve the realDiskresource from a managed disk'sid, cached per subscription, returningNoneon failure (matching the existing convention onget_managed_clusters/get_container_registries— callers must never treatNoneas compliant)._classify_disk()now determines compliance from the realDiskresource:Disk.encryption.typedistinguishesEncryptionAtRestWithPlatformKey(non-compliant) fromEncryptionAtRestWithCustomerKey/EncryptionAtRestWithPlatformAndCustomerKeys(compliant), andDisk.encryption_settings_collection.enabledreports Azure Disk Encryption (compliant regardless of key type).Diskresource can't be read are no longer silently treated as compliant — they're logged and surfaced so this can't regress into a silent pass again.playbooks/cli/fix_az_cmp_002.shwith a note that it only remediates confirmed (non_compliant) findings, not indeterminate ones, since running ADE remediation against an indeterminate finding could unnecessarily touch an already-compliant CMK disk.Disk) cases. The non-compliant test is a regression test — it fails against the old implementation and passes against this fix.Review changes (per @TFT444)
LOW-severity "unknown scan result", not aHIGH"confirmed" finding — separateINDETERMINATE_SEVERITY/INDETERMINATE_DESCRIPTION/INDETERMINATE_REMEDIATION. A confirmed non-compliant disk still keeps the finding atHIGHeven if a sibling disk on the same VM is indeterminate (metadata.determinationdistinguishes the two; seetest_cmp_002_confirmed_violation_outweighs_indeterminate_sibling_disk). This still satisfies "never silently pass on an unreadable disk," just without inflating an unknown into a confirmed HIGH violation.azure.mgmt.compute.modelsinstances (ManagedDiskParameters,Disk,Encryption,EncryptionSettingsCollection) rather than themake_resourcestand-in, which accepts arbitrary kwargs and is exactly what let the original bug's fixtures assert against a shape the SDK never returns. One test (test_cmp_002_managed_disk_parameters_has_no_encryption_attribute) asserts directly thatManagedDiskParametershas noencryptionattribute, as a canary against this exact bug class recurring if the SDK's shape ever drifts. These follow the same@pytest.mark.skipif(not _AZURE_SDK_AVAILABLE, ...)pattern already used intests/test_rules_network.pyfor AZ-NET-003.