Azure Deployment Stacks, deploy and manage a landing zone with Bicep
Tags: azure, iac, bicep, cloud
Published: 2023-09-04 20:21:12

Azure Deployment stack is the successor of Azure Blueprint. It lets you manage several resources as a block. It helps to manage the life cycle of what you deploy. [See](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-stacks?tabs=azure-powershell)

It was designed to help the infrastructure team to deploy and manage necessary tooling for developer teams. What is the most current setup deployed by infrastructure teams? A Landing Zone. 
To be short, An Azure Landing Zone is a best-practice architecture for setting up a secure and well-structured environment. Most of the time you need to customize a subscription by adding governance tools, configuring RBAC, adding resource groups, and configuring network connectivity (generally a spoke VNET peered to a HUB VNET). Let's try to do that using Azure Bicep and Azure deployment stacks. 
Let’s try to make it simple, deploying only a resource group and a VNET and configuring a peering to a hub VNET. 
It would be nice if we could do that by using a single multi-scope template. You can do that in Bicep by using the module. But it doesn't work as expected, If the deployment is valid and deploys resources with Bicep it throws an error if you try to use the same template with New-AzSubscriptionDeploymentStack. 
We need to split the deployment into two parts, one for the subscription scope and the other for the resource group scope. 
To create a resource group in Bicep we need to switch to the subscription scope by using targetScope

```
targetScope = 'subscription'

param resourceGroupName  string = 'bicepstack'
param azureRegion string = 'westeurope'

resource myResourceGroup 'Microsoft.Resources/resourceGroups@2021-01-01' = {
  name: resourceGroupName
  location: azureRegion 
}
```
But before deploying this stack we need to create one resource group that will host the deployment stack
And then we can use PowerShell to deploy the stack. 

```powershell
New-AzSubscriptionDeploymentStack -name rg01 -location westeurope -TemplateFile .\rg.bicep -DeploymentResourceGroupName 01-stack -DenySettingsMode none
```

Then we need to deploy our resources inside our new resource group. But we need to use some modules. 

The first one is for the VNET (this one is optional as we could deploy from the main Bicep file).

```
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
```
We need to use output here to get access to the VNET ID
The second module is for peering. Here we need to be able to change the scope of the deployment. When you peer two VNETs you need to create an object inside each VNETs so we need to be able to change the scope to target the HUB VNET located in a separate subscription. 

```
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
      ]
    }  
  }
}
```

Now we can create the main.bicep template 

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

}

module peering01 'peering.bicep' = {
  name: 'peering01'
  params: {
    peeringName: 'toHub'
    vnetName: 'vnet1'
    localPrefix: '10.0.0.0/24'
    remotePrefix: '172.24.20.0/24'
    remoteVnetID: '/subscriptions/xxx-xxx-xxx-xxxxx/resourceGroups/01-centralhubvnet/providers/Microsoft.Network/virtualNetworks/hubvnet'
  }

}

module peering02 'peering.bicep' = {
  name: 'peering0é'
  scope: resourceGroup('xxx-xxx-xxx-xxx-xxx', '01-centralhubvnet')
  params: {
    peeringName: 'fromHUB'
    vnetName: 'hubvnet'
    localPrefix: '172.24.20.0/24'
    remotePrefix: '10.0.0.0/24' 
    remoteVnetID: virtualNetwork.outputs.vnetID
  }
}
```

We use the module to create the VNET and two modules for the peering. The first own create the peering on the newly created VNET. The second one with a different scope to deploy the peering in the HUB VNET localized in a different subscription. We use the resourceGroup function with the Subscription ID and the resource group name to change the scope. 
Then we can use the New-AzResourceGroupDeploymentStack cmdlet to deploy the new stack.

```
New-AzResourceGroupDeploymentStack -name demo001 -ResourceGroupName stack -DenySettingsMode none -TemplateFile .\main.bicep 
```
We, now, have in Azure a new stack with the VNET and the two peering objects. We can also apply different settings to protect these objects to be deleted and manage the life cycle of the stack.