(Part 4 in a 10-part series)
Yep – as Randall Munroe points out – naming things is very hard, and the defaults that most programs and importers give you don’t really help. As you saw in the last post, creating Bicep files is easy, but creating good Bicep files gets rather difficult.
The main.bicep File
Bicep deployments usually start with a single main.bicep file that coordinates what other components are being deployed. There are a couple of little but significant techniques in my main.bicep files that I like to use, as shown in the following example file.
- Deployment Suffix: Line 29 and 31 create a unique deployment suffix that will be used in the name for each module deploy. That deployment name is shown in the Deployments tab of your Azure Resource Group. If you just use a simple name that doesn’t change, the history will be overwritten each time the deploy is run, but if you have a unique name, each time the process is run it will keep a history.
- Reusable Common Tags: Most organizations have a set of common tags that have to be applied to every resource, and lines 32-35 create those common set of tags so they can be inserted into every resource that is created, making it easier to find and categorized your resources. Once created, those tags can just be passed into the modules (and appended to in the module!) and then your common tags are defined one time in one place.
- Centralized Naming File: Lines 38-46 performs a call out to a resourcenames.bicep template and is one of the keys to proper naming. I’ll explain more in the next paragraph, but for now, just see that the outputs from this module are used as inputs to other modules, as shown in line 52 where it uses resourceNames.output.functionStorageName.
The resourcenames.bicep file is a technique that I’ve started using to put all of my object naming standards in one file. I was inspired to start doing this after seeing a demo from my colleague Jordan Bean who had something very similar to this. I came up with my version of a “resourcenames.bicep” files, and it is the first module that I call in each of my main.bicep files. Having all the names in this one place gives an easy way to change things later if needed, without affecting all the other files.
The main inputs to this module are the appName and the environmentCode, which are then used to create a unique name for all the main resources. I’ve had other combinations of base naming variables in the past, but this simple two-part combination is one that works well for Azure DevOps, “azd” CLI mode, and GitHub Actions, so this is what I’m recommending right now.
These inputs get scrubbed to keep them consistent (lines 12-14), combined into a more complex multi-part base name (lines 19-20), and then those variables are used to create the actual output variables to be used by other templates (lines 23-30).
Storage file names and key vault names (lines 28-30) need some special attention as they can have length limit, must be lower case and don’t allow some characters, so this is a great place to scrub them and make sure a long “appName” doesn’t break the storage file size limits.
Note: This resourcenames.bicep will be unique to each project and is not a good candidate to store in a Bicep Container Registry.
Sharing Info Upon Exiting Each Module
At the end of each module, outputs are set for each of the created resources that may be needed for reference in other modules, like resource Ids and names.
However – a word of warning: don’t use output variables to expose things like a storage key or a database connection string — these outputs are visible in the Azure portal deployment steps, so you will expose those secrets if you do that.
So if you can’t use output variables for secrets, how to do you put a secret in the key vault if you can’t pass it as an output…? Use the output name and/or id to reach back into the resource with the “existing” resource command, and then add it to the vault in a custom module, like this:
I’ve got one of these keyvault*.bicep modules for several common types of resources that need to store keys or connection strings in an Azure Key Vault, including storage account, service bus, signalR, Cosmos, and IoT Hub. The format in each module is just slightly different in how you retrieve the keys.
Next step: Using a Bicep Container Registry