Skip to content

Commit 0578f32

Browse files
feat(new): Added Azure.VNG.MaintenanceConfig (Azure#2920)
* feat(new): Added Azure.VNG.MaintenanceConfig * Fix release casing * Fix test --------- Co-authored-by: Bernie White <[email protected]>
1 parent 8d4957c commit 0578f32

File tree

6 files changed

+226
-9
lines changed

6 files changed

+226
-9
lines changed

docs/CHANGELOG-v1.md

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ What's changed since pre-release v1.37.0:
3535
- Azure Firewall:
3636
- Verify that firewalls have availability zones configured by @BenjaminEngeset.
3737
[#2909](https://github.com/Azure/PSRule.Rules.Azure/issues/2909)
38+
- Virtual Network Gateway:
39+
- Verify that VPN/ExpressRoute gateways have a customer-controlled maintenance configuration configured by @BenjaminEngeset.
40+
[#2910](https://github.com/Azure/PSRule.Rules.Azure/issues/2910)
3841

3942
## v1.37.0
4043

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
severity: Important
3+
pillar: Reliability
4+
category: RE:04 Target metrics
5+
resource: Virtual Network Gateway
6+
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.VNG.MaintenanceConfig/
7+
---
8+
9+
# Associate a customer-controlled maintenance configuration
10+
11+
## SYNOPSIS
12+
13+
Use a customer-controlled maintenance configuration for virtual network gateways.
14+
15+
## DESCRIPTION
16+
17+
Virtual network gateways require regular updates to maintain and enhance their functionality, reliability, performance, and security. These updates include patching software, upgrading networking components, and decommissioning outdated hardware.
18+
19+
By attaching virtual network gateways to a maintenance configuration, customers can schedule these updates to occur during a preferred maintenance window, ideally outside of business hours, to minimize disruptions.
20+
21+
Both the VPN and ExpressRoute virtual network gateway types support customer-controlled maintenance configurations.
22+
23+
## RECOMMENDATION
24+
25+
Consider using a customer-controlled maintenance configuration to efficiently schedule updates and minimize disruptions.
26+
27+
## EXAMPLES
28+
29+
### Configure with Azure template
30+
31+
To configure virtual network gateways that pass this rule:
32+
33+
- Deploy a `Microsoft.Maintenance/configurationAssignments` sub-resource (extension resource).
34+
- Set the `properties.maintenanceConfigurationId` property to the linked maintenance configuration resource Id.
35+
36+
For example:
37+
38+
```json
39+
{
40+
"type": "Microsoft.Maintenance/configurationAssignments",
41+
"apiVersion": "2023-04-01",
42+
"name": "[parameters('assignmentName')]",
43+
"location": "[parameters('location')]",
44+
"scope": "[format('Microsoft.Network/virtualNetworkGateways/{0}', parameters('name'))]",
45+
"properties": {
46+
"maintenanceConfigurationId": "[parameters('maintenanceConfigurationId')]"
47+
},
48+
"dependsOn": [
49+
"[resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name'))]"
50+
]
51+
}
52+
```
53+
54+
### Configure with Bicep
55+
56+
To configure virtual network gateways that pass this rule:
57+
58+
- Deploy a `Microsoft.Maintenance/configurationAssignments` sub-resource (extension resource).
59+
- Set the `properties.maintenanceConfigurationId` property to the linked maintenance configuration resource Id.
60+
61+
For example:
62+
63+
```bicep
64+
resource config 'Microsoft.Maintenance/configurationAssignments@2023-04-01' = {
65+
name: assignmentName
66+
location: location
67+
scope: virtualNetworkGateway
68+
properties: {
69+
maintenanceConfigurationId: maintenanceConfigurationId
70+
}
71+
}
72+
```
73+
74+
## NOTES
75+
76+
This feature is currently in preview for both the VPN and ExpressRoute virtual network gateway types.
77+
78+
## LINKS
79+
80+
- [RE:04 Target metrics](https://learn.microsoft.com/azure/well-architected/reliability/metrics)
81+
- [Configure customer-controlled gateway maintenance for VPN Gateway](https://learn.microsoft.com/azure/vpn-gateway/customer-controlled-gateway-maintenance)
82+
- [Configure customer-controlled gateway maintenance for ExpressRoute](https://learn.microsoft.com/azure/expressroute/customer-controlled-gateway-maintenance)
83+
- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.maintenance/configurationassignments)

src/PSRule.Rules.Azure/en/PSRule-rules.psd1

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
ArcKubernetesDefender = "The Arc-enabled Kubernetes cluster '{0}' should have a Microsoft Defender for Containers extension configured."
103103
VMMaintenanceConfig = "The virtual machine '{0}' should have a maintenance configuration associated."
104104
ArcServerMaintenanceConfig = "The Arc-enabled server '{0}' should have a maintenance configuration associated."
105+
VNGMaintenanceConfig = "The virtual network gateway '{0}' should have a customer-controlled maintenance configuration associated."
105106
SubStorageMalwareScanning = "The Microsoft Defender for Storage plan should have malware scanning configured."
106107
ResStorageMalwareScanning = "The storage account '{0}' should have malware scanning in Microsoft Defender for Storage configured."
107108
SubStorageSensitiveDataThreatDetection = "The Microsoft Defender for Storage plan should have sensitive data threat detection configured."

src/PSRule.Rules.Azure/rules/Azure.VNG.Rule.ps1

+9-2
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,21 @@ Rule 'Azure.VNG.ERLegacySKU' -Ref 'AZR-000271' -Type 'Microsoft.Network/virtualN
1616
Rule 'Azure.VNG.VPNAvailabilityZoneSKU' -Ref 'AZR-000272' -Type 'Microsoft.Network/virtualNetworkGateways' -With 'Azure.VNG.VPNGateway' -Tag @{ release = 'GA'; ruleSet = '2021_12'; 'Azure.WAF/pillar' = 'Reliability'; } {
1717
$vpnAvailabilityZoneSKUs = @('VpnGw1AZ', 'VpnGw2AZ', 'VpnGw3AZ', 'VpnGw4AZ', 'VpnGw5AZ');
1818
$Assert.In($TargetObject, 'Properties.sku.name', $vpnAvailabilityZoneSKUs).
19-
Reason($LocalizedData.VPNAvailabilityZoneSKU, $TargetObject.Name, ($vpnAvailabilityZoneSKUs -join ', '));
19+
Reason($LocalizedData.VPNAvailabilityZoneSKU, $TargetObject.Name, ($vpnAvailabilityZoneSKUs -join ', '));
2020
}
2121

2222
# Synopsis: Use availability zone SKU for virtual network gateways deployed with ExpressRoute gateway type
2323
Rule 'Azure.VNG.ERAvailabilityZoneSKU' -Ref 'AZR-000273' -Type 'Microsoft.Network/virtualNetworkGateways' -With 'Azure.VNG.ERGateway' -Tag @{ release = 'GA'; ruleSet = '2021_12'; 'Azure.WAF/pillar' = 'Reliability'; } {
2424
$erAvailabilityZoneSKUs = @('ErGw1AZ', 'ErGw2AZ', 'ErGw3AZ');
2525
$Assert.In($TargetObject, 'Properties.sku.name', $erAvailabilityZoneSKUs).
26-
Reason($LocalizedData.ERAvailabilityZoneSKU, $TargetObject.Name, ($erAvailabilityZoneSKUs -join ', '));
26+
Reason($LocalizedData.ERAvailabilityZoneSKU, $TargetObject.Name, ($erAvailabilityZoneSKUs -join ', '));
27+
}
28+
29+
# Synopsis: Use a customer-controlled maintenance configuration for virtual network gateways.
30+
Rule 'Azure.VNG.MaintenanceConfig' -Ref 'AZR-000430' -Type 'Microsoft.Network/virtualNetworkGateways' -Tag @{ release = 'preview'; ruleSet = '2024_06'; 'Azure.WAF/pillar' = 'Reliability'; } {
31+
$maintenanceConfig = @(GetSubResources -ResourceType 'Microsoft.Maintenance/configurationAssignments' |
32+
Where-Object { $_.properties.maintenanceConfigurationId })
33+
$Assert.GreaterOrEqual($maintenanceConfig, '.', 1).Reason($LocalizedData.VNGMaintenanceConfig, $PSRule.TargetName)
2734
}
2835

2936
#endregion Rules

tests/PSRule.Rules.Azure.Tests/Azure.VNG.Tests.ps1

+18
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,24 @@ Describe 'Azure.VNG' -Tag 'Network', 'VNG', 'VPN', 'ExpressRoute' {
125125
$ruleResult.Length | Should -Be 2;
126126
$ruleResult.TargetName | Should -BeIn 'gateway-G', 'gateway-H';
127127
}
128+
129+
It 'Azure.VNG.MaintenanceConfig' {
130+
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.VNG.MaintenanceConfig' };
131+
132+
# Fail
133+
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
134+
$ruleResult.Length | Should -Be 3;
135+
$ruleResult.TargetName | Should -BeIn 'gateway-A', 'gateway-B', 'gateway-C';
136+
137+
$ruleResult[0].Reason | Should -BeExactly "The virtual network gateway 'gateway-A' should have a customer-controlled maintenance configuration associated.";
138+
$ruleResult[1].Reason | Should -BeExactly "The virtual network gateway 'gateway-B' should have a customer-controlled maintenance configuration associated.";
139+
$ruleResult[2].Reason | Should -BeExactly "The virtual network gateway 'gateway-C' should have a customer-controlled maintenance configuration associated.";
140+
141+
# Pass
142+
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
143+
$ruleResult.Length | Should -Be 5;
144+
$ruleResult.TargetName | Should -BeIn 'gateway-D', 'gateway-E', 'gateway-F', 'gateway-G', 'gateway-H';
145+
}
128146
}
129147

130148
Context 'Resource name - Azure.VNG.Name' {

tests/PSRule.Rules.Azure.Tests/Resources.VirtualNetwork.json

+112-7
Original file line numberDiff line numberDiff line change
@@ -2490,7 +2490,22 @@
24902490
"ExtensionResourceType": null,
24912491
"Sku": null,
24922492
"Tags": null,
2493-
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2493+
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
2494+
"resources": [
2495+
{
2496+
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providersMicrosoft.Network/virtualNetworkGateways/gateway-B/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2497+
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-B/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2498+
"ResourceName": "configurationassignment-a",
2499+
"Name": "configurationassignment-a",
2500+
"Properties": {
2501+
"maintenanceConfigurationId": null
2502+
},
2503+
"ResourceGroupName": "test-rg",
2504+
"Type": " Microsoft.Maintenance/configurationAssignments",
2505+
"ResourceType": "Microsoft.Maintenance/configurationAssignments",
2506+
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2507+
}
2508+
]
24942509
},
24952510
{
24962511
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-C",
@@ -2547,7 +2562,22 @@
25472562
"ExtensionResourceType": null,
25482563
"Sku": null,
25492564
"Tags": null,
2550-
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2565+
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
2566+
"resources": [
2567+
{
2568+
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providersMicrosoft.Network/virtualNetworkGateways/gateway-C/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2569+
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-C/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2570+
"ResourceName": "configurationassignment-a",
2571+
"Name": "configurationassignment-a",
2572+
"Properties": {
2573+
"maintenanceConfigurationId": null
2574+
},
2575+
"ResourceGroupName": "test-rg",
2576+
"Type": " Microsoft.Maintenance/configurationAssignments",
2577+
"ResourceType": "Microsoft.Maintenance/configurationAssignments",
2578+
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2579+
}
2580+
]
25512581
},
25522582
{
25532583
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-D",
@@ -2600,7 +2630,22 @@
26002630
"ExtensionResourceType": null,
26012631
"Sku": null,
26022632
"Tags": null,
2603-
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2633+
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
2634+
"resources": [
2635+
{
2636+
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providersMicrosoft.Network/virtualNetworkGateways/gateway-D/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2637+
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-D/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2638+
"ResourceName": "configurationassignment-a",
2639+
"Name": "configurationassignment-a",
2640+
"Properties": {
2641+
"maintenanceConfigurationId": "00000000-0000-0000-0000-000000000000"
2642+
},
2643+
"ResourceGroupName": "test-rg",
2644+
"Type": " Microsoft.Maintenance/configurationAssignments",
2645+
"ResourceType": "Microsoft.Maintenance/configurationAssignments",
2646+
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2647+
}
2648+
]
26042649
},
26052650
{
26062651
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-E",
@@ -2653,7 +2698,22 @@
26532698
"ExtensionResourceType": null,
26542699
"Sku": null,
26552700
"Tags": null,
2656-
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2701+
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
2702+
"resources": [
2703+
{
2704+
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providersMicrosoft.Network/virtualNetworkGateways/gateway-E/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2705+
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-E/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2706+
"ResourceName": "configurationassignment-a",
2707+
"Name": "configurationassignment-a",
2708+
"Properties": {
2709+
"maintenanceConfigurationId": "00000000-0000-0000-0000-000000000000"
2710+
},
2711+
"ResourceGroupName": "test-rg",
2712+
"Type": " Microsoft.Maintenance/configurationAssignments",
2713+
"ResourceType": "Microsoft.Maintenance/configurationAssignments",
2714+
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2715+
}
2716+
]
26572717
},
26582718
{
26592719
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-F",
@@ -2706,7 +2766,22 @@
27062766
"ExtensionResourceType": null,
27072767
"Sku": null,
27082768
"Tags": null,
2709-
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2769+
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
2770+
"resources": [
2771+
{
2772+
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providersMicrosoft.Network/virtualNetworkGateways/gateway-F/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2773+
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-F/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2774+
"ResourceName": "configurationassignment-a",
2775+
"Name": "configurationassignment-a",
2776+
"Properties": {
2777+
"maintenanceConfigurationId": "00000000-0000-0000-0000-000000000000"
2778+
},
2779+
"ResourceGroupName": "test-rg",
2780+
"Type": " Microsoft.Maintenance/configurationAssignments",
2781+
"ResourceType": "Microsoft.Maintenance/configurationAssignments",
2782+
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2783+
}
2784+
]
27102785
},
27112786
{
27122787
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-G",
@@ -2763,7 +2838,22 @@
27632838
"ExtensionResourceType": null,
27642839
"Sku": null,
27652840
"Tags": null,
2766-
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2841+
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
2842+
"resources": [
2843+
{
2844+
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providersMicrosoft.Network/virtualNetworkGateways/gateway-G/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2845+
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-G/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2846+
"ResourceName": "configurationassignment-a",
2847+
"Name": "configurationassignment-a",
2848+
"Properties": {
2849+
"maintenanceConfigurationId": "00000000-0000-0000-0000-000000000000"
2850+
},
2851+
"ResourceGroupName": "test-rg",
2852+
"Type": " Microsoft.Maintenance/configurationAssignments",
2853+
"ResourceType": "Microsoft.Maintenance/configurationAssignments",
2854+
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2855+
}
2856+
]
27672857
},
27682858
{
27692859
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-H",
@@ -2820,7 +2910,22 @@
28202910
"ExtensionResourceType": null,
28212911
"Sku": null,
28222912
"Tags": null,
2823-
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2913+
"SubscriptionId": "00000000-0000-0000-0000-000000000000",
2914+
"resources": [
2915+
{
2916+
"ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providersMicrosoft.Network/virtualNetworkGateways/gateway-H/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2917+
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworkGateways/gateway-H/providers/Microsoft.Maintenance/configurationAssignments/configurationassignment-a",
2918+
"ResourceName": "configurationassignment-a",
2919+
"Name": "configurationassignment-a",
2920+
"Properties": {
2921+
"maintenanceConfigurationId": "00000000-0000-0000-0000-000000000000"
2922+
},
2923+
"ResourceGroupName": "test-rg",
2924+
"Type": " Microsoft.Maintenance/configurationAssignments",
2925+
"ResourceType": "Microsoft.Maintenance/configurationAssignments",
2926+
"SubscriptionId": "00000000-0000-0000-0000-000000000000"
2927+
}
2928+
]
28242929
},
28252930
{
28262931
"type": "Microsoft.Network/networkSecurityGroups",

0 commit comments

Comments
 (0)