diff --git a/docs/CHANGELOG-v1.md b/docs/CHANGELOG-v1.md index 116789d9ec..094598350f 100644 --- a/docs/CHANGELOG-v1.md +++ b/docs/CHANGELOG-v1.md @@ -29,6 +29,11 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers ## Unreleased +- New rules: + - Cosmos DB: + - Verify that Cosmos DB accounts have continuous backup configured by @BenjaminEngeset. + [#2954](https://github.com/Azure/PSRule.Rules.Azure/issues/2954) + ## v1.38.0-B0068 (pre-release) What's changed since pre-release v1.38.0-B0034: diff --git a/docs/en/rules/Azure.Cosmos.ContinuousBackup.md b/docs/en/rules/Azure.Cosmos.ContinuousBackup.md new file mode 100644 index 0000000000..4db62f2201 --- /dev/null +++ b/docs/en/rules/Azure.Cosmos.ContinuousBackup.md @@ -0,0 +1,120 @@ +--- +severity: Important +pillar: Reliability +category: RE:06 Data partitioning +resource: Cosmos DB +online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.Cosmos.ContinuousBackup/ +--- + +# Enable continuous backup policy + +## SYNOPSIS + +Enable continuous backup on Cosmos DB accounts. + +## DESCRIPTION + +Continuous backup for Azure Cosmos DB captures changes in near real-time, ensuring that you always have the most up-to-date backup. +Data can be restored to any restorable timestamp within the retention period. + +Benefits of continuous backup include: + +- **Accidental Write or Delete Recovery**: Quickly recover from unintended changes within a container. +- **Comprehensive Restoration**: Restore deleted accounts, databases, or containers. +- **Regional Flexibility**: Restore data into any region where backups existed at the desired restore point. +- **Ease of Use**: Restore data directly through the Azure portal without needing support requests. + +These features typically improve your: + +- **Recovery Time Objective (RTO)**: How long it take to recover, and systems are back online. +- **Recovery Point Objective (RPO)**: The point in time you can recover to. + +Continuous backup involves additional costs, so it is recommended for mission-critical applications with frequent data changes. + +Check the documentation below for important information and limitations. + +## RECOMMENDATION + +Consider configuring Azure Cosmos DB with continuous backup mode for enhanced data protection (RTO & RPO) and easier recovery. + +## EXAMPLES + +### Configure with Azure template + +To configure continuous backup for Cosmos DB: + +- Set the `properties.backupPolicy.type` property to `Continuous`. +- Set the `properties.backupPolicy.continuousModeProperties.tier` property to a valid tier. + Valid tiers include `Continuous7Days` and `Continuous30Days`. + +For example: + +```json +{ + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2024-05-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "GlobalDocumentDB", + "properties": { + "disableLocalAuth": true, + "locations": [ + { + "locationName": "[parameters('location')]", + "failoverPriority": 0, + "isZoneRedundant": true + } + ], + "backupPolicy": { + "type": "Continuous", + "continuousModeProperties": { + "tier": "Continuous7Days" + } + } + } +} +``` + +### Configure with Bicep + +To configure continuous backup for Cosmos DB: + +- Set the `properties.backupPolicy.type` property to `Continuous`. +- Set the `properties.backupPolicy.continuousModeProperties.tier` property to a valid tier. + Valid tiers include `Continuous7Days` and `Continuous30Days`. + +For example: + +```bicep +resource account 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = { + name: name + location: location + kind: 'GlobalDocumentDB' + properties: { + disableLocalAuth: true + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: true + } + ] + backupPolicy: { + type: 'Continuous' + continuousModeProperties: { + tier: 'Continuous30Days' + } + } + } +} +``` + +## NOTES + +Azure Cosmos DB API for Cassandra does not support continuous backup mode currently. + +## LINKS + +- [RE:06 Data partitioning](https://learn.microsoft.com/azure/well-architected/reliability/partition-data) +- [Continuous backup with point-in-time restore in Azure Cosmos DB](https://learn.microsoft.com/azure/cosmos-db/continuous-backup-restore-introduction) +- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.documentdb/databaseaccounts) diff --git a/src/PSRule.Rules.Azure/rules/Azure.Cosmos.Rule.yaml b/src/PSRule.Rules.Azure/rules/Azure.Cosmos.Rule.yaml index 170ceb9d5c..8b24c33803 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.Cosmos.Rule.yaml +++ b/src/PSRule.Rules.Azure/rules/Azure.Cosmos.Rule.yaml @@ -108,4 +108,108 @@ spec: field: properties.publicNetworkAccess equals: Disabled +--- +# Synopsis: Enable continuous backup on Cosmos DB accounts. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Rule +metadata: + name: Azure.Cosmos.ContinuousBackup + ref: AZR-000439 + tags: + release: GA + ruleSet: 2024_09 + Azure.WAF/pillar: Reliability +spec: + type: + - Microsoft.DocumentDb/databaseAccounts + with: + - Azure.Cosmos.IsMongo + - Azure.Cosmos.IsGremlin + - Azure.Cosmos.IsTable + - Azure.Cosmos.IsNoSQL + condition: + allOf: + - field: properties.backupPolicy.type + equals: Continuous + - field: properties.backupPolicy.continuousModeProperties.tier + hasValue: true + #endregion Rules + +#region Selectors + +--- +# Synopsis: Cosmos DB accounts that use the Mongo API. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Selector +metadata: + name: Azure.Cosmos.IsMongo +spec: + if: + field: properties.capabilities[*] + allOf: + - field: name + equals: EnableMongo + greaterOrEqual: 1 + +--- +# Synopsis: Cosmos DB accounts that use the Cassandra API. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Selector +metadata: + name: Azure.Cosmos.IsCassandra +spec: + if: + field: properties.capabilities[*] + allOf: + - field: name + equals: EnableCassandra + greaterOrEqual: 1 + +--- +# Synopsis: Cosmos DB accounts that use the Gremlin API. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Selector +metadata: + name: Azure.Cosmos.IsGremlin +spec: + if: + field: properties.capabilities[*] + allOf: + - field: name + equals: EnableGremlin + greaterOrEqual: 1 + +--- +# Synopsis: Cosmos DB accounts that use the Table API. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Selector +metadata: + name: Azure.Cosmos.IsTable +spec: + if: + field: properties.capabilities[*] + allOf: + - field: name + equals: EnableTable + greaterOrEqual: 1 + +--- +# Synopsis: Cosmos DB accounts that use the NoSQL API. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Selector +metadata: + name: Azure.Cosmos.IsNoSQL +spec: + if: + field: properties.capabilities[*] + allOf: + - field: name + in: + - EnableMongo + - EnableCassandra + - EnableTable + - EnableGremlin + count: 0 + +#endregion Selectors diff --git a/tests/PSRule.Rules.Azure.Tests/Azure.Cosmos.Tests.ps1 b/tests/PSRule.Rules.Azure.Tests/Azure.Cosmos.Tests.ps1 index 155b94dba9..447f272a54 100644 --- a/tests/PSRule.Rules.Azure.Tests/Azure.Cosmos.Tests.ps1 +++ b/tests/PSRule.Rules.Azure.Tests/Azure.Cosmos.Tests.ps1 @@ -105,6 +105,23 @@ Describe 'Azure.Cosmos' -Tag 'Cosmos', 'CosmosDB' { $ruleResult.Length | Should -Be 1; $ruleResult.TargetName | Should -BeIn 'nosql-C'; } + + It 'Azure.Cosmos.ContinuousBackup' { + $filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.Cosmos.ContinuousBackup' }; + + # Fail + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' }); + $ruleResult.Length | Should -Be 2; + $ruleResult.TargetName | Should -BeIn 'graph-A', 'graph-B'; + + $ruleResult[0].Reason | Should -Be "Path properties.backupPolicy.type: The field 'properties.backupPolicy.type' does not exist."; + $ruleResult[1].Reason | Should -Be "Path properties.backupPolicy.type: Is set to 'Periodic'."; + + # Pass + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' }); + $ruleResult.Length | Should -Be 3; + $ruleResult.TargetName | Should -BeIn 'nosql-A', 'nosql-B', 'nosql-C'; + } } Context 'Resource name - Azure.Cosmos.AccountName' { diff --git a/tests/PSRule.Rules.Azure.Tests/Resources.Cosmos.json b/tests/PSRule.Rules.Azure.Tests/Resources.Cosmos.json index 0566796a77..073cf47bdb 100644 --- a/tests/PSRule.Rules.Azure.Tests/Resources.Cosmos.json +++ b/tests/PSRule.Rules.Azure.Tests/Resources.Cosmos.json @@ -99,14 +99,6 @@ "ipAddressOrRange": "52.187.184.26" } ], - "backupPolicy": { - "type": "Periodic", - "periodicModeProperties": { - "backupIntervalInMinutes": 240, - "backupRetentionIntervalInHours": 8, - "backupStorageRedundancy": "Local" - } - }, "networkAclBypassResourceIds": [] }, "ResourceGroupName": "rg-test", @@ -264,7 +256,13 @@ ], "databaseAccountOfferType": "Standard", "enableAutomaticFailover": true, - "minimalTlsVersion": "Tls" + "minimalTlsVersion": "Tls", + "backupPolicy": { + "type": "Continuous", + "continuousModeProperties": { + "tier": "Continuous7Days" + } + } }, "ResourceGroupName": "test-rg", "Type": "Microsoft.DocumentDB/databaseAccounts", @@ -297,7 +295,13 @@ "databaseAccountOfferType": "Standard", "enableAutomaticFailover": true, "disableLocalAuth": false, - "publicNetworkAccess": "Enabled" + "publicNetworkAccess": "Enabled", + "backupPolicy": { + "type": "Continuous", + "continuousModeProperties": { + "tier": "Continuous30Days" + } + } }, "ResourceGroupName": "test-rg", "Type": "Microsoft.DocumentDB/databaseAccounts", @@ -349,8 +353,13 @@ "name": "EnableServerless" } ], - "publicNetworkAccess": "Disabled" - + "publicNetworkAccess": "Disabled", + "backupPolicy": { + "type": "Continuous", + "continuousModeProperties": { + "tier": "Continuous30Days" + } + } }, "ResourceGroupName": "test-rg", "Type": "Microsoft.DocumentDB/databaseAccounts",