Network Redundancy from On-Premises to Azure VMware and VNETs
May 10, 2025Dynamic Tool Discovery: Azure AI Agent Service + MCP Server Integration
May 12, 2025Welcome back
It’s been a while since I last posted, but with the amount of things going on in the world of AI, I thought it was time to get back into the swing of things. Today, I’m going to share a problem I faced recently and how I solved it with Bicep.
The problem
I am working on a project for simplifying the deployment of a zero-trust secure Azure AI Foundry environment, an Azure AI Foundry jumpstart if you will. This project deploys the resources using Bicep, but one of the requirements is to assign the reader
role to the service principal for the Enterprise Application added Azure Machine Learning
.
However, this is not as straightforward as it seems. The Azure Machine Learning
Enterprise Application is a multi-tenant application, and the service principal object ID is different across all tenants. This means that you cannot hardcode the Object ID in your Bicep template and you can’t use the Application ID of the Azure Machine Learning
Enterprise Application either, as the role assignement requires the Object ID of the service principal in your tenant.
I’m using the
Azure Machine Learning
Enterprise Application as an example, but this applies to any multi-tenant application in Entra ID that you want to assign roles to in your tenant. For more information on application and service principals objects in Entra ID, see this article.
The solution
The solution to this is to use the experiemental extensibility
feature of Bicep that allows you to use the Microsoft Graph Extension to work with Entra ID resources, such as service principals, groups, and users. This feature is still in preview, but it works well for this use case.
Here is a list of the steps we’re going to follow:
- Enable the extensibility feature of Bicep by adding a
bicepconfig.json
file to your project. - Add the Microsoft Graph Bicep extension to your Bicep template.
- Create the service principal resource for the
Azure Machine Learning
Enterprise Application. - Create the role assignment for the service principal using the
id
property of the service principal resource.
And now for the fun part! Let’s get started with the code.
Step 1: Enable Bicep extensibility
To enable the extensibility feature of Bicep, you need to add a bicepconfig.json
file to your Bicep project. In general this file should be in the same folder as your Bicep files. If you’re using Visual Studio Code you open the Command Palette ([CTRL/CMD]+[SHIFT]+P) and select Bicep: Create Bicep Configuration File
to create the file. To the bicepconfig.json
file, you need to add the following settings:
"extensibility": true
to theexperimentalFeaturesEnabled
section to enable the extensibility feature."microsoftGraphV1": "br:mcr.microsoft.com/bicep/extensions/microsoftgraph/v1.0:0.2.0-preview"
to theextensions
section to use the Microsoft Graph Bicep extension.
{
// See https://aka.ms/bicep/config for more information on Bicep configuration options
// Press CTRL+SPACE at any location to see Intellisense suggestions
"analyzers": {
"core": {
"rules": {
"no-unused-params": {
"level": "warning"
}
}
}
},
"experimentalFeaturesEnabled": {
"extensibility": true
},
"extensions": {
"microsoftGraphV1": "br:mcr.microsoft.com/bicep/extensions/microsoftgraph/v1.0:0.2.0-preview"
}
}
Once the extensibility feature is out of preview, setting the
"extensibility": true
will no longer be required.
Step 2: Add the Microsoft Graph Bicep extension
At the beginning of your Bicep template, you need to add the Microsoft Graph Bicep extension. This is done by adding the following line:
// Use the Microsoft Graph Bicep extension to work with Entra ID resources
extension microsoftGraphV1
Step 3: Reference the existing service principal resource
You can use the existing Microsoft.Graph/servicePrincipals@v1.0 resource that has the appId
property set to the GUID of the Azure Machine Learning
Enterprise Application.
// The Service Principal of the Azure Machine Learning service.
resource azureMachineLearningServicePrincipal 'Microsoft.Graph/servicePrincipals@v1.0' existing = {
appId: '0736f41a-0425-4b46-bdb5-1563eff02385' // Azure Machine Learning service principal
}
If you don’t know the
appId
of the Enterprise Application you want to assign, you can find it in the Azure portal by going toMicrosoft Entra ID
>Enterprise applications
and searching forAzure Machine Learning
. TheappId
is theApplication ID
of the Enterprise Application. You might need to remove theApplication type == Enterprise Applications
filter to see theAzure Machine Learning
Enterprise Application in the list.

Step 4: Create the role assignment
Once the azureMachineLearningServicePrincipal
resource is available to your Bicep template, you can use the id
property of the service principal to assign the reader
role to the resource for the Enterprise Application. In this example, I’m using assigning the reader
role to an existing Azure AI Search
service, but you can assign it to any role to any resource, existing or being created in the template.
// The existing Azure AI Search service (can be a new or existing resource).
resource azureAiSearch 'Microsoft.Search/searchServices@2025-02-01-preview' existing = {
name: 'my-azure-ai-search'
}
// The role assignment for the Azure AI Search service to grant reader role to Azure Machine Learning.
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
name: guid(subscription().subscriptionId, azureAiSearch.id, 'acdd72a7-3385-48ef-bd42-f606fba81ae7' )
scope: azureAiSearch
properties: {
principalType: 'ServicePrincipal'
principalId: azureMachineLearningServicePrincipal.id
roleDefinitionId: 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Role definition ID for Reader role
}
}
The complete Bicep template
The complete Bicep template looks like this:
// Use the Microsoft Graph Bicep extension to work with Entra ID resources
extension microsoftGraphV1
// The Service Principal of the Azure Machine Learning service.
resource azureMachineLearningServicePrincipal 'Microsoft.Graph/servicePrincipals@v1.0' existing = {
appId: '0736f41a-0425-4b46-bdb5-1563eff02385' // Azure Machine Learning service principal
}
// The existing Azure AI Search service (can be a new or existing resource).
resource azureAiSearch 'Microsoft.Search/searchServices@2025-02-01-preview' existing = {
name: 'my-azure-ai-search'
}
// The role assignment for the Azure AI Search service to grant reader role to Azure Machine Learning.
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
name: guid(subscription().subscriptionId, azureAiSearch.id, 'acdd72a7-3385-48ef-bd42-f606fba81ae7' )
scope: azureAiSearch
properties: {
principalType: 'ServicePrincipal'
principalId: azureMachineLearningServicePrincipal.id
roleDefinitionId: 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Role definition ID for Reader role
}
}
You can find the Github Gist containing the code above here.
To see the entire complete process in action, check out the Bicep for the Azure AI Foundry Jumpstart.
Conclusion
In this post, I showed you how to assign the reader
role to the service principal for the Azure Machine Learning
Enterprise Application using Bicep. This is a common scenario deploying services in Azure that are consumed by multi-tenant applications (such as Azure Machine Learning). Using experiemental features in production enviornments is generally not recommended, but hopefully the extensions feature of Bicep will be available in a stable release soon. So keep an eye out for that!