Skip to content

feat: add rule AZ-CMP-005 Trusted Launch (Secure Boot + vTPM) check - #273

Open
shariqueahmad108-ship-it wants to merge 2 commits into
openshield-org:devfrom
shariqueahmad108-ship-it:rule/az-cmp-005-trusted-launch
Open

feat: add rule AZ-CMP-005 Trusted Launch (Secure Boot + vTPM) check#273
shariqueahmad108-ship-it wants to merge 2 commits into
openshield-org:devfrom
shariqueahmad108-ship-it:rule/az-cmp-005-trusted-launch

Conversation

@shariqueahmad108-ship-it

Copy link
Copy Markdown
Contributor

What

Implements Rule 1 of #269AZ-CMP-005, flagging Generation 2 VMs that don't have Trusted Launch (Secure Boot and vTPM) fully enabled. (Per the issue's Coordination note, the Managed Identity rule was descoped, so this PR is the sole remaining scope.)

Follows the scanner/rules/ one-file-per-rule template, with the matching remediation playbook and compliance-framework mappings.

Detection logic

  • Compliantsecurity_type == "TrustedLaunch" and both uefi_settings.secure_boot_enabled and v_tpm_enabled are True.
  • Gen1 = NOT_APPLICABLE. A VM's list_all() representation doesn't carry its Hyper-V generation, so the rule resolves the OS disk's hyper_v_generation (via azure_client.get_disk(), the same pattern AZ-CMP-002 uses) to confirm a VM is Gen2 before flagging. A readable Gen1 disk reports V1 and is skipped — no false finding against hardware that can't run Trusted Launch.
  • security_type == "TrustedLaunch" but Secure Boot / vTPM off is Gen2-only by definition, so it's flagged without needing a disk lookup.
  • Confidential VMs (Secure Boot + vTPM by construction) are out of scope and skipped.
  • Unknown generation (OS disk unreadable / missing) is deliberately left unflagged — an unreadable disk could be Gen1, and the issue explicitly asks that Gen1 not produce a false finding. This mirrors the repo's existing "never treat an indeterminate result as a violation" stance (AZ-CMP-002). Trade-off: a Gen2 VM whose disk generation can't be read is a possible false negative; I erred toward zero Gen1 false positives, but happy to switch to surfacing it as a distinct low-severity/unknown result if you'd prefer the AZ-CMP-002 treatment.

Compliance mappings (all four framework JSONs)

Framework Control Rationale
NIST CSF PR.DS-6 Firmware/software integrity verification (Secure Boot + vTPM measured boot)
ISO 27001 A.12.5.1 Installation of software on operational systems — only signed boot code runs
SOC 2 CC6.8 Prevents/detects unauthorized software at boot
CIS N/A-CMP-005 CIS Azure Foundations 2.0.0 has no dedicated Trusted Launch recommendation, so this uses the repo's existing N/A convention (as in AZ-KV-001) rather than a fabricated control id — glad to renumber if there's a preferred mapping.

Tests

Six unit tests added to tests/test_rules_compute.py (mock-based, no network):

  • compliant TrustedLaunch → no findings
  • Gen2 (disk V2) without a security profile → one MEDIUM finding
  • TrustedLaunch declared but vTPM off → flagged without a disk lookup
  • Gen1 (disk V1) → NOT_APPLICABLE, no finding
  • unknown generation (disk unreadable) → not flagged
  • Confidential VM → not flagged
231 passed   # full rule-test suite (tests/test_rules_*.py + test_pqc_rules.py)
ruff check .            → clean
ruff format --check .   → clean

Honest testing note

I don't have an Azure subscription, so I could not run the issue's "tested against a real Azure free-trial subscription" step — the live checkboxes below are left unchecked for a maintainer/reviewer to confirm. The rule is fully covered by the unit tests above (compliant / non-compliant / Gen1 / unknown / confidential) and the fixtures mirror the real SDK attribute shapes (SecurityProfile.security_type, UefiSettings.secure_boot_enabled / v_tpm_enabled, Disk.hyper_v_generation).

Test plan (from the issue)

  • Compliant case returns no findings (unit)
  • Non-compliant case returns correct finding (unit)
  • Gen1 VMs return NOT_APPLICABLE, not a false finding (unit)
  • CLI playbook written (fix_az_cmp_005.sh)
  • All four compliance framework JSONs updated
  • Tested against a real Azure free-trial subscription (needs maintainer — no Azure access on my side)

Closes #269

dipeshrayg added a commit to dipeshrayg/openshield that referenced this pull request Aug 14, 2026
AZ-CMP-005 collided with openshield-org#273 (Trusted Launch check), opened a day
before this PR and already claiming that rule ID. Renumbered the rule
file, playbook, tests, and all four compliance framework entries to
AZ-CMP-006.

Also fixes a false-positive gap flagged in review: the rule only
checked for an NSG on the VMSS network interface configuration itself,
missing the case where the NSG is attached at the subnet level
instead. A VMSS whose NIC has no NSG but deploys into a
subnet that does have one was being incorrectly flagged. Now resolves
each network interface configuration's subnet (via the existing
get_virtual_networks() collector, no new collector needed) and treats
either a NIC-level or subnet-level NSG as compliant, matching how
AZ-NET-010 already reads subnet.network_security_group.

Added SOC2 to the rule's own FRAMEWORKS dict (was previously only in
soc2.json, inconsistent with how several other rules, e.g. AZ-KV-006,
already include it directly).

Addresses review feedback from TFT444 and m-khan-97 on openshield-org#275.

Signed-off-by: Dipesh Ray <dipesh.ray.g@gmail.com>
parthrohit22
parthrohit22 previously approved these changes Aug 16, 2026

@parthrohit22 parthrohit22 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice work @shariqueahmad108-ship-it ,
Solid rule. I like that you didn't just flag every VM without Trusted Launch - you actually resolve Gen1 vs Gen2 via the OS disk and treat "can't determine" as NOT_APPLICABLE instead of guessing, which keeps this from throwing false positives on VMs that physically can't support it. Confidential VM carve-out is a nice touch too. Verified the SDK fields (security_type, uefi_settings, secure_boot_enabled, v_tpm_enabled, hyper_v_generation) against the real azure-mgmt-compute models, all match. 562 passed, clean lint. No conflict with #275's AZ-CMP-006. LGTM, approving.

@Vishnu2707
Vishnu2707 requested review from Vishnu2707 and removed request for SHAURYAKSHARMA24, TFT444 and ritiksah141 August 17, 2026 23:17

@Vishnu2707 Vishnu2707 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing before merge though, the playbook uses RG=$1 and VM=$2 directly, with set -u that'll just crash instead of showing the usage message if someone runs it with no args. Same issue @TFT444 flagged on KV-006 before, just needs ${1:-} and ${2:-} like fix_az_net_016.sh already does. That should be a quick fix though.

# Note: only supported on Gen2 VM sizes/images; the update requires a restart to take effect.

set -euo pipefail

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use ${1:-} and ${2:-} like how it is present in fix_az_net_016.sh to avoid further bugs

shariqueahmad108-ship-it added a commit to shariqueahmad108-ship-it/openshield that referenced this pull request Aug 20, 2026
Use ${1:-}/${2:-} so running the playbook with missing arguments prints the
usage message and exits 1, instead of crashing on an unbound variable under
`set -euo pipefail`. Matches the convention in fix_az_net_016.sh.

Addresses review feedback from @Vishnu2707 on openshield-org#273.

Signed-off-by: shariqueahmad108-ship-it <shariqueahmad108@gmail.com>
@shariqueahmad108-ship-it

Copy link
Copy Markdown
Contributor Author

Good catch @Vishnu2707 — fixed in 3415de1. Switched to ${1:-}/${2:-} (matching fix_az_net_016.sh) so a no-arg or partial-arg run prints the usage message and exits 1 instead of tripping set -u on an unbound variable. Verified both the zero-arg and one-arg cases now print usage cleanly. Thanks for the review!

@TFT444 TFT444 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single blocking issue: fix_az_cmp_005.sh uses RG=\ and VM=\ with set -u at the top. Running the script without arguments crashes before the usage message is printed. Change both to \ and , matching the pattern in fix_az_net_016.sh. Everything else looks good.

@shariqueahmad108-ship-it

Copy link
Copy Markdown
Contributor Author

Thanks @TFT444 — that one's already handled: fix_az_cmp_005.sh was updated in 3415de1 to use RG="${1:-}" / VM="${2:-}" (lines 9-10, matching fix_az_net_016.sh), so a no-arg run prints the usage message and exits 1 instead of tripping set -u. Vishnu2707 raised the same point earlier and it's fixed on the current head. Could you re-check 3415de1? Happy to adjust if you're seeing something different.

@TFT444

TFT444 commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

@shariqueahmad108-ship-it branch have conflict solve it please
thank u

Adds a Compute scan rule that flags Generation 2 VMs which do not have
Trusted Launch fully enabled (security type TrustedLaunch with both Secure
Boot and vTPM on). Without them, unsigned or malicious code can run during
boot and persist beneath the OS, evading OS-level antimalware and EDR.

Generation 1 VMs cannot use Trusted Launch and are treated as NOT_APPLICABLE:
a VM's list_all() representation does not carry its Hyper-V generation, so the
rule resolves the OS disk's hyper_v_generation to confirm a VM is Gen2 before
flagging, and never raises a false finding against Gen1 hardware. A security
type already declared as TrustedLaunch is itself Gen2-only, so a
Secure-Boot/vTPM-off VM there is flagged without a disk lookup. Confidential
VMs (which provide Secure Boot and vTPM by construction) are out of scope, and
a VM whose generation cannot be confirmed is left unflagged rather than
risking a Gen1 false positive.

Includes the remediation playbook (playbooks/cli/fix_az_cmp_005.sh) and maps
the rule across the four compliance frameworks: NIST CSF PR.DS-6, ISO 27001
A.12.5.1, and SOC 2 CC6.8. CIS uses the repository's existing N/A convention
(as in AZ-KV-001) because CIS Azure Foundations 2.0.0 has no dedicated Trusted
Launch recommendation. Adds six unit tests covering the compliant,
non-compliant Gen2, TrustedLaunch-declared-but-vTPM-off, Gen1 NOT_APPLICABLE,
unknown-generation, and Confidential-VM cases.

Closes openshield-org#269

Signed-off-by: shariqueahmad108-ship-it <shariqueahmad108@gmail.com>
Use ${1:-}/${2:-} so running the playbook with missing arguments prints the
usage message and exits 1, instead of crashing on an unbound variable under
`set -euo pipefail`. Matches the convention in fix_az_net_016.sh.

Addresses review feedback from @Vishnu2707 on openshield-org#273.

Signed-off-by: shariqueahmad108-ship-it <shariqueahmad108@gmail.com>
@shariqueahmad108-ship-it
shariqueahmad108-ship-it force-pushed the rule/az-cmp-005-trusted-launch branch from 3415de1 to 67d21d7 Compare August 31, 2026 08:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(scanner): add AZ-XXX-000/AZ-XXX-000 Trusted Launch and Managed Identity rules

4 participants