Creating Unique Names for Resources in Bicep

When creating resources on Azure, there are times that the deployment fails due to the name selected for the resource. This is primarily due to the fact that there are some resources that are available as services and exposed to the internet, thus their name should be unique across deployments. 

Take a storage account for example. The name should not only be unique but also in lowercase and under 25 characters! A virtual machine, on the other hand, does not require a unique name (at a global level).
How do we tackle such requirements? The Bicep uniqueString function is here to help.

This particular function takes a number of string parameters and creates a unique string. Combined with scope functions like subscription and resourceGroup, you may generate strings unique to your environment. Other string functions like toLower and substring can be used to make your code even more robust.

Let's dive into some examples!

The below code is part of a bicep file that deploys a storage account:

param storageAccountName string = 'sa'

var storageAccountNameFinal = toLower('${storageAccountName}${uniqueString(resourceGroup().id)}')

We add a unique string to the parameter, in order to form the name for the storage account. In this example, the seed for the generation of the unique string is the id of the resource group we're deploying the resource in. This means that if you deploy this file again, using a different resource group, a different name will be generated.

The below code follows the same approach, but uses the id of the subscription instead:

param storageAccountName string = 'sa'

var storageAccountNameFinal = toLower('${storageAccountName}${uniqueString(subscription().id)}')

In this case, if you try to deploy the same file to a different resource group within the same subscription, the deployment will fail since the generated name will be the same!

To be on the extra-safe side, I suggest using the ids of both the subscription and the resource group:

param storageAccountName string = 'sa'

var storageAccountNameFinal = toLower('${storageAccountName}${uniqueString(subscription().id, resourceGroup().id)}')

Now what about Bicep deployments that are structured in modules, should you configure the unique name in the module or in the top Bicep file? In this case, I'd suggest avoiding the creation of unique names in modules, just to keep them reusable for other deployments. If you decide to create the name in the module, don't forget to use outputs to return the string to the main deployment file, since you may need it in a later step of the process.

There's however another caveat when it comes to modular deployments. The deployment scope for a module may be a resource group that is also created as part of the deployment. In that case, you could use Bicep id functions to get the id of the resource group, but I've found that using the name of the resource group (that you already know of) in combination with the subscription id does the job:

param storageAccountName string = 'sa'

param resourceGroupName string = 'RG'

var storageAccountNameFinal = '${storageAccountName}${uniqueString(subscription().id, rgstorage.name)}'

resource rgstorage 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: resourceGroupName
  location: location
}

The above examples are available in my Github repository over here, as usual! If you deploy all the templates as described in the instructions, you'll end up with a resource group that contains four storage accounts, each with a different name according to the respective deployment:

I hope you'll find them useful!

Popular posts from this blog

Configuring a Certificate on Exchange Receive Connector

Send Syslog Messages from PowerShell

Domain Controller Machine Password Reset