feat(new): Added Azure.ASE.AvailabilityZone (#2985)
* feat(new): Added Azure.ASE.AvailabilityZone * fix: Changelog * fix: Changelog * Update change log * Update src/PSRule.Rules.Azure/en/PSRule-rules.psd1 Co-authored-by: Bernie White <bewhite@microsoft.com> * Update src/PSRule.Rules.Azure/rules/Azure.ASE.Rule.ps1 Co-authored-by: Bernie White <bewhite@microsoft.com> * fix: Fixed test --------- Co-authored-by: Bernie White <bewhite@microsoft.com>
This commit is contained in:
Родитель
b8078d7e7c
Коммит
28aa13cabf
|
@ -29,16 +29,21 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers
|
|||
|
||||
## Unreleased
|
||||
|
||||
What's changed since v1.38.0:
|
||||
|
||||
- New rules:
|
||||
- App Service:
|
||||
- Verify that app service plans have availability zones configured by @BenjaminEngeset.
|
||||
[#2964](https://github.com/Azure/PSRule.Rules.Azure/issues/2964)
|
||||
- App Service Environment:
|
||||
- Verify that app service environments have availability zones configured by @BenjaminEngeset.
|
||||
[#2964](https://github.com/Azure/PSRule.Rules.Azure/issues/2964)
|
||||
- Azure SQL Database:
|
||||
- Verify that Azure SQL databases have a customer-controlled maintenance window configured by @BenjaminEngeset.
|
||||
[#2956](https://github.com/Azure/PSRule.Rules.Azure/issues/2956)
|
||||
- Azure SQL Managed Instance:
|
||||
- Verify that Azure SQL Managed Instances have a customer-controlled maintenance window configured by @BenjaminEngeset.
|
||||
[#2979](https://github.com/Azure/PSRule.Rules.Azure/issues/2979)
|
||||
- App Service:
|
||||
- Verify that app service plans have availability zones configured by @BenjaminEngeset.
|
||||
[#2964](https://github.com/Azure/PSRule.Rules.Azure/issues/2964)
|
||||
|
||||
## v1.38.0
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
severity: Important
|
||||
pillar: Reliability
|
||||
category: RE:05 Regions and availability zones
|
||||
resource: App Service Environment
|
||||
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.ASE.AvailabilityZone/
|
||||
---
|
||||
|
||||
# Deploy app service environments using availability zones
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
Deploy app service environments using availability zones in supported regions to ensure high availability and resilience.
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
App Service Environments support zone redundancy, which distributes your application running within the environment across Availablity Zones.
|
||||
Each Availability Zone is a group of phyiscally separated data centers.
|
||||
Deploying your application with zone redundancy:
|
||||
|
||||
- Scales your plan within the environment to a minimum of 3 instances in a highly available configuration.
|
||||
Additional instances can be added manually or on-demand by using autoscale.
|
||||
- Improves the resiliency against service disruptions or issues affecting a single zone.
|
||||
|
||||
Additionally:
|
||||
|
||||
- **Even Distribution**: If the instance count is larger than 3 and divisible by 3, instances are evenly distributed across the three zones.
|
||||
- **Partial Distribution**: Instance counts beyond 3*N are spread across the remaining one or two zones to ensure balanced distribution.
|
||||
|
||||
**Important** Configuring zone redundancy with per-application scaling is possible but may increase costs and administrative overhead.
|
||||
When `perSiteScaling` is enabled, each application can have its own scaling rules and run on dedicated instances.
|
||||
To maintain zone redundancy, it is crucial that each application’s scaling rules ensure a minimum of 3 instances.
|
||||
Without explicitly configuring this minimum, the application may not meet the zone redundancy requirement.
|
||||
|
||||
## RECOMMENDATION
|
||||
|
||||
Consider using enabling zone redundancy using availability zones to improve the resiliency of your solution.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Configure with Azure template
|
||||
|
||||
To configure a zone-redundant app service environment:
|
||||
|
||||
- Set the `properties.zoneRedundant` property to `true`.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "Microsoft.Web/hostingEnvironments",
|
||||
"apiVersion": "2022-09-01",
|
||||
"name": "[parameters('name')]",
|
||||
"location": "[parameters('location')]",
|
||||
"kind": "ASEV3",
|
||||
"properties": {
|
||||
"zoneRedundant": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configure with Bicep
|
||||
|
||||
To configure a zone-redundant app service environment:
|
||||
|
||||
- Set the `properties.zoneRedundant` property to `true`.
|
||||
|
||||
For example:
|
||||
|
||||
```bicep
|
||||
resource ase 'Microsoft.Web/hostingEnvironments@2022-09-01' = {
|
||||
name: name
|
||||
location: location
|
||||
kind 'ASEV3'
|
||||
properties: {
|
||||
zoneRedundant: true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## NOTES
|
||||
|
||||
Zone-redundancy is only supported for the `ASEV3` version.
|
||||
|
||||
Zone-redundancy is not supported for environments deployed on a dedicated host group.
|
||||
|
||||
## LINKS
|
||||
|
||||
- [RE:05 Regions and availability zones](https://learn.microsoft.com/azure/well-architected/reliability/regions-availability-zones)
|
||||
- [Reliability in Azure App Service](https://learn.microsoft.com/azure/reliability/reliability-app-service)
|
||||
- [Availability zone support](https://learn.microsoft.com/azure/reliability/reliability-app-service#availability-zone-support)
|
||||
- [About App Service Environment](https://learn.microsoft.com/azure/app-service/environment/overview)
|
||||
- [Azure resource deployment](https://learn.microsoft.com/azure/templates/microsoft.web/hostingenvironments)
|
|
@ -112,6 +112,7 @@
|
|||
InsecureParameterType = "The parameter '{0}' with type '{1}' is not secure."
|
||||
AzureSQLMIMaintenanceWindow = "The managed instance ({0}) should have a customer-controlled maintenance window configured."
|
||||
AzureSQLDatabaseMaintenanceWindow = "The {0} ({1}) should have a customer-controlled maintenance window configured."
|
||||
ASEAvailabilityZoneVersion = "The app service environment ({0}) is not deployed with a version that supports zone-redundancy."
|
||||
AppServiceAvailabilityZoneSKU = "The app service plan ({0}) is not deployed with a SKU that supports zone-redundancy."
|
||||
AppServiceAvailabilityZone = "The app service plan ({0}) deployed to region ({1}) should use three availability zones from the following [{2}]."
|
||||
}
|
||||
|
|
|
@ -5,7 +5,36 @@
|
|||
# Validation rules for Azure App Service Environment
|
||||
#
|
||||
|
||||
#region Rules
|
||||
|
||||
# Synopsis: Use ASEv3 as replacement for the classic app service environment versions ASEv1 and ASEv2.
|
||||
Rule 'Azure.ASE.MigrateV3' -Ref 'AZR-000319' -Type 'Microsoft.Web/hostingEnvironments' -Tag @{ release = 'GA'; ruleSet = '2022_12'; 'Azure.WAF/pillar' = 'Operational Excellence'; } {
|
||||
$Assert.HasFieldValue($TargetObject, 'kind', 'ASEV3').Reason($LocalizedData.ClassicASEDeprecated, $PSRule.TargetName, $TargetObject.kind)
|
||||
}
|
||||
|
||||
# Synopsis: Deploy app service environments using availability zones in supported regions to ensure high availability and resilience.
|
||||
Rule 'Azure.ASE.AvailabilityZone' -Ref 'AZR-000443' -Type 'Microsoft.Web/hostingEnvironments' -Tag @{ release = 'GA'; ruleSet = '2024_09 '; 'Azure.WAF/pillar' = 'Reliability'; } {
|
||||
# Dedicated host group does not support zone-redundancy.
|
||||
if ($TargetObject.properties.dedicatedHostCount) {
|
||||
return $Assert.Pass()
|
||||
}
|
||||
|
||||
# Check if the region supports availability zones.
|
||||
$provider = [PSRule.Rules.Azure.Runtime.Helper]::GetResourceType('Microsoft.Web', 'hostingEnvironments')
|
||||
$availabilityZones = GetAvailabilityZone -Location $TargetObject.Location -Zone $provider.ZoneMappings
|
||||
|
||||
# Don't flag if the region does not support availability zones.
|
||||
if (-not $availabilityZones) {
|
||||
return $Assert.Pass()
|
||||
}
|
||||
|
||||
# Availability zones are only supported for the ASEv3 version (modern footprint).
|
||||
$Assert.HasFieldValue($TargetObject, 'kind', 'ASEV3').Reason(
|
||||
$LocalizedData.ASEAvailabilityZoneVersion,
|
||||
$TargetObject.name
|
||||
)
|
||||
|
||||
$Assert.HasFieldValue($TargetObject, 'properties.zoneRedundant', $true)
|
||||
}
|
||||
|
||||
#endregion Rules
|
||||
|
|
|
@ -51,8 +51,32 @@ Describe 'Azure.ASE' -Tag 'ASE' {
|
|||
# Pass
|
||||
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
|
||||
$ruleResult | Should -Not -BeNullOrEmpty;
|
||||
$ruleResult.Length | Should -Be 1;
|
||||
$ruleResult.TargetName | Should -BeIn 'environment-C';
|
||||
$ruleResult.Length | Should -Be 3;
|
||||
$ruleResult.TargetName | Should -BeIn 'environment-C', 'environment-E', 'environment-F';
|
||||
}
|
||||
|
||||
It 'Azure.ASE.AvailabilityZone' {
|
||||
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.ASE.AvailabilityZone' };
|
||||
|
||||
# Fail
|
||||
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
|
||||
$ruleResult.Length | Should -Be 3;
|
||||
$ruleResult.TargetName | Should -BeIn 'environment-A', 'environment-B', 'environment-D';
|
||||
|
||||
$ruleResult[0].Reason | Should -BeExactly @(
|
||||
"The app service environment (environment-A) is not deployed with a version that supports zone-redundancy."
|
||||
"Path properties.zoneRedundant: Does not exist."
|
||||
):
|
||||
$ruleResult[1].Reason | Should -BeExactly @(
|
||||
"The app service environment (environment-B) is not deployed with a version that supports zone-redundancy."
|
||||
"Path properties.zoneRedundant: Is set to 'False'."
|
||||
):
|
||||
$ruleResult[2].Reason | Should -BeExactly "The app service environment (environment-D) is not deployed with a version that supports zone-redundancy.";
|
||||
|
||||
# Pass
|
||||
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
|
||||
$ruleResult.Length | Should -Be 3;
|
||||
$ruleResult.TargetName | Should -Be 'environment-C', 'environment-E', 'environment-F';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
"virtualNetwork": {
|
||||
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/vnet-A",
|
||||
"subnet": "subnet-A"
|
||||
},
|
||||
"zoneRedundant": true
|
||||
}
|
||||
},
|
||||
"ResourceGroupName": "rg-test",
|
||||
"Type": "microsoft.web/hostingenvironments",
|
||||
|
@ -52,7 +51,7 @@
|
|||
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Web/hostingEnvironments/environment-B/serverfarms/plan-A",
|
||||
"Identity": null,
|
||||
"Kind": null,
|
||||
"Location": "region",
|
||||
"Location": "westeurope",
|
||||
"ManagedBy": null,
|
||||
"ResourceName": "plan-A",
|
||||
"Name": "plan-A",
|
||||
|
@ -88,7 +87,7 @@
|
|||
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Web/hostingEnvironments/environment-C",
|
||||
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Web/hostingEnvironments/environment-C",
|
||||
"Identity": null,
|
||||
"Location": "westeurope",
|
||||
"Location": "notregion",
|
||||
"ManagedBy": null,
|
||||
"ResourceName": "environment-C",
|
||||
"Name": "environment-C",
|
||||
|
@ -167,5 +166,54 @@
|
|||
"Sku": null,
|
||||
"Tags": null,
|
||||
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
{
|
||||
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Web/hostingEnvironments/environment-E",
|
||||
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Web/hostingEnvironments/environment-E",
|
||||
"Identity": null,
|
||||
"Location": "westeurope",
|
||||
"ManagedBy": null,
|
||||
"ResourceName": "environment-E",
|
||||
"Name": "environment-E",
|
||||
"Kind": "ASEV3",
|
||||
"Properties": {
|
||||
"upgradePreference": "Early",
|
||||
"virtualNetwork": {
|
||||
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/vnet-A",
|
||||
"subnet": "subnet-A"
|
||||
},
|
||||
"zoneRedundant": true
|
||||
},
|
||||
"ResourceGroupName": "rg-test",
|
||||
"Type": "microsoft.web/hostingenvironments",
|
||||
"ResourceType": "microsoft.web/hostingenvironments",
|
||||
"Sku": null,
|
||||
"Tags": null,
|
||||
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
{
|
||||
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Web/hostingEnvironments/environment-F",
|
||||
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Web/hostingEnvironments/environment-F",
|
||||
"Identity": null,
|
||||
"Location": "westeurope",
|
||||
"ManagedBy": null,
|
||||
"ResourceName": "environment-F",
|
||||
"Name": "environment-E",
|
||||
"Kind": "ASEV3",
|
||||
"Properties": {
|
||||
"upgradePreference": "Early",
|
||||
"virtualNetwork": {
|
||||
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/vnet-A",
|
||||
"subnet": "subnet-A"
|
||||
},
|
||||
"dedicatedHostCount": 2,
|
||||
"zoneRedundant": false
|
||||
},
|
||||
"ResourceGroupName": "rg-test",
|
||||
"Type": "microsoft.web/hostingenvironments",
|
||||
"ResourceType": "microsoft.web/hostingenvironments",
|
||||
"Sku": null,
|
||||
"Tags": null,
|
||||
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
|
||||
}
|
||||
]
|
||||
|
|
Загрузка…
Ссылка в новой задаче