Multi Scopes Deployment with Azure Bicep
Tags: azure, iac, bicep, cloud
Published: 2023-09-08 11:49:44

As cloud professionals, one of your tasks is to deliver Subscriptions (or accounts on AWS) to development teams. But it is never a naked empty subscription, it is a pre-configured subscription with all the configuration and connectivity so teams can focus on what they do best, deploying applications. 
In Azure, configuration can be made on several scopes. In the management group scope, you need to move the subscription inside a specific management group, subscription level, you will need to create resource groups and manage RBAC, and finally, at the resource group level deploy resources like VNET, VNET peering, and other essential tooling. 
One of the problems is that you need to manage 3 different pipelines. One for each scope. It is time-consuming; they have their own lifetime and they can become error-prone with time. 
In Bicep, by default, it is not possible to target multiple scopes in one template. You need to create several templates. Unless you use Bicep modules.
A Bicep module is a Bicep template that is deployed from another Bicep. You can call it from the local file system or from a private registry. Modules allow you to simplify your deployments by reusing things you often deploy. But, there is a very interesting feature with module, you can specify the scope of the deployments when you use a module. In other words, you can create a multi-scope template. 
Let’s try a simple example; you have a new subscription, you need to create a resource group, and you want to create a VNET inside this resource group and then create a peering to another VNET in another subscription. 
Here we have 2 scopes, the management group scope, the subscription scope, and the resource group scope. The last one needs to address different subscriptions. 
We need to start at the higher level of the hierarchy, here it is the subscription scope. 
You need to use the targetScope keyword. It can have 4 values; tenant, managementGroup, subscription, and resourceGroup. Here we need to use managementGroup
We need to deploy objects and resources to different scopes. We need to create modules

- Vnet.bicep to create the VNET
- Peering.bicep to create the 2 peering we need

For the VNET module 

```
param virtualNetworkName string
param virtualNetworkAddressPrefix string
param location string 
param subnetName string
param subnetAddressPreffix string

resource virtualNetwork 'Microsoft.Network/virtualNetworks@2020-11-01' = {
  name: virtualNetworkName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        virtualNetworkAddressPrefix
      ]
    }
    subnets: [
      {
        name: subnetName
        properties: {
          addressPrefix: subnetAddressPreffix
        }
      } 
    ]
  }
}
output vnetID string = virtualNetwork.id
```

_Note: I output the VNET ID so I can use it later_ 

And for the peering 

```
param peeringName string
param vnetName string
param localPrefix string
param remotePrefix string  
param remoteVnetID string

var completePeeringName = '${vnetName}/${peeringName}'

resource peering 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2023-04-01' = {

  name: completePeeringName
  properties: {
    allowForwardedTraffic: true

    allowVirtualNetworkAccess: true

    remoteAddressSpace: {
      addressPrefixes: [
        localPrefix
      ]
    }
remoteVirtualNetwork: {
      id: remoteVnetID
    }
    remoteVirtualNetworkAddressSpace: {
      addressPrefixes: [
        remotePrefix
      ]
    }  
  }
}
```
_Note: You need to compose the name of the peering with the name of the VNET vnetName/peeringName_

Now we can start to deploy resources. In the main.bicep template.

```
targetScope = 'subscription'
```
Then we can start to create the resource group we need. 

```
targetScope = 'subscription'

param subscriptionID string
param azureRegion string = 'westeurope'
param resourceGroupName string 


resource myResourceGroup 'Microsoft.Resources/resourceGroups@2021-01-01' = {
  name: resourceGroupName
  location: azureRegion 
}
```

Then we call the VNET module to deploy the VNET. 

```
module virtualNetwork './modules/vnet.bicep' = {
  scope: myResourceGroup
  name: 'virtualNetwork'
  params: {
    virtualNetworkName: 'vnet1'
    virtualNetworkAddressPrefix: '10.0.0.0/24'
    location: 'westeurope'
    subnetName: 'default'
    subnetAddressPreffix: '10.0.0.0/24'
  }
}
```

For the scope, I use the symbolic name of the resource group deployment. 
Then we need to deploy our first peering 

```
var hubVnetID = '/subscriptions/xxx/resourceGroups/centralhubvnet/providers/Microsoft.Network/virtualNetworks/hubvnet'

module peering01 './modules/peering.bicep' = {
  scope: myResourceGroup
  name: 'peering01'
  params: {
    peeringName: 'toHub'
    vnetName: 'vnet1'
    localPrefix: '10.1.0.0/24'
    remotePrefix: '172.24.20.0/24'
    remoteVnetID: hubVnetID
  }
}
```

We can now deploy the second peering. But if we are still on the same scope, resourceGroup scope, we need to deploy it in a different subscription and resource group. The function resourceGroup() lets you do it by using the subscription ID and the resource group name

```
var hubVnetSubscriptionID   = 'xxxxxxx'
var hubVnetResourceGroup    = '01-centralhubvnet'
var hubVnetName             = 'hubvnet'

module peering02 './modules/peering.bicep' = {
  name: 'peering02'
  scope: resourceGroup(hubVnetSubscriptionID, hubVnetResourceGroup)
  params: {
    peeringName: 'fromHUB'
    vnetName: hubVnetName
    localPrefix: '172.24.20.0/24'
    remotePrefix: '10.1.0.0/24' 
    remoteVnetID: virtualNetwork.outputs.vnetID
  }
}
```

To deploy the main template simply use this command

```powershell
New-AzSubscriptionDeployment  -Name demo01 -Location westeurope -TemplateFile .\main.bicep -resourceGroupName demoBicep
```