Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use Bicep (or ARM) to create a MS Entra app registration and roles?

I'm using Terraform to create app registration and roles for our apps. But I cannot figure out how to do the same with Bicep. This is what's used today:

Step 1. Register the app in Active Directory, effectively creating an "app registration".

resource "azuread_application" "ad_app" {
  name                        = local.full_app_name
  type                        = "webapp/api"
  owners                      = var.app_owners
}

Step 2: Create a role for our app

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.

like image 216
Martin Wickman Avatar asked Dec 07 '25 22:12

Martin Wickman


2 Answers

Unfortunately both are not directly supported in ARM template or Bicep. But You can use Deployment Scripts to create both using Bicep/ARM template.


Create Azure AD App registration using Bicep:

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:

Creating App Registration with ARM templates/Bicep | by Jon Reginbald


Creating a App Roles for Azure AD application:

I don't have much idea on this but I guess you can use the below script where //create app role is written in the above 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

like image 142
AnsumanBal-MT Avatar answered Dec 10 '25 13:12

AnsumanBal-MT


This is now possible using the Microsoft Graph Resource Provider (see documentation).

  1. You would need to install or upgrade latest bicep version.
  2. As per may 2024, this feature is in plublic preview so you would need ot configure experimentation feature. Create/update bicepconfig.json config file:
{
  "experimentalFeaturesEnabled": {
    "extensibility": true
  }
}

Then you can create an application and app roles like this:

extension microsoftGraph

resource application 'Microsoft.Graph/applications@beta' = {
  displayName: 'My fisrt application'
  uniqueName: 'my-uniquename'
  appRoles: [
    {
      id: guid('my-uniquename', 'Persons.Read') // need unique guid with same value foir each deployment
      isEnabled: true
      displayName: 'Person Reader'
      description: 'Person Reader can search and read persons'
      value: 'Persons.Read'
      allowedMemberTypes: [
        'Application'
      ]
    }
  ]
}
like image 37
Thomas Avatar answered Dec 10 '25 12:12

Thomas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!