Menu Close

Get a consistent Azure naming convention with Bicep modules

Naming resources has always been a familiar theme in IT and Azure is no different. It pays off to pick a good naming strategy. I recommend looking at the advice provided by the Microsoft Docs. In this post, I’m going to assume you have a naming strategy already. What I want to focus on, is how you can implement this in your infrastructure as code. More specifically, let’s see how we can get a consistent Azure naming convention with Bicep modules

But why?

There are two things difficult about a naming convention: Creating it, and make sure that people stick to it. One way we can aim for a consistent use of the naming strategy, is by making it as easy as possible to use it.

Design your naming convention automation

The first thing we need to do, is make use of variables and Bicep functions (or ARM functions) to get the correct naming convention with the least amount of parameters. To show what I mean, I’m going to work with an example naming convention:

${teamName}-${environmentLetter}-${resourceFunction}-${resourceTypeAbbreviation}-${indexNumber}

This is just an example of giving shape to a naming convention. I recommend spending a good amount of time with your team to consider your own naming convention.

What would be ideal, is to have the different components of the resource name be added as parameters. The template should construct the name itself.
This gives you a lower risk of errors in names and the different components can often be used in tags as well. So how do we accomplish this?

If you look at the file below, this accomplishes this goal. I have added comments to the lines to explain what happens.


So that gives a pretty complete solution for the naming convention. For every resource, you can now name it by using the replace option to change the resource type abbreviation. You can find a list of recommended abbreviations here. In the template, you would look it like this example for a vnet:

vnetName: replace(names.outputs.resourceName, '[PH]', 'vnet')

Creating a naming convention module

The above code can be added at the top of any bicep file. But if you have a big environment and a lot of Bicep templates, that can force you to do a lot of copy-pasting, which we want to avoid.
So what we can do, is create a module that creates the variables we need.
To do this, the only thing we need to do is to create an output for the bicep file, like this:

// Outputs are created to give the results back to the main template
output resourceName string = resourceNamePlaceHolder 
output resourceNameShort string = resourceNameShortPlaceHolder
output storageAccountName string = storageAccountNamePlaceHolder
output vmName string = vmNamePlaceHolder 

 

After we safe this file, we can call it as a module from the main.bicep file

Using the module in your Bicep file

To use the module, we can call it like any other module.

module names 'Modules/NamingConvention.bicep' = {
  name: 'namingconvention'
  params: {
    environment: 'production'
    function: 'website'
    index: 1
    teamName: 'infra'
  }
}

We can either hardcode the values into it or have them be parameters of the main.bicep file.
This module will create outputs we can use, like names.outputs.resourceName for example

There is one limitation. You cannot use this name directly to create a resource. Let’s see what happens if you do that:

You get an error as the name needs to be calculated before the resource can be created.

Fortunately, there is another way to make this work. You won’t have this problem if you use only modules. So you can store the resource you need in a module (and make it easier to reuse, so that is a win-win!).
Below, I have created an example of what the main.bicep file could look like

 

 

This will create the following resources in Azure:

Conclusion

So this is how you can get a consistent Azure naming convention with Bicep modules. As long as your parameters don’t change, this gives you a lot of flexibility combined with a very consistent environment.

Find all the files that I used in this GitHub repository.

Of course, this naming convention is just an example. But I hope this gives you the inspiration to create your own. If you have any questions, leave them in the comments!

12 Comments

  1. Pingback:Azure Top 5 for October 11, 2021 - Jeff Brown Tech

  2. Andre van den Berg

    Hi Barbara

    We are using targetScope = ‘subscription’ in main module en then we must define also scope for the namingconvention module.

    And gives the error you mentioned in you blog with the other modules.

    • Barbara

      Hi Andre,
      I see the error. The less than ideal fix is to add targetScope = 'subscription' to the namingConvention.bicep file. That way it should work. This needs to be hardcoded though, so it might mean you have to keep two naming convention modules on file

  3. Robert Agterhuis

    Hi Barbara,

    Nice post. Some remarks after playing with bicep and your recommendations. I used the Microsoft naming convention abbreviation recommendation for putting together the resources names (all in one bicep file, this file is called as a module at the beginning of the main bicep. If i use your approach then Bicep gives an error because output of params is limited.
    So new approach: Use the Bicep Option: ConfigurationSet output this set as an Object and use this in the module declaration in your main bicep. Also this will reduce the lines of code. If your interested in my approach drop an email and i will send you the source files. ( maybe you can use it in a part 2 blog)

    • Barbara

      Hi Robert,
      This sounds interesting. I haven’t seen that output before, but I would love to see what goes on. I’ve send you an email

    • Barbara

      Yes, Robert showed me the code. What he did is the following:
      If you have to many entries, you create one variable that contains all the other variables. So it will be an object, like this:

      var outputObject = {
      outputvariable1 : 'example1'
      outputvariable2 : 'example2'
      }

      In the main.bicep file, you can call it like this: namesModule.outputs.outputobject.outputvariable1

      Hope that explains it for you. I might go over this in a following blog post. Thanks to Robert for emailing this solution!

  4. Pingback:AWESOME Azure Bicep: GitHub File Free Download

  5. prasant chettri

    Is it similar to configMap or just the object variables assignment? I have been trying to follow the your blog to create DRY module for deploying different type of resources based on the environment selected at the deployment. and I am going with the approach of creating parameter json for each env and if statement in the main module. If that is correct approach.
    Each env will have shared services, core and main deployment

    namesModule.outputs.outputobject.outputvariable1 did not work for me

  6. prasant

    namesModule.outputs.outputobject.outputvariable1 did not work for me but the previous example of output without object notation works file. Are we missing something in ?
    var outputObject = {
    outputvariable1 : ‘example1’
    outputvariable2 : ‘example2’
    }

    In the main.bicep file, you can call it like this: namesModule.outputs.outputobject.outputvariable1

  7. prasant chettri

    Thanks. Both your learnlive videos, articles and git repo, helped me to build DRY parameterized deployment close to terragrunt deployment I have seen with some clients.
    I created separate dev,prod, stage,core parameters file. Used prefix parameter file for azure suffixes and jsconcontent converstion.
    I did struggled to get the naming convention on resource module. Until I noticed that you are passing it on param of resource block which helped me to get over 5 hours of wasted resource.

    Thank you. I am a fan of your detailed and to the point blogs and videos.

    I can deploy for each env based using ps1 file with splat expression and the value that needs to be change on some parameter I can directly pass on @paramter and the value that are not passed gets picked from -parameterfile

  8. prasant chettri

    I am going parameter file for each environment dev, prod, stg and calling respective parameter with the ps1 by changing the -templateparameter and the environment value.

    I am passing index for env, approle and location from the parameter. Intellisense passes.

    Eg for location in the main module passing locationShortName: locationList[locationIndex].locationShortname
    Dev Parameter file

    “locationIndex”: {
    “value”: 1
    }

    locationList”: {
    “value”: [
    {
    “Location”: “westus2”,
    “LocationShortName”: “azw2”
    },
    {
    “Location”: “eastus”,
    “LocationShortName”: “aze”
    },
    {
    “Location”: “westus”,
    “LocationShortName”: “azw”
    },
    {
    “Location”: “centralus”,
    “LocationShortName”: “azc”
    },
    {
    “Location”: “westus3”,
    “LocationShortName”: “azw3”
    }
    ]
    }

    I get –

    The language expression property array index ‘1’ is out of bounds. Even though it should be picking up ‘azw2’for ‘westus2’ shortname on index 1

Leave a Reply

Your email address will not be published. Required fields are marked *