diff --git a/docs/CHANGELOG-v1.md b/docs/CHANGELOG-v1.md index b5d7020116a..0f658cfce5f 100644 --- a/docs/CHANGELOG-v1.md +++ b/docs/CHANGELOG-v1.md @@ -34,14 +34,21 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers What's changed since v1.32.1: +- Updated rules: + - Cognitive Services: + - Relaxed `Azure.Cognitive.ManagedIdentity` to configurations that require managed identities by @BernieWhite. + [#2559](https://github.com/Azure/PSRule.Rules.Azure/issues/2559) + - Virtual Machine: + - Checks for Azure Hybrid Benefit `Azure.VM.UseHybridUseBenefit` are not enabled by default by @BernieWhite. + [#2493](https://github.com/Azure/PSRule.Rules.Azure/issues/2493) + - To enable, set the `AZURE_VM_USE_HYBRID_USE_BENEFIT` option to `true`. + - Virtual Network: + - Added option for excluding subnets to `Azure.VNET.UseNSGs` by @BernieWhite. + [#2572](https://github.com/Azure/PSRule.Rules.Azure/issues/2572) + - To add a subnet exclusion, set the `AZURE_VNET_SUBNET_EXCLUDED_FROM_NSG` option. - General improvements: - Quality updates to rules and documentation by @BernieWhite. [#1772](https://github.com/Azure/PSRule.Rules.Azure/issues/1772) - - Added option for excluding subnets to `Azure.VNET.UseNSGs` by @BernieWhite. - [#2572](https://github.com/Azure/PSRule.Rules.Azure/issues/2572) - - To add a subnet exclusion, set the `AZURE_VNET_SUBNET_EXCLUDED_FROM_NSG` option. - - Relax `Azure.Cognitive.ManagedIdentity` to required configurations by @BernieWhite. - [#2559](https://github.com/Azure/PSRule.Rules.Azure/issues/2559) - Engineering: - Bump xunit to v2.6.4. [#2618](https://github.com/Azure/PSRule.Rules.Azure/pull/2618) diff --git a/docs/en/rules/Azure.VM.UseHybridUseBenefit.md b/docs/en/rules/Azure.VM.UseHybridUseBenefit.md index b082c24ef12..626af049c70 100644 --- a/docs/en/rules/Azure.VM.UseHybridUseBenefit.md +++ b/docs/en/rules/Azure.VM.UseHybridUseBenefit.md @@ -1,7 +1,8 @@ --- +reviewed: 2024-01-03 severity: Awareness pillar: Cost Optimization -category: Pricing and billing model +category: CO:05 Rate optimization resource: Virtual Machine online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.VM.UseHybridUseBenefit/ --- @@ -14,11 +15,31 @@ Use Azure Hybrid Benefit for applicable virtual machine (VM) workloads. ## DESCRIPTION -Azure Hybrid Benefit is a licensing benefit that helps you to reduce costs of running virtual machine (VM) workloads. +The running cost of Virtual machine (VM) workloads in Azure is composed of several components, including: + +- Compute usage for the VM size and image billed per second of run time, which may include: + - Base compute rate for the VM size. + - Software included on the VM image billed per second of run time, such as Windows Server or SQL Server. +- Storage usage for the VM disks. +- Network usage for data transfer in and out of the VM. +- Usage of other supporting Azure resources, such as load balancers, public IP addresses, or log ingestion. +- Licensing costs for other software installed on the VM. + +Azure Hybrid Benefit is a licensing benefit that helps you to reduce your overall cost of ownership. +With Azure Hybrid Benefit you to use your existing on-premises licenses to pay a reduced rate on Azure. + +When Azure Hybrid Benefit enabled on supported VM images: + +- The billing rate for the VM is adjusted to the base compute rate. +- You must separately have eligible licenses, such as Windows Server or SQL Server because Azure does not include these anymore. + +For additional information on Azure Hybrid Benefit, see the [Azure Hybrid Benefit FAQ][1]. + + [1]: https://azure.microsoft.com/pricing/hybrid-benefit/#faq ## RECOMMENDATION -Consider using Azure Hybrid Benefit for eligible workloads. +Consider using Azure Hybrid Benefit for eligible virtual machine (VM) workloads. ## EXAMPLES @@ -34,44 +55,50 @@ For example: ```json { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2021-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "hardwareProfile": { - "vmSize": "Standard_D2s_v3" - }, - "osProfile": { - "computerName": "[parameters('name')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "storageProfile": { - "imageReference": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "[parameters('sku')]", - "version": "latest" - }, - "osDisk": { - "name": "[format('{0}-disk0', parameters('name'))]", - "caching": "ReadWrite", - "createOption": "FromImage" - } - }, - "licenseType": "Windows_Server", - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', format('{0}-nic0', parameters('name')))]" - } - ] + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "zones": [ + "1" + ], + "properties": { + "hardwareProfile": { + "vmSize": "Standard_D2s_v3" + }, + "osProfile": { + "computerName": "[parameters('name')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]" + }, + "storageProfile": { + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "[parameters('sku')]", + "version": "latest" + }, + "osDisk": { + "name": "[format('{0}-disk0', parameters('name'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "managedDisk": { + "storageAccountType": "Premium_LRS" } + } }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces', format('{0}-nic0', parameters('name')))]" - ] + "licenseType": "Windows_Server", + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" + ] } ``` @@ -86,9 +113,12 @@ To deploy VMs that pass this rule: For example: ```bicep -resource vm 'Microsoft.Compute/virtualMachines@2021-07-01' = { +resource vm_with_benefit 'Microsoft.Compute/virtualMachines@2023-09-01' = { name: name location: location + zones: [ + '1' + ] properties: { hardwareProfile: { vmSize: 'Standard_D2s_v3' @@ -109,6 +139,9 @@ resource vm 'Microsoft.Compute/virtualMachines@2021-07-01' = { name: '${name}-disk0' caching: 'ReadWrite' createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Premium_LRS' + } } } licenseType: 'Windows_Server' @@ -129,8 +162,26 @@ resource vm 'Microsoft.Compute/virtualMachines@2021-07-01' = { az vm update -n '' -g '' --set licenseType=Windows_Server ``` +### NOTES + +This rule is not processed by default. +To enable this rule, set the `AZURE_VM_USE_AZURE_HYBRID_BENEFIT` configuration value to `true`. + +For example: + +```yaml title="ps-rule.yaml" +configuration: + AZURE_VM_USE_AZURE_HYBRID_BENEFIT: true +``` + +The following limitations currently apply: + +- This rule only applies to Azure Hybrid Benefit for Windows VMs. + Linux VM images are ignored. + ## LINKS -- [Design review checklist for Cost Optimization](https://learn.microsoft.com/azure/well-architected/cost-optimization/checklist) -- [Azure Hybrid Benefit FAQ](https://azure.microsoft.com/pricing/hybrid-benefit/faq/) +- [CO:05 Rate optimization](https://learn.microsoft.com/azure/well-architected/cost-optimization/get-best-rates) +- [Azure Hybrid Benefit FAQ](https://azure.microsoft.com/pricing/hybrid-benefit/#faq) - [Explore Azure Hybrid Benefit for Windows VMs](https://learn.microsoft.com/azure/virtual-machines/windows/hybrid-use-benefit-licensing) +- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.compute/virtualmachines) diff --git a/docs/examples-vm.bicep b/docs/examples-vm.bicep index 304429eaee3..a227afe55ec 100644 --- a/docs/examples-vm.bicep +++ b/docs/examples-vm.bicep @@ -23,8 +23,50 @@ param sku string @description('A reference to the VNET subnet where the VM will be deployed.') param subnetId string -// An example basic VM -resource vm1 'Microsoft.Compute/virtualMachines@2023-07-01' = { +// An example virtual machine. +resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = { + name: name + location: location + zones: [ + '1' + ] + properties: { + hardwareProfile: { + vmSize: 'Standard_D2s_v3' + } + osProfile: { + computerName: name + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: sku + version: 'latest' + } + osDisk: { + name: '${name}-disk0' + caching: 'ReadWrite' + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + } + networkProfile: { + networkInterfaces: [ + { + id: nic.id + } + ] + } + } +} + +// An example virtual machine with Azure Hybrid Benefit. +resource vm_with_benefit 'Microsoft.Compute/virtualMachines@2023-09-01' = { name: name location: location zones: [ @@ -71,7 +113,8 @@ resource vm1 'Microsoft.Compute/virtualMachines@2023-07-01' = { @sys.description('The name of the resource.') param nicName string -resource nic 'Microsoft.Network/networkInterfaces@2023-05-01' = { +// An example network interface +resource nic 'Microsoft.Network/networkInterfaces@2023-06-01' = { name: nicName location: location properties: { diff --git a/docs/examples-vm.json b/docs/examples-vm.json index 2eb087d3aa8..a30128246ae 100644 --- a/docs/examples-vm.json +++ b/docs/examples-vm.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "1366791398259070498" + "version": "0.24.24.22086", + "templateHash": "8240160405856325456" } }, "parameters": { @@ -58,7 +58,52 @@ "resources": [ { "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-07-01", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "zones": [ + "1" + ], + "properties": { + "hardwareProfile": { + "vmSize": "Standard_D2s_v3" + }, + "osProfile": { + "computerName": "[parameters('name')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]" + }, + "storageProfile": { + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "[parameters('sku')]", + "version": "latest" + }, + "osDisk": { + "name": "[format('{0}-disk0', parameters('name'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', parameters('nicName'))]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "zones": [ @@ -104,7 +149,7 @@ }, { "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2023-05-01", + "apiVersion": "2023-06-01", "name": "[parameters('nicName')]", "location": "[parameters('location')]", "properties": { diff --git a/docs/setup/configuring-rules.md b/docs/setup/configuring-rules.md index bafd8139add..738b1ad2bb0 100644 --- a/docs/setup/configuring-rules.md +++ b/docs/setup/configuring-rules.md @@ -26,14 +26,14 @@ Rules that check the Kubernetes version fail when the version is older than the Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_AKS_CLUSTER_MINIMUM_VERSION: string # A version string ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_AKS_CLUSTER_MINIMUM_VERSION configuration option configuration: AZURE_AKS_CLUSTER_MINIMUM_VERSION: 1.27.7 @@ -41,7 +41,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_AKS_CLUSTER_MINIMUM_VERSION configuration option to 1.22.4 configuration: AZURE_AKS_CLUSTER_MINIMUM_VERSION: 1.22.4 @@ -56,14 +56,14 @@ This configuration option determines the minimum subnet size for Azure AKS CNI. Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_AKS_CNI_MINIMUM_CLUSTER_SUBNET_SIZE: integer ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_AKS_CNI_MINIMUM_CLUSTER_SUBNET_SIZE configuration option configuration: AZURE_AKS_CNI_MINIMUM_CLUSTER_SUBNET_SIZE: 23 @@ -71,7 +71,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_AKS_CNI_MINIMUM_CLUSTER_SUBNET_SIZE configuration option to 26 configuration: AZURE_AKS_CNI_MINIMUM_CLUSTER_SUBNET_SIZE: 26 @@ -102,14 +102,14 @@ The following rules and configuration options are supported: Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_AKS_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST: array ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_AKS_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST configuration option configuration: AZURE_AKS_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST: [] @@ -117,7 +117,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_AKS_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST configuration option to Antarctica North and Antarctica South, with zones 1, 2, 3. configuration: AZURE_AKS_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST: @@ -152,14 +152,14 @@ This configuration option sets selective platform diagnostic categories to repor Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_AKS_ENABLED_PLATFORM_LOG_CATEGORIES_LIST: array ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_AKS_ENABLED_PLATFORM_LOG_CATEGORIES_LIST configuration option configuration: AZURE_AKS_ENABLED_PLATFORM_LOG_CATEGORIES_LIST: @@ -186,14 +186,14 @@ This configuration option sets selective platform diagnostic categories to repor Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_AUTOMATIONACCOUNT_ENABLED_PLATFORM_LOG_CATEGORIES_LIST: array ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_AUTOMATIONACCOUNT_ENABLED_PLATFORM_LOG_CATEGORIES_LIST configuration option configuration: AZURE_AUTOMATIONACCOUNT_ENABLED_PLATFORM_LOG_CATEGORIES_LIST: @@ -205,7 +205,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_AUTOMATIONACCOUNT_ENABLED_PLATFORM_LOG_CATEGORIES_LIST configuration option to JobLogs and AllMetrics categories only. configuration: AZURE_AUTOMATIONACCOUNT_ENABLED_PLATFORM_LOG_CATEGORIES_LIST: @@ -227,14 +227,14 @@ Depending on your workloads it may make sense to change this option: Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: Azure_AKSNodeMinimumMaxPods: integer ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default Azure_AKSNodeMinimumMaxPods configuration option configuration: Azure_AKSNodeMinimumMaxPods: 50 @@ -242,7 +242,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the Azure_AKSNodeMinimumMaxPods configuration option to 30 configuration: Azure_AKSNodeMinimumMaxPods: 30 @@ -258,14 +258,14 @@ Configure this option to change the minimum API version, which defaults to `'202 Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_APIM_MIN_API_VERSION: string ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_APIM_MIN_API_VERSION configuration option configuration: AZURE_APIM_MIN_API_VERSION: '2021-08-01' @@ -273,7 +273,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_APIM_MIN_API_VERSION configuration option to '2021-12-01-preview' configuration: AZURE_APIM_MIN_API_VERSION: '2021-12-01-preview' @@ -285,14 +285,14 @@ This configuration specifies whether if external ingress should be enabled or di Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: - AZURE_CONTAINERAPPS_RESTRICT_INGRESS: boolean # An boolean value + AZURE_CONTAINERAPPS_RESTRICT_INGRESS: boolean ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_CONTAINERAPPS_RESTRICT_INGRESS configuration option configuration: AZURE_CONTAINERAPPS_RESTRICT_INGRESS: false @@ -300,7 +300,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_CONTAINERAPPS_RESTRICT_INGRESS configuration option to enabled configuration: AZURE_CONTAINERAPPS_RESTRICT_INGRESS: true @@ -313,14 +313,14 @@ Configure this option to enable the per account validation, which defaults to `f Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_COSMOS_DEFENDER_PER_ACCOUNT: boolean ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_COSMOS_DEFENDER_PER_ACCOUNT configuration option configuration: AZURE_COSMOS_DEFENDER_PER_ACCOUNT: false @@ -328,7 +328,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_COSMOS_DEFENDER_PER_ACCOUNT configuration option to true configuration: AZURE_COSMOS_DEFENDER_PER_ACCOUNT: true @@ -346,14 +346,14 @@ By default, `AZURE_DEPLOYMENT_NONSENSITIVE_PARAMETER_NAMES` is not configured. Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_DEPLOYMENT_NONSENSITIVE_PARAMETER_NAMES: array ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_DEPLOYMENT_NONSENSITIVE_PARAMETER_NAMES configuration option configuration: AZURE_DEPLOYMENT_NONSENSITIVE_PARAMETER_NAMES: [] @@ -361,7 +361,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_DEPLOYMENT_NONSENSITIVE_PARAMETER_NAMES configuration option to enabled configuration: AZURE_DEPLOYMENT_NONSENSITIVE_PARAMETER_NAMES: @@ -378,14 +378,14 @@ By setting this configuration option, properties with the specified names will g Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_DEPLOYMENT_SENSITIVE_PROPERTY_NAMES: array ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_DEPLOYMENT_SENSITIVE_PROPERTY_NAMES configuration option configuration: AZURE_DEPLOYMENT_SENSITIVE_PROPERTY_NAMES: @@ -396,7 +396,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_DEPLOYMENT_SENSITIVE_PROPERTY_NAMES configuration option to enabled configuration: AZURE_DEPLOYMENT_SENSITIVE_PROPERTY_NAMES: @@ -418,7 +418,7 @@ By default, `AZURE_RESOURCE_ALLOWED_LOCATIONS` is not configured. Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_RESOURCE_ALLOWED_LOCATIONS: array # An array of regions ``` @@ -433,7 +433,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_RESOURCE_ALLOWED_LOCATIONS configuration option to Australia East, Australia South East configuration: AZURE_RESOURCE_ALLOWED_LOCATIONS: @@ -446,7 +446,7 @@ also consider setting `AZURE_RESOURCE_GROUP` the configuration value to when res For example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_RESOURCE_GROUP: location: australiaeast @@ -459,7 +459,7 @@ Rules that check certificate lifetime fail when the days remaining before expiry Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: Azure_MinimumCertificateLifetime: integer ``` @@ -474,7 +474,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the Azure_MinimumCertificateLifetime configuration option to 90 configuration: Azure_MinimumCertificateLifetime: 90 @@ -490,7 +490,7 @@ Rules that check if a VM or VMSS has Linux OS also validate against the values s Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_LINUX_OS_OFFERS: array # An array of offer names ``` @@ -505,7 +505,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_LINUX_OS_OFFERS configuration option to aLinuxOffer, anotherLinuxOffer configuration: AZURE_LINUX_OS_OFFERS: @@ -528,14 +528,14 @@ Configure this option to ignore policy definitions that: Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_POLICY_IGNORE_LIST: array ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_POLICY_IGNORE_LIST configuration option configuration: AZURE_POLICY_IGNORE_LIST: [] @@ -543,7 +543,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Add a custom policy definition to ignore AZURE_POLICY_IGNORE_LIST: - '/providers/Microsoft.Authorization/policyDefinitions/1f314764-cb73-4fc9-b863-8eca98ac36e9' @@ -559,14 +559,14 @@ This configuration option will be ignored when `-Prefix` is used with `Export-Az Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_POLICY_RULE_PREFIX: string ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_POLICY_RULE_PREFIX configuration option configuration: AZURE_POLICY_RULE_PREFIX: Azure @@ -574,7 +574,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Override the prefix of exported policy rules AZURE_POLICY_RULE_PREFIX: AzureCustomPrefix ``` @@ -585,14 +585,14 @@ This configuration option determines the maximum number of days in the future fo Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_POLICY_WAIVER_MAX_EXPIRY: integer ``` Default: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: The default AZURE_POLICY_WAIVER_MAX_EXPIRY configuration option configuration: AZURE_POLICY_WAIVER_MAX_EXPIRY: 366 @@ -600,7 +600,7 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_POLICY_WAIVER_MAX_EXPIRY configuration option to 90 configuration: AZURE_POLICY_WAIVER_MAX_EXPIRY: 90 @@ -616,7 +616,7 @@ Configure this option to enable the per account validation, which defaults to `f Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_STORAGE_DEFENDER_PER_ACCOUNT: boolean ``` @@ -631,12 +631,46 @@ configuration: Example: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" # YAML: Set the AZURE_STORAGE_DEFENDER_PER_ACCOUNT configuration option to true configuration: AZURE_STORAGE_DEFENDER_PER_ACCOUNT: true ``` +### AZURE_VM_USE_AZURE_HYBRID_BENEFIT + + + + +This configuration option determines whether to check for Azure Hybrid Benefit (AHB) when deploying Windows VMs. +When enabled, rules that check for AHB fail when the VM is not configured to use AHB. + +To use AHB, you must separately have eligible licenses, such as Windows Server or SQL Server. + +By default, this configuration option is set to `false`. + +Syntax: + +```yaml title="ps-rule.yaml" +configuration: + AZURE_VM_USE_AZURE_HYBRID_BENEFIT: boolean +``` + +Default: + +```yaml title="ps-rule.yaml" +configuration: + AZURE_VM_USE_AZURE_HYBRID_BENEFIT: false +``` + +Example: + +```yaml title="ps-rule.yaml" +# Set the configuration option to enabled. +configuration: + AZURE_VNET_DNS_WITH_IDENTITY: true +``` + ### AZURE_VNET_DNS_WITH_IDENTITY @@ -654,23 +688,22 @@ By default, this configuration option is set to `false`. Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: - AZURE_VNET_DNS_WITH_IDENTITY: boolean # An boolean value + AZURE_VNET_DNS_WITH_IDENTITY: boolean ``` Default: -```yaml title='ps-rule.yaml' -# YAML: The default AZURE_VNET_DNS_WITH_IDENTITY configuration option +```yaml title="ps-rule.yaml" configuration: AZURE_VNET_DNS_WITH_IDENTITY: false ``` Example: -```yaml title='ps-rule.yaml' -# YAML: Set the AZURE_VNET_DNS_WITH_IDENTITY configuration option to enabled +```yaml title="ps-rule.yaml" +# Set the configuration option to enabled. configuration: AZURE_VNET_DNS_WITH_IDENTITY: true ``` @@ -686,23 +719,22 @@ To configure this option, specify a list of subnet names to exclude. Syntax: -```yaml title='ps-rule.yaml' +```yaml title="ps-rule.yaml" configuration: AZURE_VNET_SUBNET_EXCLUDED_FROM_NSG: array ``` Default: -```yaml title='ps-rule.yaml' -# YAML: The default AZURE_VNET_SUBNET_EXCLUDED_FROM_NSG configuration option +```yaml title="ps-rule.yaml" configuration: AZURE_VNET_SUBNET_EXCLUDED_FROM_NSG: [] ``` Example: -```yaml title='ps-rule.yaml' -# YAML: Set the AZURE_VNET_SUBNET_EXCLUDED_FROM_NSG configuration option with two customs subnets. +```yaml title="ps-rule.yaml" +# Configure two customs subnets to be excluded from NSG checks. configuration: AZURE_VNET_SUBNET_EXCLUDED_FROM_NSG: - subnet-1 diff --git a/src/PSRule.Rules.Azure/rules/Azure.VM.Rule.ps1 b/src/PSRule.Rules.Azure/rules/Azure.VM.Rule.ps1 index 69c40ab2be3..e3045f8e3d2 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.VM.Rule.ps1 +++ b/src/PSRule.Rules.Azure/rules/Azure.VM.Rule.ps1 @@ -44,7 +44,7 @@ Rule 'Azure.VM.DiskCaching' -Ref 'AZR-000242' -Type 'Microsoft.Compute/virtualMa } # Synopsis: Use Hybrid Use Benefit -Rule 'Azure.VM.UseHybridUseBenefit' -Ref 'AZR-000243' -If { SupportsHybridUse } -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Cost Optimization'; } { +Rule 'Azure.VM.UseHybridUseBenefit' -Ref 'AZR-000243' -If { (SupportsHybridUse) -and $Configuration.GetBoolOrDefault('AZURE_VM_USE_AZURE_HYBRID_BENEFIT', $False) } -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Cost Optimization'; } { $Assert.HasFieldValue($TargetObject, 'properties.licenseType', 'Windows_Server'); } diff --git a/src/PSRule.Rules.Azure/rules/Config.Rule.yaml b/src/PSRule.Rules.Azure/rules/Config.Rule.yaml index 81a8500c876..4d69c5c9bda 100644 --- a/src/PSRule.Rules.Azure/rules/Config.Rule.yaml +++ b/src/PSRule.Rules.Azure/rules/Config.Rule.yaml @@ -52,6 +52,9 @@ spec: # Configure Container Apps external ingress. AZURE_CONTAINERAPPS_RESTRICT_INGRESS: false + # Check supported VMs use Azure Hybrid Benefit. + AZURE_VM_USE_AZURE_HYBRID_BENEFIT: false + # Configure DNS is within the identity subscription. AZURE_VNET_DNS_WITH_IDENTITY: false diff --git a/tests/PSRule.Rules.Azure.Tests/Azure.VM.Tests.ps1 b/tests/PSRule.Rules.Azure.Tests/Azure.VM.Tests.ps1 index 59ab5f32d92..19a3fe0ca42 100644 --- a/tests/PSRule.Rules.Azure.Tests/Azure.VM.Tests.ps1 +++ b/tests/PSRule.Rules.Azure.Tests/Azure.VM.Tests.ps1 @@ -908,7 +908,14 @@ Describe 'Azure.VM' -Tag 'VM' { $parameterPath = Join-Path -Path $here -ChildPath 'Resources.VirtualMachine.Parameters.json'; $outputFile = Join-Path -Path $rootPath -ChildPath out/tests/Resources.VirtualMachineTemplate.json; Export-AzRuleTemplateData -TemplateFile $templatePath -ParameterFile $parameterPath -OutputPath $outputFile; - $result = Invoke-PSRule -Module PSRule.Rules.Azure -InputPath $outputFile -Outcome All -WarningAction Ignore -ErrorAction Stop; + $invokeParams = @{ + InputPath = $outputFile + Module = 'PSRule.Rules.Azure' + WarningAction = 'Ignore' + ErrorAction = 'Stop' + Option = (Join-Path -Path $here -ChildPath 'ps-rule-options.yaml') + } + $result = Invoke-PSRule @invokeParams -Outcome All; } It 'Azure.VM.UseManagedDisks' { diff --git a/tests/PSRule.Rules.Azure.Tests/ps-rule-options.yaml b/tests/PSRule.Rules.Azure.Tests/ps-rule-options.yaml index f731cbbf850..03e6fd1d173 100644 --- a/tests/PSRule.Rules.Azure.Tests/ps-rule-options.yaml +++ b/tests/PSRule.Rules.Azure.Tests/ps-rule-options.yaml @@ -104,3 +104,4 @@ configuration: - 'anOfferName' AZURE_COSMOS_DEFENDER_PER_ACCOUNT: true AZURE_STORAGE_DEFENDER_PER_ACCOUNT: true + AZURE_VM_USE_AZURE_HYBRID_BENEFIT: true