Azure Deployment stack, using deny settings
Tags: azure, iac, cloud
Published: 2023-12-19 19:10:44

In one of my last posts about Azure Deployment Stack, I introduced this new future for deploying and protecting resources in Azure. Let’s see in detail what options we can use to control the deployment lifecycle. 

I will use the same bicep file that deploys a VNET with 2 child subnets, an NSG, and another subnet outside the VNET declaration. 

```
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'

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

In the previous post have seen how to use the -DenySettingsMode parameter of the New-AzResourceGroupDeploymentStack cmdlet to control the behavior of the stack when a user tries to delete a resource (via the Azure Portal or by using other IaC tools). 
The parameter has 3 values, none where nothing happens, and the action is not affected. The denyDelete value disallows any delete action affecting the resource deployed by the Deployment Stack. The last value is DenyWriteAndDelete protects the resource against deletion but also against any update. For example, on a Virtual Network protected by the DenyWriteAndDelete value, users will not be able to delete the VNET but also will not be able to add a prefix or change other parameters.
In the case of denyDelete if you try to delete the VNET you will get this error message
ErrorCode: DenyAssignmentAuthorizationFailed

> ErrorCode: DenyAssignmentAuthorizationFailed
ErrorMessage: The client XXX with object id XXX  has permission to perform action 'Microsoft.Network/virtualNetworks/delete' on scope '/subscriptions/XXXX/resourceGroups/01-lab-depstack/providers/Microsoft.Network/virtualNetworks/mainVnet'; however, the access is denied because of the deny assignment with name 'Deny assignment '531c2711-3f75-5170-ae80-6b06de7fc2e7' created by Deployment Stack '/subscriptions/XXX/resourceGroups/01-lab-depstack/providers/Microsoft.Resources/deploymentStacks/demo01'.' 

If you use DenyWriteAndDelete, you will have the same error if you try to delete the VNET and this error message if you try to modify the VNET, for example if you try to add one prefix.


```powershell
$vnet = Get-AzVirtualNetwork -Name mainVnet -ResourceGroupName 01-lab-depstack 
$vnet.AddressSpace.AddressPrefixes.add("192.168.0.0/24")
Set-AzVirtualNetwork -VirtualNetwork $vnet
```
You get this error message 

> Set-AzVirtualNetwork: The client XXXwith object id XXX has permission to perform action 'Microsoft.Network/virtualNetworks/write' on scope '/subscriptions/XXXX/resourceGroups/01-lab-depstack/providers/Microsoft.Network/virtualNetworks/mainVnet'; however, the access is denied because of the deny assignment with name 'Deny assignment '7109b2d9-f37a-5b14-bd7b-d789965c1b5b' created by Deployment Stack '/subscriptions/XXX/resourceGroups/01-lab-depstack/providers/Microsoft.Resources/deploymentStacks/demo02'.' 

But what happens if we try to deploy a subnet? 

```powershell
$subnet = @{
Name = 'subnet-new'
VirtualNetwork = $vent
AddressPrefix = '10.0.1.0/24'
}
Add-AzVirtualNetworkSubnetConfig @subnet
$vent | Set-AzVirtualNetwork
```

We get the same error message. This is because the action in PowerShell targets the VNET and not the subnet level. The subnet is normally at the child level and should not be affected. 
When doing the same in the portal I do not have any error message, because the portal target the child resource

Let’s try something else, I will disallow the creation of child resources. 

```powershell
New-AzResourceGroupDeploymentStack -Name "demo02" -ResourceGroupName "01-lab-depstack" -TemplateFile "./main.bicep" -DenySettingsMode DenyWriteAndDelete -DenySettingsApplyToChildScopes
```
This time, subnet creation in the portal is not possible anymore. 
But what if we still want people to create and delete subnets?
You can use the -DenySettingsExcludedAction parameter to list actions on the VNET we want to allow.
In this case 'Microsoft.Network/virtualNetworks/subnets/write' and 'Microsoft.Network/virtualNetworks/subnets/delete'.

```powershell
New-AzResourceGroupDeploymentStack -Name "demo02" -ResourceGroupName "01-lab-depstack" -TemplateFile "./main.bicep" -DenySettingsMode DenyWriteAndDelete -DenySettingsApplyToChildScopes -DenySettingsExcludedAction @('Microsoft.Network/virtualNetworks/subnets/write', 'Microsoft.Network/virtualNetworks/subnets/delete')
```

We can now create and delete subnets without any problem. 

But if I want some identities to bypass the deny settings deployed by Deployment Stack. 
The -DenySettingsExcludedPrincipal parameter can be used to perform that. It takes an array or Azure Principal ID. This user or identity will not be subject to limitations.