DEV Community

Cover image for Using Azure Bicep to deploy MS Graph resources
Olivier Miossec
Olivier Miossec

Posted on • Edited on

Using Azure Bicep to deploy MS Graph resources

In Infrastructure as Code, we focus on deploying and configuring Azure resources. Sometimes you must define Entra ID (AzureAD) objects such as a group, an application, and a Service principal. Until now, the only way was to have two systems: one in IaC for Azure Resources and one with a script (PowerShell or Azure CLI) to manage Entra ID objects.
Bicep comes with a solution to deploy MS Graph resources and Azure resources using the same code; Bicep templates support for Microsoft Graph.

This feature is now Generaly Availble

First, we need to define a scenario, you need to Create a Service Principal, deploy a VM, and give the reader role to the service principal.
You need to configure Bicep to use Microsoft Graph. In a new folder create a main.bicep file and bicepconfig.json file. In the last file type:

{ "experimentalFeaturesEnabled": { "extensibility": true } } 
Enter fullscreen mode Exit fullscreen mode

This will allow your bicep engine to use this feature in preview.
In the main.bicep file, the first thing you need to do is to write: provider microsoftGraph, it instructs Bicep that MicrosoftGraph type should be included. If you forget to do that you will not be able to deploy any MS Graph resource and if you use Visual Studio Code, every MS Graph type will be shown as unknow.

The bicep code to deploy the Service Principal, a VM, and assign the SP to the VM with the reader role.

provider microsoftGraph var entraIDRole = 'f2ef992c-3afb-46b9-b7cf-a126ee74c451' resource resourceApp 'Microsoft.Graph/applications@v1.0' = { uniqueName: 'ExampleResourceApp' displayName: 'Example Resource Application' appRoles: [ { id: entraIDRole allowedMemberTypes: [ 'User', 'Application' ] description: 'Read access to resource app data' displayName: 'ResourceAppData.Read.All' value: 'ResourceAppData.Read.All' isEnabled: true } ] } resource resourceSp 'Microsoft.Graph/servicePrincipals@v1.0' = { appId: resourceApp.appId } param adminUsername string = 'demoadmin' @allowed([ 'sshPublicKey' 'password' ]) param authenticationType string = 'password' param location string = resourceGroup().location @secure() param adminPasswordOrKey string var vmName = 'demoLinuxVM' var ubuntuOSVersion = 'Ubuntu-2004' var vmSize = 'Standard_D2s_v3' var virtualNetworkName = 'vNet' var subnetName = 'Subnet' var securityType = 'TrustedLaunch' var imageReference = { 'Ubuntu-2204': { publisher: 'Canonical' offer: '0001-com-ubuntu-server-jammy' sku: '22_04-lts-gen2' version: 'latest' } } var publicIPAddressName = '${vmName}PublicIP' var networkInterfaceName = '${vmName}NetInt' var osDiskType = 'Standard_LRS' var subnetAddressPrefix = '10.1.0.0/24' var addressPrefix = '10.1.0.0/16' var linuxConfiguration = { disablePasswordAuthentication: true ssh: { publicKeys: [ { path: '/home/${adminUsername}/.ssh/authorized_keys' keyData: adminPasswordOrKey } ] } } var securityProfileJson = { uefiSettings: { secureBootEnabled: true vTpmEnabled: true } securityType: securityType } var extensionName = 'GuestAttestation' var extensionPublisher = 'Microsoft.Azure.Security.LinuxAttestation' var extensionVersion = '1.0' var maaTenantName = 'GuestAttestation' var maaEndpoint = substring('emptystring', 0, 0) resource networkInterface 'Microsoft.Network/networkInterfaces@2023-09-01' = { name: networkInterfaceName location: location properties: { ipConfigurations: [ { name: 'ipconfig1' properties: { subnet: { id: virtualNetwork.properties.subnets[0].id } privateIPAllocationMethod: 'Dynamic' publicIPAddress: { id: publicIPAddress.id } } } ] } } resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-09-01' = { name: virtualNetworkName location: location properties: { addressSpace: { addressPrefixes: [ addressPrefix ] } subnets: [ { name: subnetName properties: { addressPrefix: subnetAddressPrefix privateEndpointNetworkPolicies: 'Enabled' privateLinkServiceNetworkPolicies: 'Enabled' } } ] } } resource publicIPAddress 'Microsoft.Network/publicIPAddresses@2023-09-01' = { name: publicIPAddressName location: location sku: { name: 'Basic' } properties: { publicIPAllocationMethod: 'Dynamic' publicIPAddressVersion: 'IPv4' idleTimeoutInMinutes: 4 } } resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = { name: vmName location: location properties: { hardwareProfile: { vmSize: vmSize } storageProfile: { osDisk: { createOption: 'FromImage' managedDisk: { storageAccountType: osDiskType } } imageReference: imageReference['Ubuntu-2204'] } networkProfile: { networkInterfaces: [ { id: networkInterface.id } ] } osProfile: { computerName: vmName adminUsername: adminUsername adminPassword: adminPasswordOrKey linuxConfiguration: ((authenticationType == 'password') ? null : linuxConfiguration) } securityProfile: (securityType == 'TrustedLaunch') ? securityProfileJson : null } } resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2023-09-01' = if (securityType == 'TrustedLaunch' && securityProfileJson.uefiSettings.secureBootEnabled && securityProfileJson.uefiSettings.vTpmEnabled) { parent: vm name: extensionName location: location properties: { publisher: extensionPublisher type: extensionName typeHandlerVersion: extensionVersion autoUpgradeMinorVersion: true enableAutomaticUpgrade: true settings: { AttestationConfig: { MaaSettings: { maaEndpoint: maaEndpoint maaTenantName: maaTenantName } } } } } resource roleAssignement 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid('roleAssignment') scope: vm properties: { principalId: resourceSp.id roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') } } 
Enter fullscreen mode Exit fullscreen mode

The code creates an Enterprise application and its SP, deploys the VM with virtual NIC and virtual network resources, and then assigns the reader role to the VM.
To deploy the SP and the VM you want, use the New-AzResourceGroupDeployment cmdlet like any other resource group deployment

New-AzResourceGroupDeployment -ResourceGroupName bicep-azgraph -TemplateFile ./Bicep/main.bicep 
Enter fullscreen mode Exit fullscreen mode

PowerShell will ask for a password and deploy the SP and the VM

Bicep support for Microsoft Graph can be used to deploy

  • Applications and Service Principals
  • Federated Identity
  • Entra ID Groups
  • OAuth Permission grant
  • App role assigned to (but this feature does not work with personal account)

The support of Microsoft Graph is in preview, and not suitable for production. You can check the project GitHub page here

You can find the code presented here on GitHub

Top comments (0)