Azure Deployment Stack overview
Tags: iac, governance, bicep, azure
Published: 2023-07-25 17:46:35


Using Infrastructure as Code on a large scale can be challenging, especially when you create infrastructure for other teams. You deploy the network, security resources, and other objects and other configurations so others can deploy their workload. 
You can see some problems. People could delete a VNET or other critical resources. Managing the life cycle of your resources across several subscriptions is challenging. Versioning your tooling is complex. 

A new feature (GA) is here to resolve these difficulties, Azure Deployment Stack. It allows creating a deployment with an IaC code (ARM or Bicep) as an Azure resource. Resources deployed by Deployment Stack are Managed Resources. Deployment Stack will create a Deployment Stack object in the subscription that will govern the resources.

Let’s take a look at this new feature. 
First things we need an ARM template or a Bicep file to deploy our resource. 
In this example, I will only deploy a VNET and a NSG.

```
param location string = resourceGroup().location
param vnetName string = 'mainVnet'

var nsgRules = [
  {
    name: 'default-nsg'
    rules: [
      {
      name: 'rule-deny-all'
      properties: {
        description: 'description'
        protocol: 'Tcp'
        sourcePortRange: '*'
        destinationPortRange: '*'
        sourceAddressPrefix: '*'
        destinationAddressPrefix: '*'
        access: 'Deny'
        priority: 3000
        direction: 'Inbound'
        }      
      }
      {
      name: 'rule-allow-rdp'
      properties: {
        description: 'description'
        protocol: 'Tcp'
        sourcePortRange: '*'
        destinationPortRange: '3389'
        sourceAddressPrefix: '*'
        destinationAddressPrefix: '*'
        access: 'Allow'
        priority: 150
        direction: 'Inbound'
        } 
      }
      {
        name: 'rule-allow-ssh'
        properties: {
          description: 'description'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '22'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          access: 'Allow'
          priority: 110
          direction: 'Inbound'
        } 
      }
    ]
  }    
]

resource NetworkSecurityGroups 'Microsoft.Network/networkSecurityGroups@2021-03-01' = [for rule in nsgRules: {
  name: rule.name
  location: resourceGroup().location
  properties: {
    securityRules: rule.rules
  }
}]

resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-11-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'Subnet-1'
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      }
      {
        name: 'Subnet-2'
        properties: {
          addressPrefix: '10.0.1.0/24'
        }
      }
    ]
  }
}
```
Let’s deploy it (note, you may have to update your AZ PowerShell module)

```powershell
New-AzResourceGroupDeploymentStack -Name "demo" -ResourceGroupName "01-depStack" -TemplateFile "./main.bicep" -DenySettingsMode "none"  
```
The result will be 

```
Id                          : /subscriptions/2a21f4a3-c253-47fc-a05d-1c04de8ed626/resourceGroups/01-depStack/providers/Microsoft.Resources/deploymentStacks/demo
Name                        : demo
ProvisioningState           : succeeded
ResourcesCleanupAction      : detach
ResourceGroupsCleanupAction : detach
DenySettingsMode            : none
CreationTime(UTC)           : 24/07/2023 20:40:49
DeploymentId                : /subscriptions/2a21f4a3-c253-47fc-a05d-1c04de8ed626/resourceGroups/01-depStack/providers/Microsoft.Resources/deployments/demo-2023-07-24-20-40-50-d03
                              09
Resources                   : /subscriptions/2a21f4a3-c253-47fc-a05d-1c04de8ed626/resourceGroups/01-depStack/providers/Microsoft.Network/networkSecurityGroups/default-nsg
                              /subscriptions/2a21f4a3-c253-47fc-a05d-1c04de8ed626/resourceGroups/01-depStack/providers/Microsoft.Network/virtualNetworks/mainVnet
```

If you look into the resource group, you will find the NSG and the VNET. But you will also find the deployment stack object, demo, in "Deployment Stack" under settings.  

You can also run this command to retrieve the Deployment Stack 

```powershell
Get-AzResourceGroupDeploymentStack -Name "demo" -ResourceGroupName "01-depStack" 
```

You will get the same output we had during the deployment.
At this point, the Deployment stack reminds me a little bit of Terrafrom state. But there are more features. 

Imagine that you want to remove the NSG from the deployment stack, but you are not sure if this NSG is used or not by teams. Deleting the NSG may cause problems. 
Deployment stack offers you a solution. You can use the Detach option. In this case, you can delete a resource from the deployment stack without removing the resource from the resource group. 

You need to remove the resource from the template and run this command: 

```powershell
Set-AzResourceGroupDeploymentStack -Name "demo" -ResourceGroupName "01-depStack" -TemplateFile "./main.bicep" -DenySettingsMode "none"  
```

And it will detach the NSG from the stack. The NSG is no longueur a managed resource and users can do whatever they want with it, including remove it. 
But if you are sure you can delete a resource without any impact, you can use -deleteResources switch, which will remove the resource from the stack and the resource group. 

```powershell
Set-AzResourceGroupDeploymentStack -Name "demo" -ResourceGroupName "01-depStack" -TemplateFile "./main.bicep" -DenySettingsMode "none" -DeleteResources  
```

This will delete the NSG from the Stack and also from the resource group. 

But Deployment Stack can do more by protecting deployed resources from accidental deletion. You have seen in the example the parameter DenySettingsMode with the value none. 
This parameter controls what people can do with objects deployed in their subscriptions. There are 3 allowed values; None (nothing happen), DenyDelete (users could not delete resources), and DenyWriteAndDelete (users could not delete or update resources).

```powershell
Set-AzResourceGroupDeploymentStack -Name "demo" -ResourceGroupName "01-depStack" -TemplateFile "./main.bicep" -DenySettingsMode "denydelete"
```
Now, people can't delete the VNET managed by the deployment stack. But the interesting point is, if they can't delete the VNET, they are still able to delete a subnet. 
Is it a good thing? Maybe yes, sometimes teams should be able to manage their VNET including deleting some subnets. 
You can use the -DenySettingsApplyToChildScopes switch to cover all child scopes, but in this case, it will cover all subnets, and it may be not what you want.
But are we able to protect an important subnet and leave others unprotected? Yes, by extracting this important subnet from the VNET. The new subnet will become managed by Stack. 

```
resource crutialSubnet 'Microsoft.Network/virtualNetworks/subnets@2023-02-01' = {
  name: 'crucial'
  parent: virtualNetwork
  properties: {
    addressPrefix: '10.0.2.0/24'
  }
}
```

```powershell
Set-AzResourceGroupDeploymentStack -Name "demo" -ResourceGroupName "01-depStack" -TemplateFile "./main.bicep" -DenySettingsMode "denydelete"
```
You will still be able to delete other subnets, but the subnet named crucial is protected. 

Azure Deployment Stack is in preview but responds to certain needs when it comes to deploying resources on a large scale. It is a perfect tool for Platform teams and people deploying landing zones for other teams.