Skip to content

Commit

Permalink
feat(new): Added Azure.SQLMI.MaintenanceWindow (Azure#2980)
Browse files Browse the repository at this point in the history
* feat(new): Added Azure.SQLMI.MaintenanceWindow

* Fix link

---------

Co-authored-by: Bernie White <[email protected]>
  • Loading branch information
BenjaminEngeset and BernieWhite authored Jul 9, 2024
1 parent fdefbf6 commit 478c527
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 4 deletions.
3 changes: 3 additions & 0 deletions docs/CHANGELOG-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers
- 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)

## v1.38.0

Expand Down
99 changes: 99 additions & 0 deletions docs/en/rules/Azure.SQLMI.MaintenanceWindow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
severity: Important
pillar: Reliability
category: RE:04 Target metrics
resource: SQL Managed Instance
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.SQLMI.MaintenanceWindow/
---

# Customer-controlled maintenance window configuration

## SYNOPSIS

Configure a customer-controlled maintenance window for Azure SQL Managed Instances.

## DESCRIPTION

Azure SQL Managed Instances undergo periodic maintenance to ensure your managed databases remains secure, stable, and up-to-date.
This maintenance includes applying security updates, system upgrades, and software patches.

Maintenance windows can be scheduled in two ways for each instance:

- System-Managed Schedule: The system automatically selects a 9-hour maintenance window between 8:00 AM to 5:00 PM local time, Monday - Sunday.
- Urgent updates may occur outside of it. To ensure all updates occur only during the maintenance window, select a non-default option.
- Custom Schedule: You can specify a preferred 8-hour maintenance window by choosing between two non-default maintenance windows:
- Weekday window: 10:00 PM to 6:00 AM local time, Monday - Thursday.
- Weekend window: 10:00 PM to 6:00 AM local time, Friday - Sunday.

By configuring a customer-controlled maintenance window, you can schedule updates to occur during a preferred time, ideally outside business hours, minimizing disruptions.

There are limitations to the non-default maintenance windows. You can find more details about this in the documentation.

## RECOMMENDATION

Consider using a customer-controlled maintenance window to efficiently schedule updates and minimize disruptions.

## EXAMPLES

### Configure with Azure template

To configure managed instances that pass this rule:

- Set the `properties.maintenanceConfigurationId` property to `/subscriptions/<subscriptionId>/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_<RegionPlaceholder>_MI_1` or `SQL_<RegionPlaceholder>_MI_2`.

For example:

```json
{
"type": "Microsoft.Sql/managedInstances",
"apiVersion": "2023-05-01-preview",
"name": "[parameters('sqlManagedInstanceName'))]",
"location": "westeurope",
"sku": {
"name": "GP_Gen5",
},
"properties": {
"maintenanceConfigurationId": "[subscriptionResourceId('Microsoft.Maintenance/publicMaintenanceConfigurations', 'SQL_WestEurope_MI_1')]"
}
}
```

### Configure with Bicep

To configure managed instances that pass this rule:

- Set the `properties.maintenanceConfigurationId` property to `/subscriptions/<subscriptionId>/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_<RegionPlaceholder>_MI_1` or `SQL_<RegionPlaceholder>_MI_2`.

For example:

```bicep
resource maintenanceWindow 'Microsoft.Maintenance/publicMaintenanceConfigurations@2023-04-01' existing = {
scope: subscription()
name: 'SQL_WestEurope_MI_1'
}
resource sqlManagedInstance 'Microsoft.Sql/managedInstances@2023-05-01-preview' = {
name: sqlManagedInstanceName
location: 'westeurope'
sku: {
name: 'GP_Gen5'
}
properties: {
maintenanceConfigurationId: maintenanceWindow.id
}
}
```

## NOTES

For managed instances within an instance pool, the maintenance configuration set at the instance pool level is inherited by all instances within that pool.
However, instance pools do not support customer-controlled maintenance windows directly.
To specify maintenance windows, you must configure them at the individual instance level, thereby overriding the inherited instance pool configuration.

## LINKS

- [RE:04 Target metrics](https://learn.microsoft.com/azure/well-architected/reliability/metrics)
- [Maintenance window in Azure SQL Managed Instance](https://learn.microsoft.com/azure/azure-sql/managed-instance/maintenance-window)
- [Configure maintenance window](https://learn.microsoft.com/azure/azure-sql/managed-instance/maintenance-window-configure)
- [Azure deployment reference - Maintenance Configuration](https://learn.microsoft.com/azure/templates/microsoft.maintenance/publicmaintenanceconfigurations)
- [Azure deployment reference - Azure SQL Managed Instance](https://learn.microsoft.com/azure/templates/microsoft.sql/managedinstances)
1 change: 1 addition & 0 deletions src/PSRule.Rules.Azure/en/PSRule-rules.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,6 @@
ResStorageSensitiveDataThreatDetection = "The storage account '{0}' should have sensitive data threat detection in Microsoft Defender for Storage configured."
ResAPIDefender = "The API '{0}' should be onboarded to Microsoft Defender for APIs."
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."
}
9 changes: 9 additions & 0 deletions src/PSRule.Rules.Azure/rules/Azure.SQLMI.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,13 @@ Rule 'Azure.SQLMI.AAD' -Ref 'AZR-000368' -Type 'Microsoft.Sql/managedInstances',
}
}

# Synopsis: Configure a customer-controlled maintenance window for Azure SQL managed instances.
Rule 'Azure.SQLMI.MaintenanceWindow' -Ref 'AZR-000441' -Type 'Microsoft.Sql/managedInstances' -Tag @{ release = 'GA'; ruleSet = '2024_09'; 'Azure.WAF/pillar' = 'Reliability'; } {
$Assert.Match($TargetObject, 'properties.maintenanceConfigurationId', '\/publicMaintenanceConfigurations\/SQL_[A-Za-z]+[A-Za-z0-9]*_MI_[12]$', $False).
Reason(
$LocalizedData.AzureSQLMIMaintenanceWindow,
$TargetObject.Name
)
}

#endregion SQL Managed Instance
19 changes: 18 additions & 1 deletion tests/PSRule.Rules.Azure.Tests/Azure.SQLMI.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,23 @@ Describe 'Azure.SQLMI' -Tag 'SQLMI' {
$ruleResult.Length | Should -Be 3;
$ruleResult.TargetName | Should -BeIn 'server-B', 'server-D', 'ActiveDirectoryAdmin-B';
}

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

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'server-A', 'server-B';

$ruleResult[0].Reason | Should -BeExactly "The managed instance (server-A) should have a customer-controlled maintenance window configured.";
$ruleResult[1].Reason | Should -BeExactly "The managed instance (server-B) should have a customer-controlled maintenance window configured.";

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'server-C', 'server-D';
}
}

Context 'Resource name - Azure.SQLMI.Name' {
Expand Down Expand Up @@ -139,4 +156,4 @@ Describe 'Azure.SQLMI' -Tag 'SQLMI' {
$ruleResult.Outcome | Should -Be 'Fail';
}
}
}
}
9 changes: 6 additions & 3 deletions tests/PSRule.Rules.Azure.Tests/Resources.SQLMI.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
"primaryUserAssignedIdentityId": null,
"publicNetworkAccess": null,
"restrictOutboundNetworkAccess": null,
"version": null
"version": null,
"maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_Default"
}
},
{
Expand All @@ -85,7 +86,8 @@
"primaryUserAssignedIdentityId": null,
"publicNetworkAccess": null,
"restrictOutboundNetworkAccess": null,
"version": null
"version": null,
"maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_WestEurope_MI_1"
},
"resources": [
{
Expand Down Expand Up @@ -138,7 +140,8 @@
"primaryUserAssignedIdentityId": null,
"publicNetworkAccess": null,
"restrictOutboundNetworkAccess": null,
"version": null
"version": null,
"maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_EastUS_MI_2"
},
"resources": [
{
Expand Down

0 comments on commit 478c527

Please sign in to comment.