How to govern Azure Bicep with template specs?
Azure DevOps Infrastructure-as-code Azure Bicep 💪
Table of contents:
Last week I was setting up a static web site using Azure DevOps and Bicep consuming templates from git. This approach might not be the best option for a large environment with multiple teams as we’ll run into several challenges trying to share and (re)use the templates. Fortunately, Microsoft has a better place for the template. It’s called Azure Resource Manager template specs, which is a regular resource with type Microsoft.Resources/templateSpecs
that has several benefits including ability to store templates with different versions (both ARM and Bicep are supported), manage access through Azure RBAC, template’s consumer does not need full access to it and can deploy resource just passing parameters.
The process:
- Platform team plans what has to be provisioned.
- Platform team creates IaC templates to provision cloud resources (exact list of resources depends on the nature of the application / system).
- Repo is a central place for template sources that the platform team uses.
- Pipeline runs to validate new version of the template and publishes it to Template spec.
- Consumer (in this case Team Blue) passes parameters and provisions resource using Template spec.
- Consumer provides feedback to the platform team (i.e. template has to be extended with additional parameters or new modules has to be added) and the process begins another round.
In this repo I have some code for both parties: platform team and consumer team.
1├── README.md
2├── consumer-team-blue
3│ ├── parameters-team-blue.json
4│ └── provision.sh
5├── template-spec-arm
6└── template-spec-bicep
7 ├── deploy-templates.sh
8 └── main.bicep
Publish Template Spec #
As I’ve mentioned, Azure Template Spec is just a regular resource, we can also see it in the Azure Portal like below:
I am going to use the ACR resource as an example (this is defined in my main.bicep
, see below). It requires only acrName
and acrSku
as entry parameters (also acrSku
as default value Basic
in case if this parameter has not been passed).
1@minLength(5)
2@maxLength(50)
3@description('Name of the azure container registry (must be globally unique)')
4param acrName string
5
6@description('Enable an admin user that has push/pull permission to the registry.')
7param acrAdminUserEnabled bool = false
8
9@description('Location for all resources.')
10param location string = resourceGroup().location
11
12@allowed([
13 'Basic'
14 'Standard'
15 'Premium'
16])
17@description('Tier of your Azure Container Registry.')
18param acrSku string = 'Basic'
19
20// azure container registry
21resource acr 'Microsoft.ContainerRegistry/registries@2019-12-01-preview' = {
22 name: acrName
23 location: location
24 tags: {
25 displayName: 'Container Registry'
26 'container.registry': acrName
27 }
28 sku: {
29 name: acrSku
30 }
31 properties: {
32 adminUserEnabled: acrAdminUserEnabled
33 }
34}
35
36output acrLoginServer string = acr.properties.loginServer
Now what we want to do is validate it and if it’s okay - publish. This is how I publish the template to the Spec.
1#!/bin/bash
2
3export TEMPLATE_SPEC="WeekendSprints-TemplateSpec-ACR"
4export TEMPLATE_SPEC_DISPLAY_NAME="Weekend Sprints Template Spec ACR"
5export TEMPLATE_SPEC_DESCRIPTION="Weekends Sprints Template Spec ACR Basic tier"
6export RESOURCE_GROUP="WeekendSprints-TemplateSpec-RG"
7export LOCATION="westeurope"
8export VERSION="1.0.0"
9
10echo "Deploying template spec to ... "
11echo "Resource group: $RESOURCE_GROUP"
12echo "Location: $LOCATION"
13echo "Version: $VERSION"
14
15az group create -n $RESOURCE_GROUP -l $LOCATION
16
17echo "Resource group $RESOURCE_GROUP has been created/updated"
18
19az ts create \
20 --name $TEMPLATE_SPEC \
21 --display-name "$TEMPLATE_SPEC_DISPLAY_NAME" \
22 --description "$TEMPLATE_SPEC_DESCRIPTION" \
23 --version $VERSION \
24 --tags BU=Finance Environment=Production \
25 --resource-group $RESOURCE_GROUP \
26 --location $LOCATION \
27 --template-file "./main.bicep" \
28 --yes \
29 --query 'id' -o json
While doing this in unattended way (pipeline/action) we can prepend validation task az deployment group validate ...
to fail the step in case of errors in the template or lack of parameters as I explained in the previous post.
Now via Access Control (IAM) we can define who can access the template (builtin Reader
role should be sufficient to consume it). We can deploy this via the portal as highlighted on the picture above, but we would like a better process). Let’s take a look at the consumer’s part.
Consume Template Spec #
As it has been said earlier a consumer needs to supply two parameters. One of the option to do so is to define parameters in the file
1{
2 "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
3 "contentVersion": "1.0.0.0",
4 "parameters": {
5 "acrName":{
6 "value": "pardus"
7 },
8 "acrSku": {
9 "value": "Standard"
10 }
11 }
12 }
and consume like this:
1#!/bin/bash
2echo "Provisioning environments..."
3
4RESOURCE_GROUP="TeamBlue-RG"
5LOCATION="northeurope"
6TS_RG="WeekendSprints-TemplateSpec-RG"
7TS_NAME="WeekendSprints-TemplateSpec-ACR"
8VERSION="1.0.0"
9
10RGP=$(az group create -l $LOCATION -n $RESOURCE_GROUP)
11echo "Resource group $RESOURCE_GROUP has been created/updated"
12
13ACR_TS_ID=$(az ts show --resource-group $TS_RG --name $TS_NAME --version $VERSION --query 'id' -o json)
14
15az deployment group what-if \
16 --resource-group $RESOURCE_GROUP \
17 --template-spec $ACR_TS_ID \
18 --parameters "./parameters-team-blue.json"
19
20az deployment group validate \
21 --resource-group $RESOURCE_GROUP \
22 --template-spec $ACR_TS_ID \
23 --parameters "./parameters-team-blue.json"
24
25az deployment group create \
26 --resource-group $RESOURCE_GROUP \
27 --template-spec $ACR_TS_ID \
28 --parameters "./parameters-team-blue.json"
There it is:
Alternatively a parameter can be passed via environment variable and defined in AZ CLI like explained here.
Do you have similar process in place? I would love to hear from you in the comments below. Thank you for reading! 💪