In infrastructure as Code, we focus on deploying and configuring Azure resources. Sometimes you must define Entra ID (AzureAD) objects such as group, application, and Service principal. Until now the only way was to have two systems, one in IaC for Azure Resource and one with 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.
Be careful, Microsoft Graph Bicep is currently in preview.
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
}
}
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')
}
}
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
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)