From 0749e14637bdd41253e7e87445bbd1204e3085f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 07:48:02 +0000 Subject: [PATCH 1/4] Initial plan From 98ae60b9bfc677532613b14ab0e60e4e279bc5b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 08:00:14 +0000 Subject: [PATCH 2/4] Add Azure.ServiceBus.ReplicaLocation rule (AZR-000535) to check geo-replication replica locations are within allowed regions Co-authored-by: BernieWhite <13513058+BernieWhite@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/PSRule.Rules.Azure/sessions/31679168-91da-40a5-9474-6c4b54ac8252 --- docs/changelog.md | 4 + .../rules/Azure.ServiceBus.ReplicaLocation.md | 148 ++++++++++++++++++ docs/en/rules/index.md | 1 + docs/en/rules/resource.md | 1 + docs/es/rules/resource.md | 1 + .../rules/Azure.ServiceBus.Rule.ps1 | 15 ++ .../Azure.ServiceBus.Tests.ps1 | 32 ++++ 7 files changed, 202 insertions(+) create mode 100644 docs/en/rules/Azure.ServiceBus.ReplicaLocation.md diff --git a/docs/changelog.md b/docs/changelog.md index 953a25e7049..5b0dd6e431e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -30,6 +30,10 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers ## Unreleased +- New rules: + - Service Bus: + - Added `Azure.ServiceBus.ReplicaLocation` to check that geo-replication replica locations are within allowed regions. + [#3381](https://github.com/Azure/PSRule.Rules.Azure/issues/3381) - Updated rules: - Azure Kubernetes Service: - Updated `Azure.AKS.Version` to use `1.33.7` as the minimum version by @BernieWhite. diff --git a/docs/en/rules/Azure.ServiceBus.ReplicaLocation.md b/docs/en/rules/Azure.ServiceBus.ReplicaLocation.md new file mode 100644 index 00000000000..3e45a4dcb8d --- /dev/null +++ b/docs/en/rules/Azure.ServiceBus.ReplicaLocation.md @@ -0,0 +1,148 @@ +--- +reviewed: 2026-03-25 +severity: Important +pillar: Security +category: SE:01 Security baseline +resource: Service Bus +resourceType: Microsoft.ServiceBus/namespaces +online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.ServiceBus.ReplicaLocation/ +--- + +# Service Bus namespace replica location is not allowed + +## SYNOPSIS + +Service Bus namespace replica locations should be within allowed regions. + +## DESCRIPTION + +Azure supports deployment to many locations around the world called regions. +Many organizations have requirements or legal obligations that limit where data can be stored or processed. +This is commonly known as data residency. + +Service Bus namespaces can be configured with geo-replication to replicate data to one or more secondary regions. +Each configured region stores and processes data, making it subject to local legal requirements in that region. + +To align with your organizational requirements, you may choose to limit the regions that geo-replication replicas can be deployed to. +This allows you to ensure that resources are deployed to regions that meet your data residency requirements. + +Some resources, particularly those related to preview services or features, may not be available in all regions. + +## RECOMMENDATION + +Consider deploying Service Bus namespace geo-replication replicas to allowed regions to align with your organizational requirements. +Also consider using Azure Policy to enforce allowed regions at runtime. + +## EXAMPLES + +### Configure with Bicep + +To deploy namespaces that pass this rule: + +- Set the `locationName` property of each replica location specified in `properties.geoDataReplication.locations` to an allowed region. + +For example: + +```bicep +resource sb 'Microsoft.ServiceBus/namespaces@2023-01-01-preview' = { + name: serviceBusName + location: primaryLocation + sku: { + name: 'Premium' + tier: 'Premium' + capacity: 1 + } + properties: { + geoDataReplication: { + maxReplicationLagDurationInSeconds: maxReplicationLagInSeconds + locations: [ + { + locationName: primaryLocation + roleType: 'Primary' + } + { + locationName: secondaryLocation + roleType: 'Secondary' + } + ] + } + } +} +``` + +### Configure with Azure template + +To deploy namespaces that pass this rule: + +- Set the `locationName` property of each replica location specified in `properties.geoDataReplication.locations` to an allowed region. + +For example: + +```json +{ + "type": "Microsoft.ServiceBus/namespaces", + "apiVersion": "2023-01-01-preview", + "name": "[parameters('serviceBusName')]", + "location": "[parameters('primaryLocation')]", + "sku": { + "name": "Premium", + "tier": "Premium", + "capacity": 1 + }, + "properties": { + "geoDataReplication": { + "maxReplicationLagDurationInSeconds": "[parameters('maxReplicationLagInSeconds')]", + "locations": [ + { + "locationName": "[parameters('primaryLocation')]", + "roleType": "Primary" + }, + { + "locationName": "[parameters('secondaryLocation')]", + "roleType": "Secondary" + } + ] + } + } +} +``` + +## NOTES + +This rule requires one or more allowed regions to be configured. +By default, all regions are allowed. + +### Rule configuration + + + +To configure this rule set the `AZURE_RESOURCE_ALLOWED_LOCATIONS` configuration value to a set of allowed regions. + +For example: + +```yaml +configuration: + AZURE_RESOURCE_ALLOWED_LOCATIONS: + - australiaeast + - australiasoutheast +``` + +If you configure this `AZURE_RESOURCE_ALLOWED_LOCATIONS` configuration value, +also consider setting `AZURE_RESOURCE_GROUP` the configuration value to when resources use the location of the resource group. + +For example: + +```yaml +configuration: + AZURE_RESOURCE_GROUP: + location: australiaeast +``` + +## LINKS + +- [SE:01 Security baseline](https://learn.microsoft.com/azure/well-architected/security/establish-baseline) +- [Geo-replication](https://learn.microsoft.com/azure/service-bus-messaging/service-bus-geo-replication) +- [Configure geo-replication](https://learn.microsoft.com/azure/service-bus-messaging/service-bus-geo-replication#setup) +- [Data residency in Azure](https://azure.microsoft.com/explore/global-infrastructure/data-residency/#overview) +- [Azure geographies](https://azure.microsoft.com/explore/global-infrastructure/geographies/#geographies) +- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.servicebus/namespaces) diff --git a/docs/en/rules/index.md b/docs/en/rules/index.md index 12f6e475686..97809c82a37 100644 --- a/docs/en/rules/index.md +++ b/docs/en/rules/index.md @@ -553,5 +553,6 @@ AZR-000531 | [Azure.ServiceFabric.ManagedNaming](Azure.ServiceFabric.ManagedNami AZR-000532 | [Azure.EventHub.AvailabilityZone](Azure.EventHub.AvailabilityZone.md) | Use zone redundant Event Hub namespaces in supported regions to improve reliability. | GA AZR-000533 | [Azure.Redis.MigrateAMR](Azure.Redis.MigrateAMR.md) | Azure Cache for Redis is being retired. Migrate to Azure Managed Redis. | GA AZR-000534 | [Azure.RedisEnterprise.MigrateAMR](Azure.RedisEnterprise.MigrateAMR.md) | Azure Cache for Redis Enterprise and Enterprise Flash are being retired. Migrate to Azure Managed Redis. | GA +AZR-000535 | [Azure.ServiceBus.ReplicaLocation](Azure.ServiceBus.ReplicaLocation.md) | Service Bus namespace replica locations should be within allowed regions. | GA *[GA]: Generally Available — Rules related to a generally available Azure features. diff --git a/docs/en/rules/resource.md b/docs/en/rules/resource.md index 6db33181d03..2cf06f88c17 100644 --- a/docs/en/rules/resource.md +++ b/docs/en/rules/resource.md @@ -787,6 +787,7 @@ Name | Synopsis | Severity | Level [Azure.ServiceBus.DisableLocalAuth](Azure.ServiceBus.DisableLocalAuth.md) | Authenticate Service Bus publishers and consumers with Entra ID identities. | Important | Error [Azure.ServiceBus.GeoReplica](Azure.ServiceBus.GeoReplica.md) | Enhance resilience to regional outages by replicating namespaces. | Important | Error [Azure.ServiceBus.MinTLS](Azure.ServiceBus.MinTLS.md) | Service Bus namespaces should reject TLS versions older than 1.2. | Important | Error +[Azure.ServiceBus.ReplicaLocation](Azure.ServiceBus.ReplicaLocation.md) | Service Bus namespace replica locations should be within allowed regions. | Important | Error [Azure.ServiceBus.Usage](Azure.ServiceBus.Usage.md) | Regularly remove unused resources to reduce costs. | Important | Error ## Service Fabric diff --git a/docs/es/rules/resource.md b/docs/es/rules/resource.md index 6db33181d03..2cf06f88c17 100644 --- a/docs/es/rules/resource.md +++ b/docs/es/rules/resource.md @@ -787,6 +787,7 @@ Name | Synopsis | Severity | Level [Azure.ServiceBus.DisableLocalAuth](Azure.ServiceBus.DisableLocalAuth.md) | Authenticate Service Bus publishers and consumers with Entra ID identities. | Important | Error [Azure.ServiceBus.GeoReplica](Azure.ServiceBus.GeoReplica.md) | Enhance resilience to regional outages by replicating namespaces. | Important | Error [Azure.ServiceBus.MinTLS](Azure.ServiceBus.MinTLS.md) | Service Bus namespaces should reject TLS versions older than 1.2. | Important | Error +[Azure.ServiceBus.ReplicaLocation](Azure.ServiceBus.ReplicaLocation.md) | Service Bus namespace replica locations should be within allowed regions. | Important | Error [Azure.ServiceBus.Usage](Azure.ServiceBus.Usage.md) | Regularly remove unused resources to reduce costs. | Important | Error ## Service Fabric diff --git a/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 b/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 index 5a041c51bc5..7acd54f6eff 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 +++ b/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 @@ -13,6 +13,21 @@ Rule 'Azure.ServiceBus.Usage' -Ref 'AZR-000177' -Type 'Microsoft.ServiceBus/name $Assert.GreaterOrEqual($items, '.', 1); } +# Synopsis: Service Bus namespace replica locations should be within allowed regions. +Rule 'Azure.ServiceBus.ReplicaLocation' -Ref 'AZR-000535' -Type 'Microsoft.ServiceBus/namespaces' -If { $Assert.HasField($TargetObject, 'properties.geoDataReplication.locations') } -Tag @{ release = 'GA'; ruleSet = '2026_06'; 'Azure.WAF/pillar' = 'Security'; } { + $context = $PSRule.GetService('Azure.Context'); + $locations = $PSRule.GetPath($TargetObject, 'properties.geoDataReplication.locations[*].locationName'); + if ($locations -eq $Null -or $locations.Length -eq 0) { + return $Assert.Pass(); + } + + for ($i = 0; $i -lt $locations.Length; $i++) { + $path = "properties.geoDataReplication.locations[$i].locationName"; + [string]$location = $locations[$i]; + $Assert.Create($path, [bool]$context.IsAllowedLocation($location), $LocalizedData.LocationNotAllowed, @($location)); + } +} + # Synopsis: Ensure namespaces audit diagnostic logs are enabled. Rule 'Azure.ServiceBus.AuditLogs' -Ref 'AZR-000358' -Type 'Microsoft.ServiceBus/namespaces' -With 'Azure.ServiceBus.IsPremium' -Tag @{ release = 'GA'; ruleSet = '2023_03'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.WAF/maturity' = 'L1' } { $logCategoryGroups = 'audit', 'allLogs' diff --git a/tests/PSRule.Rules.Azure.Tests/Azure.ServiceBus.Tests.ps1 b/tests/PSRule.Rules.Azure.Tests/Azure.ServiceBus.Tests.ps1 index 9c26e8e9fe5..6b4fb026ca7 100644 --- a/tests/PSRule.Rules.Azure.Tests/Azure.ServiceBus.Tests.ps1 +++ b/tests/PSRule.Rules.Azure.Tests/Azure.ServiceBus.Tests.ps1 @@ -131,6 +131,38 @@ Describe 'Azure.ServiceBus' -Tag 'ServiceBus' { } } + Context 'With Location Configuration' { + BeforeAll { + $invokeParams = @{ + Baseline = 'Azure.All' + Module = 'PSRule.Rules.Azure' + WarningAction = 'Ignore' + ErrorAction = 'Stop' + Option = @{ + 'Configuration.AZURE_RESOURCE_ALLOWED_LOCATIONS' = @('centraluseuap', 'norwayeast') + } + } + $dataPath = Join-Path -Path $here -ChildPath 'Resources.ServiceBus.json'; + $result = Invoke-PSRule @invokeParams -InputPath $dataPath; + } + + It 'Azure.ServiceBus.ReplicaLocation' { + $filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.ServiceBus.ReplicaLocation' }; + + # Fail + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' }); + $ruleResult | Should -Not -BeNullOrEmpty; + $ruleResult.Length | Should -Be 1; + $ruleResult.TargetName | Should -BeIn 'servicens-E'; + + # Pass + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' }); + $ruleResult | Should -Not -BeNullOrEmpty; + $ruleResult.Length | Should -Be 2; + $ruleResult.TargetName | Should -BeIn 'servicens-C', 'servicens-D'; + } + } + Context 'With Template' { BeforeAll { $outputFile = Join-Path -Path $rootPath -ChildPath out/tests/Resources.ServiceBus.json; From 190fb5ce7d35354f962043d64463c1a4f5225e17 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:50:13 +0000 Subject: [PATCH 3/4] Update rule ID to AZR-000536 for Azure.ServiceBus.ReplicaLocation Co-authored-by: BernieWhite <13513058+BernieWhite@users.noreply.github.com> Agent-Logs-Url: https://github.com/Azure/PSRule.Rules.Azure/sessions/60cdc848-1de6-4a8f-93f6-0143644f42af --- docs/en/rules/index.md | 2 +- src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/rules/index.md b/docs/en/rules/index.md index 97809c82a37..9240bfd933d 100644 --- a/docs/en/rules/index.md +++ b/docs/en/rules/index.md @@ -553,6 +553,6 @@ AZR-000531 | [Azure.ServiceFabric.ManagedNaming](Azure.ServiceFabric.ManagedNami AZR-000532 | [Azure.EventHub.AvailabilityZone](Azure.EventHub.AvailabilityZone.md) | Use zone redundant Event Hub namespaces in supported regions to improve reliability. | GA AZR-000533 | [Azure.Redis.MigrateAMR](Azure.Redis.MigrateAMR.md) | Azure Cache for Redis is being retired. Migrate to Azure Managed Redis. | GA AZR-000534 | [Azure.RedisEnterprise.MigrateAMR](Azure.RedisEnterprise.MigrateAMR.md) | Azure Cache for Redis Enterprise and Enterprise Flash are being retired. Migrate to Azure Managed Redis. | GA -AZR-000535 | [Azure.ServiceBus.ReplicaLocation](Azure.ServiceBus.ReplicaLocation.md) | Service Bus namespace replica locations should be within allowed regions. | GA +AZR-000536 | [Azure.ServiceBus.ReplicaLocation](Azure.ServiceBus.ReplicaLocation.md) | Service Bus namespace replica locations should be within allowed regions. | GA *[GA]: Generally Available — Rules related to a generally available Azure features. diff --git a/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 b/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 index 7acd54f6eff..b1fd7d95fae 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 +++ b/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 @@ -14,7 +14,7 @@ Rule 'Azure.ServiceBus.Usage' -Ref 'AZR-000177' -Type 'Microsoft.ServiceBus/name } # Synopsis: Service Bus namespace replica locations should be within allowed regions. -Rule 'Azure.ServiceBus.ReplicaLocation' -Ref 'AZR-000535' -Type 'Microsoft.ServiceBus/namespaces' -If { $Assert.HasField($TargetObject, 'properties.geoDataReplication.locations') } -Tag @{ release = 'GA'; ruleSet = '2026_06'; 'Azure.WAF/pillar' = 'Security'; } { +Rule 'Azure.ServiceBus.ReplicaLocation' -Ref 'AZR-000536' -Type 'Microsoft.ServiceBus/namespaces' -If { $Assert.HasField($TargetObject, 'properties.geoDataReplication.locations') } -Tag @{ release = 'GA'; ruleSet = '2026_06'; 'Azure.WAF/pillar' = 'Security'; } { $context = $PSRule.GetService('Azure.Context'); $locations = $PSRule.GetPath($TargetObject, 'properties.geoDataReplication.locations[*].locationName'); if ($locations -eq $Null -or $locations.Length -eq 0) { From 680c15ad7e2c5718e77122b9c392f4a11a344e91 Mon Sep 17 00:00:00 2001 From: Bernie White Date: Thu, 26 Mar 2026 17:01:09 +0100 Subject: [PATCH 4/4] Additional updates --- .../rules/Azure.ServiceBus.ReplicaLocation.md | 43 ++++++++------ docs/en/rules/index.md | 2 +- docs/examples/resources/servicebus.bicep | 47 +++++++++++++++- docs/examples/resources/servicebus.json | 56 +++++++++++++++++-- .../rules/Azure.ServiceBus.Rule.ps1 | 2 +- 5 files changed, 126 insertions(+), 24 deletions(-) diff --git a/docs/en/rules/Azure.ServiceBus.ReplicaLocation.md b/docs/en/rules/Azure.ServiceBus.ReplicaLocation.md index 3e45a4dcb8d..a85b066f493 100644 --- a/docs/en/rules/Azure.ServiceBus.ReplicaLocation.md +++ b/docs/en/rules/Azure.ServiceBus.ReplicaLocation.md @@ -1,5 +1,5 @@ --- -reviewed: 2026-03-25 +reviewed: 2026-03-26 severity: Important pillar: Security category: SE:01 Security baseline @@ -12,7 +12,7 @@ online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.Servic ## SYNOPSIS -Service Bus namespace replica locations should be within allowed regions. +The replica location determines the country or region where the data is stored and processed. ## DESCRIPTION @@ -44,20 +44,23 @@ To deploy namespaces that pass this rule: For example: ```bicep -resource sb 'Microsoft.ServiceBus/namespaces@2023-01-01-preview' = { - name: serviceBusName - location: primaryLocation +resource withReplication 'Microsoft.ServiceBus/namespaces@2025-05-01-preview' = { + name: name + location: location + identity: { + type: 'SystemAssigned' + } sku: { name: 'Premium' - tier: 'Premium' - capacity: 1 } properties: { + disableLocalAuth: true + minimumTlsVersion: '1.2' geoDataReplication: { - maxReplicationLagDurationInSeconds: maxReplicationLagInSeconds + maxReplicationLagDurationInSeconds: 300 locations: [ { - locationName: primaryLocation + locationName: location roleType: 'Primary' } { @@ -81,20 +84,23 @@ For example: ```json { "type": "Microsoft.ServiceBus/namespaces", - "apiVersion": "2023-01-01-preview", - "name": "[parameters('serviceBusName')]", - "location": "[parameters('primaryLocation')]", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, "sku": { - "name": "Premium", - "tier": "Premium", - "capacity": 1 + "name": "Premium" }, "properties": { + "disableLocalAuth": true, + "minimumTlsVersion": "1.2", "geoDataReplication": { - "maxReplicationLagDurationInSeconds": "[parameters('maxReplicationLagInSeconds')]", + "maxReplicationLagDurationInSeconds": 300, "locations": [ { - "locationName": "[parameters('primaryLocation')]", + "locationName": "[parameters('location')]", "roleType": "Primary" }, { @@ -112,6 +118,9 @@ For example: This rule requires one or more allowed regions to be configured. By default, all regions are allowed. +Also note that Service Bus geo-replication requires a Premium SKU namespace. +As a result, this rule only applies to namespaces using the Premium SKU that already have geo-replication configured. + ### Rule configuration diff --git a/docs/en/rules/index.md b/docs/en/rules/index.md index 9240bfd933d..03917ab6c5e 100644 --- a/docs/en/rules/index.md +++ b/docs/en/rules/index.md @@ -553,6 +553,6 @@ AZR-000531 | [Azure.ServiceFabric.ManagedNaming](Azure.ServiceFabric.ManagedNami AZR-000532 | [Azure.EventHub.AvailabilityZone](Azure.EventHub.AvailabilityZone.md) | Use zone redundant Event Hub namespaces in supported regions to improve reliability. | GA AZR-000533 | [Azure.Redis.MigrateAMR](Azure.Redis.MigrateAMR.md) | Azure Cache for Redis is being retired. Migrate to Azure Managed Redis. | GA AZR-000534 | [Azure.RedisEnterprise.MigrateAMR](Azure.RedisEnterprise.MigrateAMR.md) | Azure Cache for Redis Enterprise and Enterprise Flash are being retired. Migrate to Azure Managed Redis. | GA -AZR-000536 | [Azure.ServiceBus.ReplicaLocation](Azure.ServiceBus.ReplicaLocation.md) | Service Bus namespace replica locations should be within allowed regions. | GA +AZR-000540 | [Azure.ServiceBus.ReplicaLocation](Azure.ServiceBus.ReplicaLocation.md) | Service Bus namespace replica locations should be within allowed regions. | GA *[GA]: Generally Available — Rules related to a generally available Azure features. diff --git a/docs/examples/resources/servicebus.bicep b/docs/examples/resources/servicebus.bicep index f92573fd3ea..8fe937fc76c 100644 --- a/docs/examples/resources/servicebus.bicep +++ b/docs/examples/resources/servicebus.bicep @@ -9,8 +9,11 @@ param name string @description('The location resources will be deployed.') param location string = resourceGroup().location +@description('The secondary location for geo-replication.') +param secondaryLocation string + // An example Service Bus namespace. -resource ns 'Microsoft.ServiceBus/namespaces@2022-10-01-preview' = { +resource ns 'Microsoft.ServiceBus/namespaces@2025-05-01-preview' = { name: name location: location identity: { @@ -22,5 +25,47 @@ resource ns 'Microsoft.ServiceBus/namespaces@2022-10-01-preview' = { properties: { disableLocalAuth: true minimumTlsVersion: '1.2' + geoDataReplication: { + maxReplicationLagDurationInSeconds: 300 + locations: [ + { + locationName: location + roleType: 'Primary' + } + { + locationName: secondaryLocation + roleType: 'Secondary' + } + ] + } + } +} + +// An example Service Bus namespace with geo-replication enabled. +resource withReplication 'Microsoft.ServiceBus/namespaces@2025-05-01-preview' = { + name: name + location: location + identity: { + type: 'SystemAssigned' + } + sku: { + name: 'Premium' + } + properties: { + disableLocalAuth: true + minimumTlsVersion: '1.2' + geoDataReplication: { + maxReplicationLagDurationInSeconds: 300 + locations: [ + { + locationName: location + roleType: 'Primary' + } + { + locationName: secondaryLocation + roleType: 'Secondary' + } + ] + } } } diff --git a/docs/examples/resources/servicebus.json b/docs/examples/resources/servicebus.json index 8fdb73039de..e6681369498 100644 --- a/docs/examples/resources/servicebus.json +++ b/docs/examples/resources/servicebus.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11141900091582778494" + "version": "0.41.2.15936", + "templateHash": "5825917393636321245" } }, "parameters": { @@ -21,12 +21,18 @@ "metadata": { "description": "The location resources will be deployed." } + }, + "secondaryLocation": { + "type": "string", + "metadata": { + "description": "The secondary location for geo-replication." + } } }, "resources": [ { "type": "Microsoft.ServiceBus/namespaces", - "apiVersion": "2022-10-01-preview", + "apiVersion": "2025-05-01-preview", "name": "[parameters('name')]", "location": "[parameters('location')]", "identity": { @@ -37,7 +43,49 @@ }, "properties": { "disableLocalAuth": true, - "minimumTlsVersion": "1.2" + "minimumTlsVersion": "1.2", + "geoDataReplication": { + "maxReplicationLagDurationInSeconds": 300, + "locations": [ + { + "locationName": "[parameters('location')]", + "roleType": "Primary" + }, + { + "locationName": "[parameters('secondaryLocation')]", + "roleType": "Secondary" + } + ] + } + } + }, + { + "type": "Microsoft.ServiceBus/namespaces", + "apiVersion": "2025-05-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "sku": { + "name": "Premium" + }, + "properties": { + "disableLocalAuth": true, + "minimumTlsVersion": "1.2", + "geoDataReplication": { + "maxReplicationLagDurationInSeconds": 300, + "locations": [ + { + "locationName": "[parameters('location')]", + "roleType": "Primary" + }, + { + "locationName": "[parameters('secondaryLocation')]", + "roleType": "Secondary" + } + ] + } } } ] diff --git a/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 b/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 index b1fd7d95fae..4d02624b94c 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 +++ b/src/PSRule.Rules.Azure/rules/Azure.ServiceBus.Rule.ps1 @@ -14,7 +14,7 @@ Rule 'Azure.ServiceBus.Usage' -Ref 'AZR-000177' -Type 'Microsoft.ServiceBus/name } # Synopsis: Service Bus namespace replica locations should be within allowed regions. -Rule 'Azure.ServiceBus.ReplicaLocation' -Ref 'AZR-000536' -Type 'Microsoft.ServiceBus/namespaces' -If { $Assert.HasField($TargetObject, 'properties.geoDataReplication.locations') } -Tag @{ release = 'GA'; ruleSet = '2026_06'; 'Azure.WAF/pillar' = 'Security'; } { +Rule 'Azure.ServiceBus.ReplicaLocation' -Ref 'AZR-000540' -Type 'Microsoft.ServiceBus/namespaces' -If { $Assert.HasField($TargetObject, 'properties.geoDataReplication.locations') } -Tag @{ release = 'GA'; ruleSet = '2026_06'; 'Azure.WAF/pillar' = 'Security'; } { $context = $PSRule.GetService('Azure.Context'); $locations = $PSRule.GetPath($TargetObject, 'properties.geoDataReplication.locations[*].locationName'); if ($locations -eq $Null -or $locations.Length -eq 0) {