Contents
When using Azure Bicep for declarative deployments, an important piece of the puzzle was missing for a long time – until now! The development of a Microsoft Graph provider/extension for Bicep was announced back in July 2022 and has now reached public preview status.
The Graph extension allows you to create and include Entra ID resources like groups or service principals declaratively in your Bicep deployments. Therefore, this is especially useful for end-to-end deployments including Entra ID permission groups and role assignments. Until now, some goals were only achievable through Bicep deployment scripts and scripting efforts, which are prone to errors and difficult to troubleshoot.
Let’s take a closer look at the new Graph extension and how it works.
Entra ID / Graph object support
The following Microsoft Graph resource types are currently available to use with the new extension:
- Applications (App Registrations)
- Federated identity credentials (Federated credentials on a Managed Identity)
- App role assigned to (Azure RBAC role assignments)
- Groups (Entra ID groups)
- Oauth2 permission grants (Graph permission assignments)
- Service principals (Enterprise Applications)
Concept of Bicep extensions
Azure Bicep is built to talk to the Azure Resource Manager in the background and has (almost) no capabilities outside of that. As the name states, the new Microsoft Graph capabilities use the concept of Bicep extensions, which allows targeting other endpoints like the Microsoft Graph API (kubernetes
is another provider).
Extensions, also known as providers, need to be declared at the top of your Bicep files like so (make sure you enabled the experimental features in your bicepconfig.json
file first, check the prerequisites below for more information):
provider microsoftGraph
Benefits of using the Microsoft Graph extension
The biggest advantage for me is the ability to achieve end-to-end deployments including service principals, permission groups, and corresponding permission assignments. Not to mention all the declarative and repeatable benefits Bicep itself brings with it.
Prerequisites
To use the new Graph extension, ensure you have
- Azure CLI installed on your machine (to run deployments)
- the Bicep extension installed in VS Code (v0.27.1 or later)
- the correct permissions to run appropriate tasks, i.e. create groups or App Registrations
Enable Bicep preview features
Before we can use the new extension in our files, we need to enable preview features in our bicepconfig.json
file. Check this link if you want to know more about the bicepconfig.json
configuration file: 5 nifty Azure Bicep tips and tricks – marcogerber.ch
Create a new file called bicepconfig.json
in your current working directory and add the following lines:
{ "experimentalFeaturesEnabled": { "extensibility": true } }
Save the file and preview features will now be available for Bicep files in the current working directory.
Include the Graph extension in your Bicep files
Since the new Graph extension is – as the name states – an extension on not a native part of the Bicep DSL, we have to include it at the beginning of each Bicep file like so:
provider microsoftGraph
After the provider is declared, linting is automatically be available in VSCode:
Lab: Graph extension in action
For this quick lab, we’ll create the following resources:
- User-assigned Managed Identity
- Entra ID security group including the Managed Identity as a member
- Storage Account
- Role assignment, which assigns the role
Storage Blob Data Reader
to the Storage Account with the security group as principal
Let’s start by creating a new main.bicep
file in your current working directory. Declare the Graph extension at the top and add some parameters and variables to simplify the deployment:
provider microsoftGraph // Parameters param managedIdentityName string = 'd-id-graph-demo' param storageAccountName string = 'dstographdemo6294' param appRoleDefinitionId string = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' // Storage Blob Data Reader param groupDisplayName string = '${storageAccountName}-StorageBlobDataReader' // Variables var groupUniqueName = toLower(replace(groupDisplayName, ' ', '')) var roleAssignmentName = guid(groupUniqueName, appRoleDefinitionId, resourceGroup().id)
We are now ready to create our first resource, the user-assigned Managed Identity:
// Resources resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-07-31-preview' = { name: managedIdentityName location: resourceGroup().location }
Next, let’s create our first Graph resource, the Entra ID security group. Note lines 25 – 27 where we add the Managed Identity as a group member:
resource securityGroup 'Microsoft.Graph/groups@v1.0' = { displayName: groupDisplayName uniqueName: groupUniqueName mailEnabled: false mailNickname: groupUniqueName securityEnabled: true members: [ managedIdentity.properties.principalId ] }
Second to last, the Storage Account:
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = { name: storageAccountName location: resourceGroup().location sku: { name: 'Standard_LRS' } kind: 'StorageV2' }
And finally, the role assignment. Note lines 42 and 43 where link the security group and the RBAC role together in an assignment:
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: roleAssignmentName properties: { principalId: securityGroup.id roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', appRoleDefinitionId) } }
Here you have the final main.bicep
file:
provider microsoftGraph // Parameters param managedIdentityName string = 'd-id-graph-demo' param storageAccountName string = 'dstographdemo6294' param appRoleDefinitionId string = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' // Storage Blob Data Reader param groupDisplayName string = '${storageAccountName}-StorageBlobDataReader' // Variables var groupUniqueName = toLower(replace(groupDisplayName, ' ', '')) var roleAssignmentName = guid(groupUniqueName, appRoleDefinitionId, resourceGroup().id) // Resources resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-07-31-preview' = { name: managedIdentityName location: resourceGroup().location } resource securityGroup 'Microsoft.Graph/groups@v1.0' = { displayName: groupDisplayName uniqueName: groupUniqueName mailEnabled: false mailNickname: groupUniqueName securityEnabled: true members: [ managedIdentity.properties.principalId ] } resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = { name: storageAccountName location: resourceGroup().location sku: { name: 'Standard_LRS' } kind: 'StorageV2' } resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: roleAssignmentName properties: { principalId: securityGroup.id roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', appRoleDefinitionId) } }
Deployment steps
To deploy the main.bicep
file to Azure, we use simple Azure CLI commands.
1. Login to Azure
First, log in to your Azure account via the Azure CLI. This step authenticates your session and allows you to manage your Azure resources from the command line.
az login
2. Set Azure Subscription
Once logged in, specify which Azure subscription you want to use for the deployment. Replace <subscriptionId> with your actual subscription ID. Skip this step if you only have one subscription.
az account set --subscription <subscriptionId>
3. Deploy Resources
Finally, we use the az deployment group create
command to deploy the resources. This command deploys all resources defined in your Bicep file to the specified resource group. In this example, the resource group is named d-rgr-graph-demo
. Create a resource group first with your desired name.
Replace the path to the Bicep file if it’s located in a different directory or has a different name.
az deployment group create -g d-rgr-graph-demo -f .\main.bicep
And that’s it, you’ll find all the resources in the specified resource group after a few seconds.
You can find the code from this post in my GitHub repository.
Known Issues
Since the feature is still in preview there are some rather major issues, for instance:
- Applications (App Registrations) do not yet support the creation of secrets as you can via the Azure portal, CLI, or PowerShell. Only keys from an Azure Key Vault are supported as of now.
- Only Azure PowerShell and Azure CLI apps are supported for interactive deployments of Microsoft Graph resources.
- At the moment, you may get an
Another object with the same value for property uniqueName already exists
error when recreating Graph resources (delete and redeploy a resource).
Current known issues and corresponding resolution steps are documented here: Known issues: Microsoft Graph Bicep templates – Microsoft Graph Bicep | Microsoft Learn
Resources
- Official announcement: Announcing public preview of Bicep templates support for Microsoft Graph – Microsoft Community Hub
- Documentation: Bicep templates for Microsoft Graph resources – Microsoft Graph Bicep | Microsoft Learn
- Microsoft Graph Bicep resource reference overview: Microsoft Graph Bicep resource reference overview – Microsoft Graph Bicep v1.0 reference | Microsoft Learn
- Microsoft Graph Bicep Extension GitHub project: GitHub – microsoftgraph/msgraph-bicep-types: Repo contains Microsoft Graph resource types to integrate with bicep templates.
- Quickstart templates: msgraph-bicep-types/quickstart-templates at main · microsoftgraph/msgraph-bicep-types · GitHub
- Code from this blog post: blog-posts/deploy-entra-id-resources-declaratively-using-azure-bicep at main · gerbermarco/blog-posts · GitHub