Skip to content

Instantly share code, notes, and snippets.

@jlucaspains
Last active April 7, 2024 21:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlucaspains/8cbcb641a5ebc40a027956f94127f0a7 to your computer and use it in GitHub Desktop.
Save jlucaspains/8cbcb641a5ebc40a027956f94127f0a7 to your computer and use it in GitHub Desktop.
Create app registrations and add roles bound to azure entra groups
{
"requestedAccessTokenVersion": 2,
"oauth2PermissionScopes": [
{
"id": "332a3ddb-38d8-4c69-a59a-1ea9b2058685",
"adminConsentDescription": "Read and write information about people",
"adminConsentDisplayName": "Read and write information about people",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Read and write information about people",
"userConsentDisplayName": "Read and write information about people",
"value": "api-read-write"
}
]
}
[
{
"allowedMemberTypes": [
"User"
],
"description": "Can use all app features including write capabilities",
"displayName": "Administrator",
"id": "25909a57-ce45-49d3-b1f3-4b6f3d03d15a",
"isEnabled": true,
"origin": "Application",
"value": "Administrator"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Can configure aspects the application but generally not make administrative changes",
"displayName": "Developer",
"id": "07470a96-716a-4688-92fd-6fb452f81202",
"isEnabled": true,
"origin": "Application",
"value": "Developer"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Can view data and perform user level actions but not make administrative changes",
"displayName": "User",
"id": "3e87b7be-a276-4e85-add7-974e0d29fed8",
"isEnabled": true,
"origin": "Application",
"value": "User"
}
]
[CmdletBinding()] param ()
$AppNames = @(
"OrdersApi",
"PeopleApi"
)
$Envs = @(
"dev",
"qa"
)
foreach ($AppName in $AppNames) {
Write-Host "Processing $($AppName)..."
foreach ($Env in $Envs) {
$FullAppName = "$($AppName)-$($Env)"
Write-Host "Processing $FullAppName..."
$appObjectId = (az ad app list --display-name $FullAppName --query "[0].id" -o tsv)
# If the app is not found, create it.
# This is the place to add any special configuration needed for a new app registration
if ($null -eq $appObjectId) {
$appObjectId = (az ad app create --display-name $FullAppName --sign-in-audience AzureADMyOrg --identifier-uris "api://$($FullAppName).lpains.net" --query "id" -o tsv)
# Ensure the api section is set correctly
az ad app update --id $appObjectId --set api=@appApi.json
az ad app permission add --id $appObjectId --api 00000003-0000-0000-c000-000000000000 --api-permissions e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope
}
# Find the enterprise app service principal object id
$appSPObjectId = (az ad sp list --display-name $FullAppName --query '[0].id' -o tsv)
if ($null -eq $appSPObjectId) {
$appSPObjectId = (az ad sp create --id $appObjectId --query '[0].id' -o tsv)
}
Write-Host "App Object Id: $appObjectId"
Write-Host "App Service Principal Object Id: $appSPObjectId"
}
Write-Host "Finished procesing $($AppName). It may take a few minutes for the changes to take effect."
}
[CmdletBinding()] param ()
$AppNames = @(
"OrdersApi",
"PeopleApi"
)
$Envs = @(
"dev",
"qa"
)
foreach ($AppName in $AppNames) {
Write-Host "Processing $($AppName)..."
foreach ($Env in $Envs) {
$FullAppName = "$($AppName)-$($Env)"
Write-Host "Processing $FullAppName..."
$appObjectId = (az ad app list --display-name $FullAppName --query "[0].id" -o tsv)
$appSPObjectId = (az ad sp list --display-name $FullAppName --query '[0].id' -o tsv)
Write-Verbose "App Object Id: $appObjectId"
Write-Verbose "App Service Principal Object Id: $appSPObjectId"
if ($null -eq $appObjectId -or $null -eq $appSPObjectId) {
Write-Host "App registration not found. Skipping..."
continue;
}
$jsonData = Get-Content -Path "./appRoles.json" | ConvertFrom-Json
# The appRoles file may contain a subset of the roles
# we will create a unique list of roles already in the app registration and the roles in the file
Write-Host "Creating unique list of roles to update..."
$existingAppRegRolesJson = (az ad app list --display-name $FullAppName --query "[0].appRoles")
Write-Verbose ($existingAppRegRolesJson | ConvertTo-Json)
$existingAppRegRoles = $existingAppRegRolesJson | ConvertFrom-Json
$mergedUniqueRoles = $existingAppRegRoles + $jsonData | Sort-Object -Property Id -Unique
$appRoles = $mergedUniqueRoles | ConvertTo-Json
Write-Verbose $appRoles
$appRoles > "./TempRoles.json"
# Apply the unique set of app roles to the app registration
Write-Host "Adding app registration roles..."
az ad app update --id $appObjectId --app-roles "./TempRoles.json"
# Find existing role assignments in the enterprise app
$existingRoles = (az rest -m GET -u "https://graph.microsoft.com/v1.0/servicePrincipals/$appSPObjectId/appRoleAssignedTo") | ConvertFrom-Json
Write-Verbose $existingRoles
foreach ($role in $jsonData) {
$existingRole = $existingRoles.value | Where-Object { $_.appRoleId -eq $role.id }
# No reason to apply an existing role assignment again
if ($null -ne $existingRole) {
Write-Verbose $existingRole
Write-Host "Binding already exist between $($role.Value) and group prefix-$($Env)-$($role.Value)..."
continue;
}
# Find the Azure Entra group using a convention approach of prefix-environment-role
Write-Host "Binding $($role.Value) to group blog-$($Env)-$($role.Value)..."
$RoleGuid = $role.id
$groupId = (az ad group list --display-name "blog-$($Env)-$($role.Value)" --query "[0].id" -o tsv)
$postBody = "{\""principalId\"": \""$groupId\"", \""resourceId\"": \""$appSPObjectId\"", \""appRoleId\"": \""$RoleGuid\""}"
Write-Verbose $postBody
# Create the role assignment between the group and the app role
az rest -m POST -u "https://graph.microsoft.com/v1.0/servicePrincipals/$appSPObjectId/appRoleAssignments" -b $postBody --headers "Content-Type=application/json"
}
}
Write-Host "Finished procesing $($AppName)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment