Azure Bicep – Tagging Policies

With the recent v0.3 release of Azure Bicep, the language is maturing and becoming a powerful language for declaratively deploying resources to Azure. As of v0.3, it’s fully supported by Microsoft, and they’re rapidly releasing new features and improvements. The 0.4 version of Bicep is estimated to arrive at Microsoft Build, with many exciting new capabilities — including referencing external modules, indexed loops and more.

I’ve created a couple of Azure Policies in Bicep to discover and learn the capabilities of this language, all of which are available in this repository.

The modules consist of three main components; the definition itself, the assignments, and the role assignments for the SystemAssigned identity (if the policy requires permissions to resources).

A Bicep module is a .bicep-file which can be referenced to by another .bicep-file within the same repository. A module starts with defining the parameters which is expected from the consumer of the module (optionally with a default value), and then continues describing the resources.

A policy definition in Bicep is fairly similar to a policy definition in an ARM template, slightly prettified. The example below has the policyRule omitted; the repository has the entire code.

resource inheritTagRG_PolicyDef 'Microsoft.Authorization/policyDefinitions@2020-09-01' = {
  name: 'inherit-tag-from-rg'
  properties: {
    displayName: 'Inherit a tag from the resource group if missing'
    policyType: 'Custom'
    mode: 'Indexed'
    description: ''
    parameters: {
      tagName: {
        type: 'String'
        metadata: {}
      }
    }
    metadata: {}
    policyRule: {}
  }
}

One of the neat features in the latest version of Bicep, is the ability to loop, which is a lot easier to implement in Bicep than with ARM Templates. The above policy definition requires an assignment for every tag, which would be exhausting to implement manually in the portal or by describing each individual assignment with code. Loops in Bicep function like for-each loops, enabling you to loop through an array referencing the respective individual element each iteration.

resource inheritTagsFromRG_policyAssignments 'Microsoft.Authorization/policyAssignments@2020-09-01' = [for name in tagNames: {
  name: 'inheritTag-${name}-FromRG'
  properties: {
    policyDefinitionId: inheritTagRG_PolicyDef.id
    displayName: 'Inherit tag "${name}" from RG'
    parameters: {
      tagName: {
        value: '${name}'
      }
    }
  }
  location: 'norwayeast'
  identity: {
    type: 'SystemAssigned'
  }  
}]

The role assignments required for each policy assignment can also be created using loops, since Bicep supports referencing an individual object created by a loop with an index. If I wanted to reference the first object created by the loop above, I’d reference inheritTagsFromRG_policyAssignments[0]. To achieve this using loops, create a loop iterating as many times as there are elements in the array, which is calculated by the range between 0 and the length of the array.

resource inheritTagsFromRG_roleAssignments 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = [for i in range(0, length(tagNames)): {
  name: guid('contributor ${inheritTagsFromRG_policyAssignments[i].name}', subscription().subscriptionId)
  properties: {
    roleDefinitionId: contrib_roleDef.id
    principalId: inheritTagsFromRG_policyAssignments[i].identity.principalId
  }
}]

To learn more about Bicep, I really recommend their repository. In particular, the docs and the language spec.

Leave a Reply

Your email address will not be published.