Azure Bicep and MS Graph - a long awaited collaboration

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

About me
