How to share modules with Azure Bicep
Tags: azure, bicep, iac
Published: 2022-01-25 20:49:12

Modules in Bicep is a feature that offers you the possibility to reuse a portion of bicep codes inside another Bicep file. Modules allow you to simplify your deployments by reusing things you often deploy. Thinks about spoke VNETs, NSG, monitoring solutions, things that do not change and are always included in most deployments.  
For example, a VNET is a common component used in most IaaS deployments. It takes a name, one or several prefixes, and a collection of subnets. 

Creating a Bicep module is simple. You just need to create a bicep file with parameters and resources. Like for any other Bicep file.

A module for creating a VNET look like this:

```
param vnetNaame string
param vvnetPreffix array
param subnets array

resource vnet 'Microsoft.Network/virtualNetworks@2020-06-01' = {
  name: vnetNaame
  location: resourceGroup().location
  properties: {
    addressSpace: {
      addressPrefixes: vvnetPreffix
    }
    subnets: subnets
  }
}

output id string = vnet.id
```

note that the file output the VNET ID, which will be useful to connect a virtual nic or another network object.

Using the module is simple, you need to use the module resource. It works like any other resource, with a symbolic name, but instead of using the resource type and the API version, you need to provide the path of the module file. 
You will need to give a name property that will be used in the Microsoft.Resources/deployments. 
You can also use the scope you want, deploying module resources in another resource group.

```
module vnet01 'vnet.bicep' = {
  name: vnetdeploy
  params: {
    subnets: [
      {
        name: 'subnet1'
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      } 
      {
        name: 'subnet2'
        properties: {
          addressPrefix: '10.0.1.0/24'
        }
      }
    ]
    vnetNaame: 'vnet01'
    vvnetPreffix:  [
      '172.24.0.0/24'
      '10.0.0.0/22'
    ]
  }
}
``` 

You may need to use the VNET ID in other resources in the main bicep file. You can use the resource name, vnet01, to get the output of the module, the event ID, vnet01.outputs.id

Our module is only on the local file system. If we want to share it, the process can be complex. Users will need to download it from a central location. It will be hard to enforce the version you need. Users will need to download the file, which limits any automation process.

Fortunately, Bicep modules can be consumed automatically from a remote location using TemplateSpec or Azure registry.

With Azure Bicep you have two possibilities, using an Azure Container Registry or using Azure Template Spec.

To publish a module to a registry you need an Azure Container Registry. You will need a dedicated one. 
To create a registry you can use this Bicep configuration.

```@minLength(5)
@maxLength(40)
@description('Provide a globally unique name of the Azure Container Registry for Bicep modules')
param acrName string = 'bicepmodule${uniqueString(resourceGroup().id)}'

param location string = resourceGroup().location
param acrSku string = 'Basic'

resource acrResource 'Microsoft.ContainerRegistry/registries@2021-06-01-preview' = {
  name: acrName
  location: location
  sku: {
    name: acrSku
  }
  properties: {
    adminUserEnabled: false
  }
}

output loginServer string = acrResource.properties.loginServer
```
To deploy the container registry 

```powershell
New-AzResourceGroupDeployment -ResourceGroupName 01-bicepmodule -TemplateFile ./acr.bicep
``` 

After the deployment of the template, the output will give you the login server that will be used to publish and use modules from the container registry.

To publish a module, users must at least have the Push permission on the container registry, to use a module from the container registry, users must have, at least the Pull permission.

Publishing a module can be done by using the  Publish-AzBicepModule cmdlet


**`Publish-AzBicepModule -FilePath <Local module file path> -Target br:<login server>/<registry path>/<module name>:<version tag>`**

```powershell
Publish-AzBicepModule -FilePath ./vnet.bicep -Target br:bicepmoduleask3vdc2rys.azurecr.io/bicep/network/vnet:v0.1
```

The path in the registry should follow a logical convention for a better understanding. For example, Network for all modules related to network in Azure.

To use the module in a deployment, users must have the Pull privilege to the target container registry.
In a bicep file, to target the registry in the Bicep deployment file you need the “br:” prefix followed by the login server of the registry, the path of the module, the module name, and the version tag. 

```
module vnet01 'br:bicepmoduleask3vdc2rys.azurecr.io/bicep/modules/vnet:v0.1' = {
  name: 'vnetdeploy'
  params: {
    subnets: [
      {
        name: 'subnet1'
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      } 
      {
        name: 'subnet2'
        properties: {
          addressPrefix: '10.0.1.0/24'
        }
      }
    ]
    vnetNaame: 'vnet01'
    vvnetPreffix:  [
      '172.24.0.0/24'
      '10.0.0.0/22'
    ]
  }
}
```

You can also use Azure Template Spec for storing modules. To have an overview of Azure Template Spec, you can read [this post]( https://dev.to/omiossec/automate-azure-templatespec-deployment-and-update-19n8). 

To deploy with template spec instead of using the **`br:<login server>/<registry path>/<module name>:<version tag>`** you will need to use the **`ts:<Subscription ID of the Template Spec>/<Resource Group Name>/<Template Spec Name>:<version>`** 

You can simplify the deployment and avoid using long and complex identifiers by using an alias for both Container Registry and Template Spec.  An alias will replace the login server for container registry and subscription ID and Resource Group for Template Spec. 

To create these alias, you will need to create a bicepconfig.json file in the same directory of your bicep file. 

```json
{
    "moduleAliases": {
      "br": {
        "NetModule": {
          "registry": "bicepmoduleask3vdc2rys.azurecr.io"
        }
      },
      "ts": {
        "CoreModule": {
          "subscription": "00000000-0000-0000-0000-000000000000",
          "resourceGroup": "coreTemplateSpec"
        }
      }
    }
  }
```

For Container registry 

**`module myVnet 'br/NetModule:bicep//bicep/modules/vnet:v0.1= {}`**

For Template Spec 

**`module stgModule  'ts/CoreModule:vnet:v1' = {}`**