Problem
For our apps, I’m using Terraform to construct app registration and roles. But I can’t seem to get Bicep to do the same thing. This is how it’s done nowadays.
Step 1: Create a “app registration” in Active Directory by registering the app.
resource "azuread_application" "ad_app" {
name = local.full_app_name
type = "webapp/api"
owners = var.app_owners
}
Step 2: Assign our app a role.
resource "azuread_application_app_role" "person_read" {
application_object_id = azuread_application.ad_app.id
allowed_member_types = ["Application"]
description = "Person Reader can search and read persons"
display_name = "Person Reader"
value = "Persons.Read"
}
Problem is I cannot figure out how to do those steps with Bicep (or ARM templates). I tried with ‘Microsoft.Authorization/roleDefinitions’, but it doesn’t seem right. And I have no idea about how to do the app registration.
Asked by Martin Wickman
Solution #1
Unfortunately, neither ARM template nor Bicep directly support them. However, you may generate both using the Bicep/ARM template and Deployment Scripts.
Using Bice, create an Azure AD App registration.
param name string
param location string = resourceGroup().location
param currentTime string = utcNow()
resource script 'Microsoft.Resources/deploymentScripts@2019-10-01-preview' = {
name: name
location: location
kind: 'AzurePowerShell'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${resourceId('app-reg-automation', 'Microsoft.ManagedIdentity/userAssignedIdentities', 'AppRegCreator')}': {}
}
}
properties: {
azPowerShellVersion: '5.0'
arguments: '-resourceName "${name}"'
scriptContent: '''
param([string] $resourceName)
$token = (Get-AzAccessToken -ResourceUrl https://graph.microsoft.com).Token
$headers = @{'Content-Type' = 'application/json'; 'Authorization' = 'Bearer ' + $token}
$template = @{
displayName = $resourceName
requiredResourceAccess = @(
@{
resourceAppId = "00000003-0000-0000-c000-000000000000"
resourceAccess = @(
@{
id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
type = "Scope"
}
)
}
)
signInAudience = "AzureADMyOrg"
}
// Upsert App registration
$app = (Invoke-RestMethod -Method Get -Headers $headers -Uri "https://graph.microsoft.com/beta/applications?filter=displayName eq '$($resourceName)'").value
$principal = @{}
if ($app) {
$ignore = Invoke-RestMethod -Method Patch -Headers $headers -Uri "https://graph.microsoft.com/beta/applications/$($app.id)" -Body ($template | ConvertTo-Json -Depth 10)
$principal = (Invoke-RestMethod -Method Get -Headers $headers -Uri "https://graph.microsoft.com/beta/servicePrincipals?filter=appId eq '$($app.appId)'").value
} else {
$app = (Invoke-RestMethod -Method Post -Headers $headers -Uri "https://graph.microsoft.com/beta/applications" -Body ($template | ConvertTo-Json -Depth 10))
$principal = Invoke-RestMethod -Method POST -Headers $headers -Uri "https://graph.microsoft.com/beta/servicePrincipals" -Body (@{ "appId" = $app.appId } | ConvertTo-Json)
}
// Creating client secret
$app = (Invoke-RestMethod -Method Get -Headers $headers -Uri "https://graph.microsoft.com/beta/applications/$($app.id)")
foreach ($password in $app.passwordCredentials) {
Write-Host "Deleting secret with id: $($password.keyId)"
$body = @{
"keyId" = $password.keyId
}
$ignore = Invoke-RestMethod -Method POST -Headers $headers -Uri "https://graph.microsoft.com/beta/applications/$($app.id)/removePassword" -Body ($body | ConvertTo-Json)
}
$body = @{
"passwordCredential" = @{
"displayName"= "Client Secret"
}
}
$secret = (Invoke-RestMethod -Method POST -Headers $headers -Uri "https://graph.microsoft.com/beta/applications/$($app.id)/addPassword" -Body ($body | ConvertTo-Json)).secretText
$DeploymentScriptOutputs = @{}
$DeploymentScriptOutputs['objectId'] = $app.id
$DeploymentScriptOutputs['clientId'] = $app.appId
$DeploymentScriptOutputs['clientSecret'] = $secret
$DeploymentScriptOutputs['principalId'] = $principal.id
// create app role
'''
cleanupPreference: 'OnSuccess'
retentionInterval: 'P1D'
forceUpdateTag: currentTime // ensures script will run every time
}
}
output objectId string = script.properties.outputs.objectId
output clientId string = script.properties.outputs.clientId
output clientSecret string = script.properties.outputs.clientSecret
output principalId string = script.properties.outputs.principalId
Reference:
Using ARM templates/Bicep to Create App Registration | by Jon Reginbald
Creating a App Roles for Azure AD application:
I’m not sure about this, but I believe you may use the script below, where /create app role is written in the preceding code:
$app = (Invoke-RestMethod -Method Get -Headers $headers -Uri "https://graph.microsoft.com/beta/applications/$($app.id)")
$body1 = @{
Id = [Guid]::NewGuid().ToString()
IsEnabled = true
AllowedMemberTypes =@("application")
Description = "My Role Description.."
DisplayName = "My Custom Role"
Value = "MyCustomRole"
}
$createapprole= Invoke-RestMethod -Method POST -Headers $headers -Uri "https://graph.microsoft.com/beta/applications/$($app.id)/appRoles" -Body ($body1 | ConvertTo-Json)
Reference:
appRole resource type
Update application
Answered by AnsumanBal-MT
Post is based on https://stackoverflow.com/questions/69120936/how-do-i-use-bicep-or-arm-to-create-an-ad-app-registration-and-roles