8 tricks for parameters in Azure Bicep deployments

These tips and tricks offer valuable insights on how to effectively manage and utilize input parameters during Azure Bicep deployment.

Use .bicepparam File Format

The Azure Bicep has introduced support for a new file format called .bicepparam starting from version v0.18.4. This format is used to pass parameters into Bicep templates.

The syntax of this new file format is simpler and is more readable than the previous JSON schema type used for ARM deployments.

Example:

1
2
3
4
5
6
7
//enables IntelliCode in VSCode to suggest and validate parameters against bicep template
using './file.bicep'

//parameters
param location = 'westeurope'
param param1 = 'value1'
param param2 = 'value2'

Use sys. Functions In Parameters Files

The .bicepparam file also allows the use of functions from the sys namespace, such as concat(), first(), and uniqueString(). These functions can be used to manipulate and process the parameters passed into Bicep templates.

Example:

1
2
3
param rgName = 'my-awesome-rg'
param uniqueSuffix = '${sys.uniqueString(rgName)}'
param storageName = 'storage${sys.uniqueString(uniqueSuffix)}'

This can help you to simplify your Bicep templates and remove additional parameter transformations inside the template.

Consolidate Parameters In One Place

One property I find frustrating when deploying via Bicep/ARM is that certain parameters, such as rgName and location, must be in some cases specified as extra arguments for the az command during execution, while the rest of the parameters are contained in a .bicepparam or .json parameters file.

Instead of that, I do prefer to have all customization options for the current deployment in the parameter file in one place and make no change to script executing az command.

In a ARM JSON Parameters Files

My trick to consolidate ARM JSON parameters into one place is based on reading the JSON file before the deployment command, and storing the value into variable in script.

For Scripts Based On PowerShell:

1
(Get-Content mytemplate.parameters.json -Raw | ConvertFrom-Json).parameters.resourceGroupName

For Scripts Based On az-cli (with bash):

I do recommend to use jq tool for reading a JSON file from command line. You can install the jq via multiple ways, one of them is via pip, on Ubuntu as official package:

1
sudo apt-get update && sudo apt-get install jq

on MacOS via Homebrew:

1
brew install jq

When you have jq command ready, you can access the parameter easily:

1
jq .parameters.resourceGroupName.value mytemplate.parameters.json

In .bicepparam Files

The .bicepparam is a new file format, and as such, it can be more challenging to parse the file using other tools. One of the option could be to implement custom parser, but that’s too much complicated for such small task.

As the simpliest way I do prefer to install a full Bicep cli.

Note

The Bicep cli, included in az-cli with commands az bicep, doesn’t contain all Bicep’s commands as in full Bicep cli.

With this full Bicep cli installed, you can compile input .bicepparam into ARM JSON format, which can be easily parsed with the jq tool.

1
2
paramsInJson=`bicep build-params $parametersFilename --stdout  | jq -r ".parametersJson"`
resourceGroupName=`echo $paramsInJson | jq -r ".parameters.resourceGroupName.value"`

Pass A Parameter With Dynamic Value

Occasionally, it may be necessary to include a dynamic variable as a parameter during Bicep deployment, which can be sourced from an environment variable or retrieved as output from another REST API. But how to pass into the template?

ARM JSON Parameters

When you use a Bicep deployment with the original ARM JSON parameters file format, there is a option to override the parameter in the parameters file, with passing addditional --parameters argument in key=value format.

1
2
3
4
5
6
az deployment group create \
  --name myDeployment \
  --resource-group rg-bicep \
  --template-file main.bicep \
  --parameters @main.parameters.json \
  --parameters myParameter='$bashVariable'

The myParameter value in JSON parameters files will be overwritten with one in argument.

Note

You can notice the parameters filename starts with @, in .bicepparam is without this character.

Bicep .bicepparam Files

At the time this article was written, the current version of az-cli does not support the use of a .bicepparam file with this trick. The way the .bicepparam file is parsed is different, and attempting to use the --parameters argument results in an error:

1
2
3
4
5
6
7
8
$ az deployment group create \
  --name myDeployment \
  --resource-group rg-bicep \
  --template-file main.bicep \
  --parameters main.bicepparam \
  --parameters myParameter='$bashVariable'

ERROR: Can not use --parameters argument more than once when using a .bicepparam file

According to some comments found in the Azure Bicep project on GitHub, there are plans to change the behavior and enable overwriting parameters using the syntax --parameters main.bicepparam param1=localvalue, but there is no timeline for this change.

My current workaround around this limitation is based again on the bicep build-params command:

  1. compile the .bicepparam file into temp JSON file
  2. modify the temp JSON file (replace)
  3. provide the temp JSON file as a parameter file to az-cli
  4. delete the temp JSON

Pass Current IP Address

A specific scenario I want to demonstrate is how to restrict access to my current public IP address. Although I am not a fan of using IP-based restrictions, I use them often in my temporary PoCs.

To achieve this, I use the above trick in combination with retrieving my IP address from an external service such as http://ifconfig.me:

1
myIpAddress=`curl ifconfig.me 2> /dev/null`

In the .bicepparam file, I create a unique placeholder value (e.g., $myIpAddress), compile into into ARM parameters JSON file and replace it there using the traditional sed command, before it gets processed by deployment command:

1
(...) | sed "s/\$myIpAddress/$myIpAddress/" > temp.json

Use secure() Attribute

Do not forget to annotate all sensitive Bicep parameters with attribute secure(). This decorator prevents to include the value of the parameter into logs and deployment history.

1
2
@secure()
param vmAdminPassword string

Also with this attribute applied, you can integrate Azure Key Vault and store these secrets within Key Vault, and access them during the deployment from Bicep template directly.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
  name: kvName
  scope: resourceGroup(subscriptionId, kvResourceGroup )
}

module sql './sql.bicep' = {
  name: 'deploySQL'
  params: {
    sqlServerName: sqlServerName
    adminLogin: adminLogin
    adminPassword: keyVault.getSecret('vmAdminPassword')
  }
}


// sql.bicep:

@secure()
param adminPassword string

resource sqlServer 'Microsoft.Sql/servers@2022-08-01-preview' = {
  ...
}

Markdown Description

When working with a complex Bicep template, it can be useful to include more complex instructions on how to use specific parameters. This can be done by adding a user guide within the @description() decorator in Markdown language, which will then be displayed in IntelliSense completion. This can help users understand how to use the parameter and make it easier for them to work with the template.

1
2
3
4
5
6
7

@description('''
Here can be a *markdown-enabled* text, displayed in **IntelliSense** in VSCode 
1. something A
1. something B
''')
param subnetName string

example of Bicep parameter with markdown syntax in VSCode

Using a Single Parameter File for Multiple Bicep Templates

If you have a complex project that consists of multiple Bicep templates, you may need to use the same parameters across several templates. For example, you may need to use the same common Resource Group name in multiple templates.

However, in Bicep, the parameter file must only contain parameters that are relevant to the specific template it is associated with. This means that if a parameter is only used in templateA.bicep, it cannot be included in the parameter file for templateB.bicep.

1
Error BCP259: The parameter "templateBParameter" is assigned in the params file without being declared in the Bicep file.

One workaround for this issue is to include the extra parameters in the other template, but assign them default values and provide an explanation in the description() decorator, that these parameters are not used in that particular template.

Example:

1
2
3
4
5
@description('common parameter used in both templates')
param commonParameterA string

@description('NOT USED in this template')
param templateBParameter string = ''

This allows you to include the same parameters in multiple templates without causing any issues and minimizes confusion of another user of given template.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy