Azure resource governance with project Bicep and Template Specs

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.

Azure resource governance with project Bicep and Template Specs schema

The process:

  1. Platform team plans what has to be provisioned.
  2. Platform team creates IaC templates to provision cloud resources (exact list of resources depends on the nature of the application / system).
  3. Repo is a central place for template sources that the platform team uses.
  4. Pipeline runs to validate new version of the template and publishes it to Template spec.
  5. Consumer (in this case Team Blue) passes parameters and provisions resource using Template spec.
  6. 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.

├── README.md
├── consumer-team-blue
│   ├── parameters-team-blue.json
│   └── provision.sh
├── template-spec-arm
└── template-spec-bicep
    ├── deploy-templates.sh
    └── 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:

Azure Template Spec resource

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).

@minLength(5)
@maxLength(50)
@description('Name of the azure container registry (must be globally unique)')
param acrName string

@description('Enable an admin user that has push/pull permission to the registry.')
param acrAdminUserEnabled bool = false

@description('Location for all resources.')
param location string = resourceGroup().location

@allowed([
  'Basic'
  'Standard'
  'Premium'
])
@description('Tier of your Azure Container Registry.')
param acrSku string = 'Basic'

// azure container registry
resource acr 'Microsoft.ContainerRegistry/registries@2019-12-01-preview' = {
  name: acrName
  location: location
  tags: {
    displayName: 'Container Registry'
    'container.registry': acrName
  }
  sku: {
    name: acrSku
  }
  properties: {
    adminUserEnabled: acrAdminUserEnabled
  }
}

output 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.

#!/bin/bash

export TEMPLATE_SPEC="WeekendSprints-TemplateSpec-ACR"
export TEMPLATE_SPEC_DISPLAY_NAME="Weekend Sprints Template Spec ACR"
export TEMPLATE_SPEC_DESCRIPTION="Weekends Sprints Template Spec ACR Basic tier"
export RESOURCE_GROUP="WeekendSprints-TemplateSpec-RG"
export LOCATION="westeurope"
export VERSION="1.0.0"

echo "Deploying template spec to ... "
echo "Resource group:   $RESOURCE_GROUP"
echo "Location:         $LOCATION"
echo "Version:          $VERSION"

az group create -n $RESOURCE_GROUP -l $LOCATION

echo "Resource group $RESOURCE_GROUP has been created/updated"

az ts create \
    --name $TEMPLATE_SPEC \
    --display-name "$TEMPLATE_SPEC_DISPLAY_NAME" \
    --description "$TEMPLATE_SPEC_DESCRIPTION" \
    --version $VERSION \
    --tags BU=Finance Environment=Production \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION \
    --template-file "./main.bicep" \
    --yes \
    --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.

Azure Portal - Template Spec

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

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
      "acrName":{
          "value": "pardus"
      },
      "acrSku": {
          "value": "Standard"
      }
    }
  }

and consume like this:

#!/bin/bash
echo "Provisioning environments..."

RESOURCE_GROUP="TeamBlue-RG"
LOCATION="northeurope"
TS_RG="WeekendSprints-TemplateSpec-RG"
TS_NAME="WeekendSprints-TemplateSpec-ACR"
VERSION="1.0.0"

RGP=$(az group create -l $LOCATION -n $RESOURCE_GROUP)
echo "Resource group $RESOURCE_GROUP has been created/updated"

ACR_TS_ID=$(az ts show --resource-group $TS_RG --name $TS_NAME --version $VERSION --query 'id' -o json)

az deployment group what-if \
  --resource-group $RESOURCE_GROUP \
  --template-spec $ACR_TS_ID \
  --parameters "./parameters-team-blue.json"

az deployment group validate \
  --resource-group $RESOURCE_GROUP \
  --template-spec $ACR_TS_ID \
  --parameters "./parameters-team-blue.json"

az deployment group create \
  --resource-group $RESOURCE_GROUP \
  --template-spec $ACR_TS_ID \
  --parameters "./parameters-team-blue.json"

There it is:

Azure portal - ACR Azure portal - ACR deployment

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! 💪

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