Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

What's changed since pre-release v1.48.0-B0228:

- New rules:
- Azure Fleet:
- Added `Azure.Fleet.SecureBoot` to require Trusted Launch/Confidential VM with Secure Boot for fleet VM profiles by @l46983284-cpu.
[#3729](https://github.com/Azure/PSRule.Rules.Azure/issues/3729)
- General improvements:
- Added support for resolving filtered subnet IDs from existing virtual networks during Bicep expansion.
[#2159](https://github.com/Azure/PSRule.Rules.Azure/issues/2159)
Expand Down
187 changes: 187 additions & 0 deletions docs/en/rules/Azure.Fleet.SecureBoot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---
reviewed: 2026-07-14
severity: Important
pillar: Security
category: SE:08 Hardening resources
resource: Azure Fleet
resourceType: Microsoft.AzureFleet/fleets
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.Fleet.SecureBoot/
---

# Azure Fleet Secure Boot is not enabled

## SYNOPSIS

Operating systems or drivers may be maliciously modified or injected if an actor gains access to VM/ OS storage or build media.

## DESCRIPTION

Azure Fleet virtual machine profiles are able to run a wide range of operating systems including many distributions of Windows and Linux.
A malicious actor may attempt to tamper or inject operating system and driver components to gain access to resources and persist between reboots.

When a fleet VM instance is started, Azure is able to verify if:

1. The operating system and drivers originate from a trusted source.
2. These components are in their original unaltered state.

Azure is able to perform this verification by Secure Boot and Trusted Launch features.
These features verify the cryptographic signatures of early boot components before they start.

Secure Boot and Trusted Launch are on by default for many configurations.
However, if you are running an older configuration these features may need to be enabled.

Setting the security type to `ConfidentialVM` is also acceptable.

## RECOMMENDATION

Consider enabling Trusted Launch or Confidential VM with Secure Boot for Azure Fleet VM profiles to protect against boot-level attacks.

## EXAMPLES

### Configure with Bicep

To deploy an Azure Fleet that passes this rule:

- Set the `properties.computeProfile.baseVirtualMachineProfile.securityProfile.securityType` property to `TrustedLaunch` or `ConfidentialVM`.
- Set the `properties.computeProfile.baseVirtualMachineProfile.securityProfile.uefiSettings.secureBootEnabled` property to `true`.

For example:

```bicep
resource windows_fleet 'Microsoft.AzureFleet/fleets@2024-11-01' = {
name: name
location: location
properties: {
computeProfile: {
baseVirtualMachineProfile: {
securityProfile: {
securityType: 'TrustedLaunch'
encryptionAtHost: true
uefiSettings: {
secureBootEnabled: true
vTpmEnabled: true
}
}
osProfile: {
computerNamePrefix: 'fleet'
adminUsername: adminUsername
adminPassword: secret
}
networkProfile: {
networkInterfaceConfigurations: [
{
name: 'netconfig'
properties: {
ipConfigurations: [
{
name: 'ipconfig'
properties: {
primary: true
subnet: {
id: subnetId
}
}
}
]
}
}
]
}
}
}
vmSizesProfile: [
{
name: 'Standard_D8ds_v6'
rank: 0
}
]
regularPriorityProfile: {
minCapacity: 1
capacity: 5
allocationStrategy: 'Prioritized'
}
}
}
```

### Configure with Azure template

To deploy an Azure Fleet that passes this rule:

- Set the `properties.computeProfile.baseVirtualMachineProfile.securityProfile.securityType` property to `TrustedLaunch` or `ConfidentialVM`.
- Set the `properties.computeProfile.baseVirtualMachineProfile.securityProfile.uefiSettings.secureBootEnabled` property to `true`.

For example:

```json
{
"type": "Microsoft.AzureFleet/fleets",
"apiVersion": "2024-11-01",
"name": "[parameters('name')]",
"location": "[parameters('location')]",
"properties": {
"computeProfile": {
"baseVirtualMachineProfile": {
"securityProfile": {
"securityType": "TrustedLaunch",
"encryptionAtHost": true,
"uefiSettings": {
"secureBootEnabled": true,
"vTpmEnabled": true
}
},
"osProfile": {
"computerNamePrefix": "fleet",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('secret')]"
},
"networkProfile": {
"networkInterfaceConfigurations": [
{
"name": "netconfig",
"properties": {
"ipConfigurations": [
{
"name": "ipconfig",
"properties": {
"primary": true,
"subnet": {
"id": "[parameters('subnetId')]"
}
}
}
]
}
}
]
}
}
},
"vmSizesProfile": [
{
"name": "Standard_D8ds_v6",
"rank": 0
}
],
"regularPriorityProfile": {
"minCapacity": 1,
"capacity": 5,
"allocationStrategy": "Prioritized"
}
}
}
```

## NOTES

Currently there are a few limitations (see documentation for up to date details), including:

- A supported VM SKU and operating system is required.
- Secure Boot and Trusted Launch is only supported on Generation 2 VM images.

## LINKS

- [SE:08 Hardening resources](https://learn.microsoft.com/azure/well-architected/security/harden-resources)
- [Security: Level 2](https://learn.microsoft.com/azure/well-architected/security/maturity-model?tabs=level2)
- [Trusted Launch for Azure virtual machines](https://learn.microsoft.com/azure/virtual-machines/trusted-launch)
- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.azurefleet/fleets#securityprofile)
2 changes: 2 additions & 0 deletions src/PSRule.Rules.Azure/en/PSRule-rules.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
ReplicaInSecondaryNotFound = "A replica in a secondary region was not found."
VMSSPublicKey = "The virtual machine scale set '{0}' should have password authentication disabled."
FleetPublicKey = "The Azure Fleet '{0}' should have password authentication disabled."
FleetSecureBoot = "The Azure Fleet '{0}' should set the 'securityType' property to 'TrustedLaunch' or 'ConfidentialVM'."
FleetSecureBootEnabled = "The Azure Fleet '{0}' should have Secure Boot enabled."
ACRSoftDeletePolicy = "The container registry '{0}' should have soft delete policy enabled."
ACRSoftDeletePolicyRetention = "The container registry '{0}' should have retention period value between one to 90 days for the soft delete policy."
ContainerRegistryAuditDiagnosticSetting = "Minimum one diagnostic setting should have ({0}) configured or category group ({1}) configured."
Expand Down
9 changes: 9 additions & 0 deletions src/PSRule.Rules.Azure/rules/Azure.Fleet.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ Rule 'Azure.Fleet.PublicKey' -Ref 'AZR-000541' -Type 'Microsoft.AzureFleet/fleet
Reason($LocalizedData.FleetPublicKey, $PSRule.TargetName)
}


# Synopsis: Azure Fleet VM profiles should use Trusted Launch with Secure Boot enabled.
Rule 'Azure.Fleet.SecureBoot' -Ref 'AZR-000545' -Type 'Microsoft.AzureFleet/fleets' -Tag @{ release = 'GA'; ruleSet = '2026_09'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.WAF/maturity' = 'L2' } {
$Assert.In($TargetObject, 'properties.computeProfile.baseVirtualMachineProfile.securityProfile.securityType', @('TrustedLaunch', 'ConfidentialVM')).
Reason($LocalizedData.FleetSecureBoot, $PSRule.TargetName)
$Assert.HasFieldValue($TargetObject, 'properties.computeProfile.baseVirtualMachineProfile.securityProfile.uefiSettings.secureBootEnabled', $True).
Reason($LocalizedData.FleetSecureBootEnabled, $PSRule.TargetName)
}

#endregion Rules
20 changes: 18 additions & 2 deletions tests/PSRule.Rules.Azure.Tests/Azure.Fleet.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,24 @@ Describe 'Azure.Fleet' -Tag 'Fleet' {
# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'fleet-001';
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'fleet-001', 'fleet-005';
}

It 'Azure.Fleet.SecureBoot' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.Fleet.SecureBoot' };

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 5;
$ruleResult.TargetName | Should -BeIn 'fleet-001', 'fleet-002', 'fleet-003', 'fleet-006', 'fleet-007';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 3;
$ruleResult.TargetName | Should -BeIn 'fleet-004', 'fleet-005', 'fleet-008';
}
Comment on lines +60 to 74

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.

Could you add separate test cases for the two checks? The three failing fleets are missing the whole security profile, so they fail both checks at the same time. The test still passes if the secureBootEnabled assertion is removed.

Please add these cases:

  • TrustedLaunch with secureBootEnabled: false should fail.
  • An invalid or missing securityType with secureBootEnabled: true should fail.
  • ConfidentialVM with secureBootEnabled: true should pass.

This will confirm that both properties are checked and that ConfidentialVM is supported.

}
}
Loading