Scripting Azure AD application role assignments

When using Azure Active Directory for adding role-based access control to your web applications and APIs, it is highly recommended to use application roles.  This allows you to define custom application roles and these can be assigned to users and applications.  A clean way to secure your applications!

The challenge

Preferably, role assignments are automated through privileged release pipelines.  The two PowerShell commands that can be used to automate this – New-AzureADServiceAppRoleAssignment and New-AzureADUserAppRoleAssignment – are not easy to use, as it is not always clear what the exact Ids are that you have to provide.

The solution

That’s why I prefer to automate this based on display names and let a script take care of fetching the required Ids. Lately, I have developed such a script to assign Azure AD application roles to users and applications.  Hereby, I share it with the community.  The script can be found in this gist.

Config file

The script is driven by a simple config file, that contains a JSON array of role assignments:

  • description: free text field that describes the role assignment
  • client_type: “user” or “application”
  • client_principal_name: the users’ UPN (someone@example.com) or the display name of the service principal (enterprise application)
  • server_app_registration_name: the display name of the app registration to which you want to grant the client access
  • role_name the display name of the application role you want to assign to the configured client

This is how you configure access for a user (UPN):

{
"description": "Grant Toon administrator access on application Z.",
"client_type" : "user",
"client_principal_name": "toon@yourazurecoach.com",
"server_app_registration_name": "app-registration-z-prod",
"role_name": "administrator"
}

This is how you configure access for an application (service principal):

{
"description": "Grant service principal X reader access on application Z.",
"client_type" : "application",
"client_principal_name": "service-principal-x-prod",
"server_app_registration_name": "app-registration-z-prod",
"role_name": "reader"
},

Script

You can use the script like this:

  • Download the script and the config file.
  • Update the config files to your needs
  • Trigger the script via PowerShell
.\aad-apply-role-assignments.ps1 -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -ConfigFilePath ".\aad-role-assignments.json"

If you are interested, this is how the script looks like:

param (
[string] $TenantId,
[string] $ConfigFilePath
)
$ErrorActionPreference = "Stop"
Write-Host Start Azure AD role assignment script
Write-Host "-Tenant Id:" $TenantId -ForegroundColor Gray
Write-Host "-Config File Path:" $ConfigFilePath -ForegroundColor Gray
Write-Host Installing and importing AzureAD Module
if (Get-Module -ListAvailable -Name AzureAD) {
Import-Module -Name "AzureAD"
}
else {
Install-Module -Name "AzureAD" -Force
}
Write-Host Connecting to Azure AD Tenant within current security context
$azure_context = Get-AzContext
$account_id = $azure_context.Account.Id
Write-Host "-Account Id:" $azure_context.Account.Id -ForegroundColor Gray
Connect-AzureAD -TenantId $TenantId -AccountId $account_id
Write-Host Loading role assignments from config file
$role_assignments = (Get-Content $ConfigFilePath -Raw) | ConvertFrom-Json
Write-Host Looping each configured role assignment
foreach($role_assignment in $role_assignments)
{
Write-Host Applying role assigment... started -ForegroundColor Green
Write-Host "-Description:" $role_assignment.description -ForegroundColor Gray
Write-Host "-Client principal Name:" $role_assignment.client_principal_name -ForegroundColor Gray
Write-Host "-Server App Registration Name:" $role_assignment.server_app_registration_name -ForegroundColor Gray
Write-Host "-Role Name:" $role_assignment.role_name -ForegroundColor Gray
Write-Host Getting the server application registration
$aad_filter = "DisplayName eq '" + $role_assignment.server_app_registration_name + "'"
$server_application_registration = Get-AzureADApplication -Filter $aad_filter
if (!$server_application_registration) { throw "Cannot find configured server application registration with name '" + $role_assignment.server_app_registration_name + "'" }
Write-Host Getting the server service principal id
$aad_filter = "AppId eq '" + $server_application_registration.AppId + "'"
$server_service_principal = Get-AzureADServicePrincipal -Filter $aad_filter
$server_service_principal_id = $server_service_principal.ObjectId
Write-Host "-Server service principal Id: " $server_service_principal_id -ForegroundColor Gray
Write-Host Getting the Id for the configured application role
$role_id = ($server_application_registration.AppRoles | Where-Object DisplayName -eq $role_assignment.role_name).Id
if (!$role_id) { throw "Cannot find configured application role with name '" + $role_assignment.role_name + "'" }
Write-Host "-Role Id: " $role_id -ForegroundColor Gray
if(($role_assignment.client_type -ne "application") -and ($role_assignment.client_type -ne "user")) { throw "Incorrect client_type '" + $role_assignment.client_type + "' provided." }
switch ($role_assignment.client_type)
{
"application"
{
Write-Host Getting the configured client service principal
$aad_filter = "DisplayName eq '" + $role_assignment.client_principal_name + "'"
$client_service_principal = (Get-AzureADServicePrincipal -Filter $aad_filter)
if (!$client_service_principal) { throw "Cannot find configured client service principal with name '" + $role_assignment.client_principal_name + "'" }
$client_service_principal_id = $client_service_principal.ObjectId
$client_service_principal_name = $client_service_principal.DisplayName
Write-Host "-Client service principal Id:" $client_service_principal_id -ForegroundColor Gray
Write-Host Assigning the Azure Ad role to the configured service principal
try
{
New-AzureADServiceAppRoleAssignment -Id $role_id -ResourceId $server_service_principal_id -ObjectId $client_service_principal_id -PrincipalId $client_service_principal_id
}
catch
{
if( $_.Exception.Message -like '*Permission being assigned already exists on the object*')
{
Write-Host Permission already exists
}
else
{
Write-Error $_.Exception.Message
}
}
}
"user"
{
Write-Host Getting the configured client user
$user = Get-AzureADUser -searchstring $role_assignment.client_principal_name
if (!$user) { throw "Cannot find configured client users with name '" + $role_assignment.client_principal_name + "'" }
$user_id = $user.ObjectId
Write-Host "-User Id:" $user_id -ForegroundColor Gray
Write-Host Assigning the Azure Ad role to the configured user
try
{
New-AzureADUserAppRoleAssignment -Id $role_id -ResourceId $server_service_principal_id -ObjectId $user_id -PrincipalId $user_id
}
catch
{
if( $_.Exception.Message -like '*Permission being assigned already exists on the object*')
{
Write-Host Permission already exists
}
else
{
Write-Error $_.Exception.Message
}
}
}
}
Write-Host Applying role assigment... done -ForegroundColor Green
}

I hope that this script helps you to accelerate your security automation.

Cheers
Toon

About me

Hi! I’m Toon Vanhoutte, a hands-on Azure architect – based in Belgium – with a big passion for teaching and helping people out. I’m happy to assist you during your Azure journey with high-quality advisory and I would love to teach you Azure’s possibilities via my tailored training courses.

Subscribe to the blog