Azure Bicep and MS Graph - a long awaited collaboration

Azure Bicep and MS Graph - a long awaited collaboration
Borrowed image from announcement: https://techcommunity.microsoft.com/t5/azure-governance-and-management/announcing-public-preview-of-bicep-templates-support-for/ba-p/4141772

Introduction

For a long time one of the major shortcomings in my opinion working with Azure Bicep has been its lack of ability to create simpler things like Entra ID groups and service principals, hence I use Terraform for 99% of my deployments.

Not being able to create Entra ID groups for example forces one to complement your IaC scripts with Powershell or CLI scripts. It would be preferable to have the ability to work in the same confguration files and context and not require more languages and tools.

Well, now we should be able to with the new announcement of Bicep Templates for MS graph, you can find the post from Microsoft here if you want to read it straight from the source.

Bicep templates for Microsoft Graph resources allows you to define groups or applications and deploy them along with your other resources using Infrastructure as Code.

Until now, you had to orchestrate your deployments between two mechanisms using ARM or Bicep template files for Azure resources and Microsoft Graph PowerShell for Microsoft Entra ID resources - this is hopefully no longer the case.

Install the VS code extension

Some setup first. Ensure you have installed the VS Code extension to get help with intellisense and authoring when writing your Bicep configuration files.

Setup your workspace

I will have a Github repository here where you can clone a finished product but if you want to experiment yourself you need to create two files, a main.bicep and a bicepconfig.json - we need the last one to enable the feature.

Github Repository

GitHub - carlzxc71/azure-bicep-ms-graph-lab: This is a repository that contains source-code for a blogpost created on Lindbergtech about creating Entra Groups with Azure Bicep which is a preview feature
This is a repository that contains source-code for a blogpost created on Lindbergtech about creating Entra Groups with Azure Bicep which is a preview feature - carlzxc71/azure-bicep-ms-graph-lab

Incase you are deploying manually and not cloning the repo

Create and add the following code to a file called main.bicep

targetScope = 'subscription'

provider microsoftGraph

resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: 'rg-prod-sc-bicep'
  location: 'swedencentral'
}

// Reader role assignment

resource entraGroupReader 'Microsoft.Graph/groups@v1.0' = {
  displayName: 'sec-rg-prod-sc-bicep-reader'
  mailEnabled: false
  mailNickname: 'sec-rg-prod-sc-bicep-reader'
  securityEnabled: true
  uniqueName: 'sec-rg-prod-sc-bicep-reader'
}

module readerRoleAssignment 'modules/roleAssignmentReader.bicep' = {
  name: 'readerRoleAssignment'
  scope: resourceGroup
  params: {
    principalId : entraGroupReader.id
    roleDefinitionId: 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader role definition ID
  }
}

// Contributor role assignment

resource entraGroupContributor 'Microsoft.Graph/groups@v1.0' = {
  displayName: 'sec-rg-prod-sc-bicep-contributor'
  mailEnabled: false
  mailNickname: 'sec-rg-prod-sc-bicep-contributor'
  securityEnabled: true
  uniqueName: 'sec-rg-prod-sc-bicep-contributor'
}

module contributorRoleAssignment 'modules/roleAssignmentContributor.bicep' = {
  name: 'contributorRoleAssignment'
  scope: resourceGroup
  params: {
    principalId : entraGroupContributor.id
    roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor role definition ID
  }
}

// Owner role assignment

resource entraGroupOwner 'Microsoft.Graph/groups@v1.0' = {
  displayName: 'sec-rg-prod-sc-bicep-owner'
  mailEnabled: false
  mailNickname: 'sec-rg-prod-sc-bicep-owner'
  securityEnabled: true
  uniqueName: 'sec-rg-prod-sc-bicep-owner'
}

module ownerRoleAssignment 'modules/roleAssignmentOwner.bicep' = {
  name: 'ownerRoleAssignment'
  scope: resourceGroup
  params: {
    principalId : entraGroupOwner.id
    roleDefinitionId: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role definition ID
  }
}

Add the following code to your JSON config file called bicepconfig.json

{
    "experimentalFeaturesEnabled": {
        "extensibility": true
    }
}

There are some issues here with assigning permissions at another scope than what is set in main.bicep (Which is subscription but role assignments are at Resource Group level) so we need to store the roleAssignment configuration code in modules. Create a folder called modules and create the following files:

  • modules/roleAssignmentReader.bicep
param principalId string

@description('The role definition ID')
param roleDefinitionId string

resource roleAssignmentReader 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId))
  scope: az.resourceGroup()
  properties: {
    principalId: principalId
    principalType: 'Group'
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
  }
}
  • modules/roleAssignmentContributor.bicep
param principalId string

@description('The role definition ID')
param roleDefinitionId string

resource roleAssignmentContributor 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId))
  scope: az.resourceGroup()
  properties: {
    principalId: principalId
    principalType: 'Group'
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
  }
}
  • modules/roleAssignmentOwner.bicep
param principalId string

@description('The role definition ID')
param roleDefinitionId string

resource roleAssignmentOwner 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId))
  scope: az.resourceGroup()
  properties: {
    principalId: principalId
    principalType: 'Group'
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
  }
}

Save it and run the following command in your terminal

az deployment sub create --location swedencentral --template-file main.bicep

Once done you can head to your subscription and in the left pane you can select Deployments and you should see one called Main unless you called it something else. Here we should see our successful deployment.

The same Deployments section from the Resource Group will show the roleassignments from the modules:

After deployment we can see the following groups and role assignments created:

Imagine you often create new resource groups for yourself or others and want to automate the setup, apply tagging and automatically create groups used for role-assignments this can be a useful configuration for you to use and adapt to work for you.

Maybe expand and create the same groups but for the subscription?

References

Announcing public preview of Bicep templates support for Microsoft Graph
Declare Microsoft Entra ID resources like applications and groups in Bicep templates
Create and deploy your first Bicep file with Microsoft Graph resources - Microsoft Graph Bicep
Create a Bicep file using VS Code that declares Microsoft Graph resources and then deploy that Bicep file.

About me

About me
If you have landed on my page you will have already understood my passion for tech, but obviously there is more to life than that. Here I will try and outline a few of my other hobbies. Strength training I am a person who loves to move around and challenge