How to deploy Azure Network Manager with Azure Bicep
Tags: azure, bicep, iac
Published: 2022-01-04 20:45:18

Using Azure at a large scale for IaaS solutions like VMs or Machine Scale Set or Kubernetes means using Virtual Networks, a lot of VNETS. But you need to ensure the consistency of all these networks. You will need to add a connection to the central network for new subscriptions and add security layers.

You can use several solutions for that. You can write a PowerShell script to automate the process or an ARM template to deploy the required resources. But one of the problems is, when the infrastructure scale,  updating all the network stack across subscriptions can be very painful.

During the MS Ignite 2021, in November, Microsoft announced the public preview of Azure the Virtual Network Manager resource. this new network tool allows you to automate connectivity and security configuration across several VNETs.

As Virtual Network manager is still in preview, to start using it, you will need to register it in your subscriptions.

```powershell
Register-AzProviderFeature -FeatureName AllowAzureNetworkManager -ProviderNamespace Microsoft.Network
```

You may need to wait a few minutes for the full registration of the feature.
You will also need to update your Azure PowerShell module to use the new cmdlets that come with Virtual Network manager.

```powershell
Install-Module -Name Az.Network -AllowPrerelease -Force
```

Azure Virtual Network Manager allows you to create network topologies and global security rules (similar to NSG) and deploy them to a group of VNETs across your subscriptions.

In a network manager object, you will have configurations:

- Connectivity configuration, the HUB and Spoke model (you will need to provide a HUB VNET with network gateway), or the Mesh model (where every VNETs are inter-connected each other)	
- Security admin configuration, where you define a collection of security rules to be applied to VNETs

These configurations are constructed on networks groups, where you define a group of VNETs, by selecting them one by one or dynamically using their name, a tag, subscriptions, or resource groups.

And finally, you have a deployment object, where you apply configuration against network groups. 

How can we apply configuration as code to deploy and manage using infrastructure as code?

In a single Azure Network Manager, there are several sub-objects; configurations, and networks groups. They are not independent. You need a network group to create a configuration. The last object, deployment object configuration, and network groups together.  

So, we can manage with bicep: 

- The Network manager resource, name, and location
- Connectivity Configurations, name, type, hub VNET, 
- Security configurations, name, and rules collection
- Network groups

The deployment process can’t be managed by Bicep yet.

How can we do it?
First we need to create the network manager object

```
resource netMgr01 'Microsoft.Network/networkManagers@2021-02-01-preview' = {
  name: '02mgr'
  location: resourceGroup().location
  properties: {
    description: 'test azure network manager'
    displayName: 'test netmanager'
    networkManagerScopeAccesses: [
      'Connectivity'
      'SecurityAdmin'
    ]
    networkManagerScopes: {
      managementGroups: [
        '/providers/Microsoft.Management/managementGroups/group01'
      ]
      subscriptions: []
    }
  }
}

```

You need to select a scope, at this time you cannot have several network managers of the same scope (or overlapping scope). Also, the network manager object can not be modified after its creation by Azure Bicep or ARM template.

Before creating any configuration we need to create a network group. A network group is mandatory to create a configuration object. A network group can have a static membership, you manually add VNETs or dynamic membership where you select VNETs by several parameters.
Let’s try to build a static group.
By default we can use this code to create a group

```
resource netMgrGrp 'Microsoft.Network/networkManagers/networkGroups@2021-02-01-preview' = {
  name: '<Network Manager Name>/<Network Group Name>'
  properties: {
    description: groupDescription
    displayName: displayName       
    groupMembers: [
      {
        resourceId: 'VNET Resource ID'
      }
    ]
    memberType: 'static'
  }
}
```

To indicate the name of the Azure Network Manager, you can use the notation 
Parent resource name/Resource Name. But if the network manager resource is present in the same bicep file you can use the parent property:
`parent: parentSymbolicName`
 

With Azure Bicep, you can add, update and remove VNET by using a parameter for groupMembers. It’s an array of resource ID.

```
param listofVnet array

var displayName = 'Hub and spoke group'
var groupDescription = 'Group for Hub and spoke'

resource symbolicname 'Microsoft.Network/networkManagers/networkGroups@2021-02-01-preview' = {
  name: '02mgr/hubspoke-grp'
  properties: {
    description: groupDescription
    displayName: displayName
    groupMembers: listofVnet
    memberType: 'static'
  }
}
```

To deploy:

```powershell
$groupparam = @( 
    @{
        "resourceId" = "resourceID"
    }
)

New-AzResourceGroupDeployment -ResourceGroupName "01-netmgr" -TemplateFile ./groups.bicep -listofVnet $groupparam
```

To manage dynamically group membership, we can add several VNETs in $groupParam PowerShell variable.

```powershell
$groupparam = @( 
    @{
        "resourceId" = "ID vnet 1"
    }
    @{
        "resourceId" = "ID vnet 2"
    }
    @{
        "resourceId" = "ID vnet 3"
    }
)
```

To deploy the bicep template, you will need to use the new-AzResourceGroupDeployment PowerShell cmdlet with the groupparam variable.

```powershell
New-AzResourceGroupDeployment -ResourceGroupName "01-netmgr" -TemplateFile ./groups.bicep -listofVnet $groupparam
```

To remove one VNET, simply remove its ResourceID from the variable 

```powershell
$groupparam = @( 
    @{
        "resourceId" = "ID vnet 1"
    }
    @{
        "resourceId" = "ID vnet 3"
    }
)
```

And re-run 

```powershell
New-AzResourceGroupDeployment -ResourceGroupName "01-netmgr" -TemplateFile ./groups.bicep -listofVnet $groupparam
```

The group will be updated according to the $groupparam parameter.

With this network group, It’s now possible to create a network configuration. The Network Manager configuration will need the group ID. 
To form the network group ID
`/subscriptions/<SsubscriptioinID>/resourceGroups/<ResourceGroupName>/providers/microsoft.network/networkManagers/<NetworkManagerName>/networkGroups/<NetworkGroupName>`

The simplest one is a Mesh configuration, where all VNETs are connected to each other by peering. In this configuration, you just need to give, at least, one network group ID, like this.

```
param networkGroupId  string 

resource hubAndSpoke 'Microsoft.Network/networkManagers/connectivityConfigurations@2021-02-01-preview' = {
  name: '02mgr/meshconfig'

  properties: {
    appliesToGroups: [
      {
        isGlobal: 'True'
        groupConnectivity: 'DirectlyConnected'
        useHubGateway: 'False'
        networkGroupId: networkGroupId
      }
    ]
    deleteExistingPeering: 'True'
    description: 'default Mesh configuratioon'
    displayName: 'Default Mesh'
    connectivityTopology: 'Mesh'
    isGlobal: 'False'
  }
}
```

Now that we have both our network group and our network configuration, we can deploy it. For that, we need to use the latest version of the Azure PowerShell module, and the Deploy-AzNetworkManagerCommit cmdlet. 

You will need to import the pre-release version of the Az.Network module.

```powershell
Install-Module -Name Az.Network -RequiredVersion 4.12.1-preview -AllowPrerelease
And then import it to your PowerShell session.
Import-Module -Name Az.Network -RequiredVersion '4.12.1'
```

To start a deployment you will need to provide target regions and the target configurationID. Via the -TargetLocation and the -ConfigurationID parameters. These parameters only accept System.Collections.Generic.List.

For regions, we can use regions name like NorthEurope or WestUs like this

```powershell
[System.Collections.Generic.List[string]]$TargetRegions = @()   
$TargetRegions.Add("NorthEurope")   
$TargetRegions.Add("WestEurope")
```
  
For configuration, we need the ID from our last connectivity configuration. Like the network group ID the configuration ID is formed like this

```powershell
$connectivityConfigurationId =”/subscriptions/<SsubscriptioinID>/resourceGroups/<ResourceGroupName>/providers/microsoft.network/networkManagers/<NetworkManagerName>/connectivityConfigurations/<ConfigurationName>”

[System.Collections.Generic.List[string]]$ConfigCollection = @()  
$ConfigCollection.add($connectivityConfigurationId)
```

To deploy the configuration 

```powershell
Deploy-AzNetworkManagerCommit -Name <NameOfTheNetworkMqnqger> -ResourceGroupName <ResouurceGroupName> -TargetLocation $TargetRegions -ConfigurationId $ ConfigCollection -CommitType 'Connectivity'
```
 
Connectivity configuration is not the only thing you can do with Azure Network manager. You can also centralize network security rules. These rules will have a higher priority than the NSG rules associated with a subnet. It can be useful to enforce security like blocking RDP or SSH access from the Internet even if someone changes the local NSG rules.

Creating a security configuration start with a security admin configuration:

```
  resource ssecuconfig 'Microsoft.Network/networkManagers/securityAdminConfigurations@2021-02-01-preview' = {
    name: '02mgr/hubspoke-ssecu'

    properties: {
      deleteExistingNSGs: 'True'
      description: 'secuity config for hub'
      displayName: 'hub-security'
      securityType: 'AdminPolicy'
    }
  }
```

You will need a name, a display name, and a description. The security type can be AdminPolicy or UserPolicy, deleteExistingNSGs let you flag to delete NSG if you want to replace them with security rules.
Security configuration has the network manager object as a parent, so you will need to use the form parentresourceName/SubResourceName

We can now build a collection rule. A collection rule is a container of security rules associated with et network group.

```
  resource symbolicname 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections@2021-02-01-preview' = {
    name: '02mgr/hubspoke-ssecu/rulecollection01'
    properties: {
      appliesToGroups: [
        {
          networkGroupId: networkGroupId
        }
      ]
      description: 'rules collectiion 01'
      displayName: 'rules collection 01'
    }
  }
```

To indicate to Azure Bicep, the parent resource, you will need to use the form Network Manager Name/Security Configuration name/Rule Collection Name

We can now add a rule to the rule collection object.

Security rules are similar to NSG rules and use the same semantic.
Note that you will need to use Name/Security Configuration name/Rule Collection Name/rule name to link the rule to the network manager.

We need to deploy the security configuration. The deployment process is the same as in the connectivity configuration deployment. 
The first operation is to create a generic list of the target azure location.

```powershell
[System.Collections.Generic.List[string]]$TargetRegions = @()   
$TargetRegions.Add("NorthEurope")   
$TargetRegions.Add("WestEurope") 
```

Then a generic list for the list of security configurations we want to deploy

```powershell
$securityConfigurationId = '/subscriptions/<SubscriptiionID>/resourceGroups/<ResourceGroupName>/providers/microsoft.network/networkManagers/02mgr/securityAdminConfigurations/hubspoke-ssecu'
[System.Collections.Generic.List[string]]$ConfigCollection = @()  
$ConfigCollection.add($securityConfigurationId)
```
 

Then we can deploy our security configuration with the Deploy-AzNetworkManagerCommit cmdlet

```powershell
Deploy-AzNetworkManagerCommit -Name 02mgr -ResourceGroupName "01-netmgr" -TargetLocation $TargetRegions -ConfigurationId $ConfigCollection -CommitType 'SecurityAdmin'
```