Awesome
Azure Governance Visualizer (AzGovViz) accelerator
Azure Governance Visualizer is a PowerShell based script that iterates your Azure tenant's management group hierarchy down to the subscription level. It captures most relevant Azure governance capabilities such as Azure Policy, role-based access control (RBAC), Blueprints, and a lot more. From the collected data Azure Governance Visualizer provides visibility on your HierarchyMap, creates a TenantSummary, creates DefinitionInsights and builds granular ScopeInsights on management groups and subscriptions.
This accelerator speeds up the adoption of Azure Governance Visualizer into your environment.
Table of contents
- Azure Governance Visualizer (AzGovViz) accelerator
- Table of contents
- :rocket: Deployment guide
- 1. Create a service principal (Microsoft Entra ID app registration) to run Azure Governance Visualizer
- 2. Create copy of the Azure Governance Visualizer accerlator in your own GitHub repository
- 3. Configure federated credentials for the service principal created in the first step
- 4. Grant permissions in Azure for the AzGovViz service principal created in the first step
- 5. Create a Microsoft Entra application for user authentication to the Azure Web App that will host AzGovViz
- 6. Create a resource group and assign necessary RBAC roles
- 7. Create the GitHub secrets, variables, and permissions
- 8. Deploy Azure Governance Visualizer Azure resources and application
- :checkered_flag: Try it out!
- :broom: Clean up resources
- Additional topics
- Sources to documentation
:rocket: Deployment guide
Follow these steps to deploy the Azure Governance Visualizer accelerator into your own Azure and Microsoft Entra ID tenant. Most steps have both portal based ( :computer_mouse: ) and PowerShell based ( :keyboard: ) instructions. Use whichever you feel is appropriate for your situation, they both produce the same results.
1. Create a service principal (Microsoft Entra ID app registration) to run Azure Governance Visualizer
NOTE: To grant API permissions and grant admin consent for the directory, you must have 'Privileged Role Administrator' or 'Global Administrator' role assigned. See Assign Microsoft Entra roles to users for instructions.
:computer_mouse: Use the Microsoft Entra admin center to create the service principal:
- Navigate to the Microsoft Entra admin center
- Click on 'App registrations'
- Click on 'New registration'
- Name your application (e.g. AzureGovernanceVisualizer_SP)
- Click 'Register'
- Your App registration has been created. In the 'Overview' copy the 'Application (client) ID' as you will need it later to setup the secrets in GitHub.
- Under 'Manage' click on 'API permissions'
- Click on 'Add a permissions'
- Click on 'Microsoft Graph'
- Click on 'Application permissions'
- Select the following set of permissions and click 'Add permissions'
- Application / Application.Read.All
- Group / Group.Read.All
- User / User.Read.All
- PrivilegedAccess / PrivilegedAccess.Read.AzureResources
- Click on 'Add a permissions'
- Back in the main 'API permissions' menu you will find permissions with status 'Not granted for...'. Click on 'Grant admin consent for TenantName' and confirm by click on 'Yes'. Now you will find the permissions with status 'Granted for TenantName'
:keyboard: Use PowerShell to create the service principal:
-
Install AzAPICall and connect to Azure
$module = Get-Module -Name "AzAPICall" -ListAvailable if ($module) { Update-Module -Name "AzAPICall" -Force } else { Install-Module -Name AzAPICall } Connect-AzAccount
-
Initialize AzAPICall
$parameters4AzAPICallModule = @{ #SubscriptionId4AzContext = $null #specify Subscription Id #DebugAzAPICall = $true #WriteMethod = 'Output' #Debug, Error, Host, Information, Output, Progress, Verbose, Warning (default: host) #DebugWriteMethod = 'Warning' #Debug, Error, Host, Information, Output, Progress, Verbose, Warning (default: host) #SkipAzContextSubscriptionValidation = $true #Use if the account doesn´t have any permissions on Management Groups, Subscriptions, Resource Groups or Resources } $azAPICallConf = initAzAPICall @parameters4AzAPICallModule
-
Define variables
$MicrosoftGraphAppId = "00000003-0000-0000-c000-000000000000" $AzGovVizAppName = "<App registration name that will be used to run AzGovViz>"
-
Get Microsoft Graph permissions role IDs and the create app registration
$apiEndPoint = $azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph $apiEndPointVersion = '/v1.0' $api = '/servicePrincipals' $optionalQueryParameters = "?`$filter=(displayName eq 'Microsoft Graph')&$count=true&" $uri = $apiEndPoint + $apiEndPointVersion + $api + $optionalQueryParameters $azAPICallPayload = @{ uri= $uri method= 'GET' currentTask= "'$($azAPICallConf['azAPIEndpoints'].($apiEndPoint.split('/')[2])) API: Get - Groups'" consistencyLevel= 'eventual' noPaging= $true AzAPICallConfiguration = $azAPICallConf } $graphApp = AzAPICall @azAPICallPayload $appRole = $graphApp.appRoles | Where-Object { $_.value -eq 'Application.Read.All' } | Select-Object -ExpandProperty id $userRole = $graphApp.appRoles | Where-Object { $_.value -eq 'User.Read.All' } | Select-Object -ExpandProperty id $groupRole = $graphApp.appRoles | Where-Object { $_.value -eq 'Group.Read.All' } | Select-Object -ExpandProperty id $pimRole = $graphApp.appRoles | Where-Object { $_.value -eq 'PrivilegedAccess.Read.AzureResources' } | Select-Object -ExpandProperty id $body = @" { "DisplayName":"$AzGovVizAppName", "requiredResourceAccess" : [ { "resourceAppId" : "$MicrosoftGraphAppId", "resourceAccess": [ { "id": "$appRole", "type": "Role" }, { "id": "$userRole", "type": "Role" }, { "id": "$groupRole", "type": "Role" }, { "id": "$pimRole", "type": "Role" } ] } ] } "@ $AzGovVizAppObjectId = (AzAPICall -method POST -body $body -uri "$($azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph)/v1.0/applications" -AzAPICallConfiguration $azAPICallConf -listenOn 'Content' -consistencyLevel 'eventual').id do { Write-Host "Waiting for the AzGovViz service principal to get created..." Start-Sleep -seconds 20 $AzGovVizAppId = (AzAPICall -method GET -uri "$($azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph)/v1.0/applications/$AzGovVizAppObjectId" -AzAPICallConfiguration $azAPICallConf -listenOn 'Content' -consistencyLevel 'eventual' -skipOnErrorCode 404).appId } until ($null -ne $AzGovVizAppId) Write-host "AzGovViz service principal created successfully."
-
Grant admin consent using the Microsoft Entra admin center.
Result: A service principal is created with the necessary API permissions and admin consent granted. The following screenshot shows the API permissions and granted status.
2. Create copy of the Azure Governance Visualizer accerlator in your own GitHub repository
:computer_mouse: Use the GitHub website:
-
Navigate to the accelerator GitHub repository.
-
Create a new repository from the accelerator template.
- Ensure the new repository is set to Private.
:keyboard: Use PowerShell and the GitHub CLI:
-
Install the GitHub CLI
-
Login to your GitHub account.
gh auth login
-
Create a private repository from the accelerator template
$directoryToCloneAccelerator = "<Local directory to clone the Accelerator's repository>" $GitHubOrg = "<GitHub organization to use>" $GitHubRepository = "Azure-Governance-Visualizer" ### Create a new repository from template gh repo create $GitHubRepository --template Azure/Azure-Governance-Visualizer-Accelerator --private New-Item -ItemType Directory -Path $directoryToCloneAccelerator -Force cd $directoryToCloneAccelerator gh repo clone "$GitHubOrg/$GitHubRepository" Set-Location $GitHubRepository
3. Configure federated credentials for the service principal created in the first step
:computer_mouse: Use the Microsoft Entra admin center:
- Navigate to the Microsoft Entra admin center
- Click on 'App registrations'
- Search for the Application that you created earlier and click on it
- Under 'Manage' click on 'Certificates & Secrets'
- Click on 'Federated credentials'
- Click 'Add credential'
- Select Federation credential scenario 'GitHub Actions deploying Azure Resources'
- Fill the field 'Organization' with your GitHub organization name
- Fill the field 'Repository' with your GitHub repository name
- For the entity type select 'Branch'
- Fill the field 'GitHub branch name' with your branch name
- Fill the field 'Name' with a name (e.g. AzureGovernanceVisualizer_GitHub_Actions)
- Click 'Add'
:keyboard: Use PowerShell and the GitHub CLI:
$gitHubRef= ":ref:refs/heads/main"
$subject = "repo:$gitHubOrg/$GitHubRepository$gitHubRef"
$body = @"
{
"audiences": [
"api://AzureADTokenExchange"
],
"subject":"$subject",
"issuer":"https://token.actions.githubusercontent.com",
"name":"AzGovVizCreds"
}
"@
AzAPICall -method POST -body $body -uri "$($azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph)/v1.0/applications/$AzGovVizAppObjectId/federatedIdentityCredentials" -AzAPICallConfiguration $azAPICallConf -listenOn 'Content' -consistencyLevel 'eventual'
4. Grant permissions in Azure for the AzGovViz service principal created in the first step
NOTE: To assign roles, you must have 'Microsoft.Authorization/roleAssignments/write' permissions on the target management group scope (such as the built-in RBAC role 'User Access Administrator' or 'Owner')
:computer_mouse: From the Azure portal:
Create a 'Reader' RBAC role assignment on the target management group scope for the service principal that will run Azure Governance Visualizer.
:keyboard: Use PowerShell:
$managementGroupId = "<managementGroupId>"
New-AzRoleAssignment `
-ApplicationId $AzGovVizAppId `
-RoleDefinitionName "Reader" `
-Scope /providers/Microsoft.Management/managementGroups/$managementGroupId
5. Create a Microsoft Entra application for user authentication to the Azure Web App that will host AzGovViz
:computer_mouse: From the Microsoft Entra admin center:
-
Create an app registration in Microsoft Entra ID for your Azure App Web App.
In the Redirect URIs section, select Web for platform and type the URI in the following format: "https://<webapp_name>.azurewebsites.net/.auth/login/aad/callback"
-
Create a secret for your app registration: Certificates & secrets > Client secrets > New client secret > Enter a description and expiration date > Add
Copy the secret's value and store it in a safe place, keeping mind you won't be able to view it again later <img width="971" alt="image" src="https://github.com/user-attachments/assets/8132e138-bab5-4e04-ab4b-d82eb51afc2f">
-
Click on Authentication and under Implicit grant and hybrid flows, enable ID tokens to allow OpenID Connect user sign-ins from App Service. Select Save.
-
From the left navigation, select Expose an API > Add > Save.
-
Click on Add a scope and provide the values as the screenshot.
-
From the left navigation, select Manifest and set "groupMembershipClaims" to "SecurityGroup".
:keyboard: Use PowerShell:
# 2-60 Alphanumeric, hyphens and Unicode characters. Can't start or end with hyphen. A web site must have a globally unique name.
$webAppName = "<Azure Web App name to publish AzGovViz>"
$WebApplicationAppName = "<App registration name that will be used to add Microsoft Entra ID-based authentication to the web app>"
$body = @"
{
"DisplayName":"$WebApplicationAppName",
"web": {
"redirectUris": [
"https://$webAppName.azurewebsites.net/.auth/login/aad/callback"
],
"implicitGrantSettings": {
"enableIdTokenIssuance": true
}
}
}
"@
$webAppSP = AzAPICall -method POST -body $body -uri "$($azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph)/v1.0/applications" -AzAPICallConfiguration $azAPICallConf -listenOn 'Content' -consistencyLevel 'eventual'
$webAppSPAppId = $webAppSP.appId
$webAppSPObjectId = $webAppSP.Id
do {
Write-Host "Waiting for the Azure WebApp app registration to get created..."
Start-Sleep -seconds 30
$webApp = AzAPICall -uri "$($azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph)/v1.0/applications/$webAppSPObjectId" -AzAPICallConfiguration $azAPICallConf -listenOn 'Content' -consistencyLevel 'eventual'
} until ( $null -ne $webApp)
Write-host "Azure Web App app registration created successfully."
# Add an API scope for the Web App
$body = @"
{
"identifierUris" : [
"api://$webAppSPAppId"
],
"groupMembershipClaims" : "SecurityGroup",
"api": {
"oauth2PermissionScopes": [
{
"value": "user_impersonation",
"adminConsentDescription": "AzGovViz Web App Microsoft Entra ID authentication",
"adminConsentDisplayName": "AzGovViz Web App Microsoft Entra ID authentication",
"type": "User",
"id": "$webAppSPAppId"
}
]
}
}
"@
AzAPICall -method PATCH -body $body -uri "$($azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph)/v1.0/applications/$webAppSPObjectId" -AzAPICallConfiguration $azAPICallConf -listenOn 'Content' -consistencyLevel 'eventual'
# Generate client secret
$body = @"
{
"passwordCredential":{
"displayName": "AzGovVizWebAppSecret"
}
}
"@
$webAppSPAppSecret = (AzAPICall -method POST -body $body -uri "$($azAPICallConf['azAPIEndpointUrls'].MicrosoftGraph)/v1.0/applications/$webAppSPObjectId/addPassword" -AzAPICallConfiguration $azAPICallConf -listenOn 'Content' -consistencyLevel 'eventual').secretText
6. Create a resource group and assign necessary RBAC roles
NOTES:
To assign roles, you must have 'Microsoft.Authorization/roleAssignments/write' permissions on the target management group scope (such as the built-in RBAC role 'User Access Administrator' or 'Owner').
Make sure that the resource provider Microsoft.Web is registered on the subscription where the Azure Web App hosting AzGovViz will be deployed.
:computer_mouse: From the Azure portal:
- Create a new resource group in Azure.
- Assign the following roles to the AzGovViz service principal the on the newly created resource group.
:keyboard: Use PowerShell:
$subscriptionId = "<Subscription Id>"
$resourceGroupName = "Name of the resource group where the Azure Web App will be created>"
$location = "<Azure Region for the Azure Web App>"
Select-AzSubscription -SubscriptionId $subscriptionId
New-AzResourceGroup -Name $resourceGroupName -Location $location
New-AzRoleAssignment -ApplicationId $AzGovVizAppId -RoleDefinitionName "Web Plan Contributor" -ResourceGroupName $resourceGroupName
New-AzRoleAssignment -ApplicationId $AzGovVizAppId -RoleDefinitionName "WebSite Contributor" -ResourceGroupName $resourceGroupName
7. Create the GitHub secrets, variables, and permissions
:computer_mouse: From the GitHub website:
-
Create the following GitHub secrets on the repository.
Secret Value CLIENT_ID Application ID of the identity that will run Azure Governance Visualizer ENTRA_CLIENT_ID Application ID of the identity that will be used to configure user authentication to the Azure Web App ENTRA_CLIENT_SECRET Secret of the identity that will be used to configure user authentication to the Azure Web App SUBSCRIPTION_ID Azure subscription ID TENANT_ID Microsoft Entra tenant ID MANAGEMENT_GROUP_ID Azure management group ID -
Create the following GitHub variables on the repository.
Variable Value RESOURCE_GROUP_NAME Name of the pre-created resource group to host the Azure Web App WEB_APP_NAME Globally unique name of the Azure Web App -
Enable GitHub actions to create and approve pull requests on the repository.
:keyboard: Use PowerShell and the GitHub CLI:
$subscriptionId = "<Azure subscription ID>"
$tenantId = "<Microsoft Entra tenant ID>"
$managementGroupId = $managementGroupId
$resourceGroupName = $resourceGroupName
$clientId = $AzGovVizAppId
$webAppClientId = $webAppSPAppId
$webAppClientSecret = $webAppSPAppSecret
# Create GitHub repository secrets and variables
gh secret set 'CLIENT_ID' -b $clientId
gh secret set 'ENTRA_CLIENT_ID' -b $webAppClientId
gh secret set 'ENTRA_CLIENT_SECRET' -b $webAppClientSecret
gh secret set 'SUBSCRIPTION_ID' -b $subscriptionId
gh secret set 'TENANT_ID' -b $tenantId
gh secret set 'MANAGEMENT_GROUP_ID' -b $managementGroupId
gh variable set 'RESOURCE_GROUP_NAME' -b $resourceGroupName
gh variable set 'WEB_APP_NAME' -b $webAppName
# Configure GitHub actions permissions
gh api -X PUT /repos/$GitHubOrg/$GitHubRepository/actions/permissions/workflow -F can_approve_pull_request_reviews=true
8. Deploy Azure Governance Visualizer Azure resources and application
-
Navigate to Actions in your newly created repository.
-
Run the DeployAzGovVizAccelerator workflow to initialize the accelerator, deploy the Azure Web App and configure Microsoft Entra authentication for it. By default, the web app is accessible to any authenticated user in the current tenant. To limit access to certain users, provide the ObjectId of an Entra ID group. Important note: the group must be of type Security and not Microsoft 365.
This workflow will trigger another workflow to sync the latest AzGovViz code to your repository.
You will have to add the AzGovViz parameters you need into the DeployAzGovViz workflow and enable the schedule option if you want to continuously run Azure Governance Visualizer.
As an example, you can add the NoPIMEligibility parameter if you don't have PIM.
-
Then, run the DeployAzGovViz workflow to deploy AzGovViz and publish it to the Azure Web App
:checkered_flag: Try it out!
Once the DeployAzGovViz workflow has been ran successfully, navigate to the Azure Web App on the Azure portal and click Browse to access the visualizer. You'll notice that you'll need to be authenticated with Microsoft Entra ID.
:broom: Clean up resources
If you were deploying the Azure Governance Visualizer for exploratory purposes, you'll want to delete the created Azure resources to prevent undesired costs from accruing and remove the related Microsoft Entra ID objects. Follow these steps to delete all resources created as part of this reference implementation.
- Delete the create resource group.
- Delete the private GitHub repository.
- Delete the local copy of the GitHub repository created on your machine.
- Delete the two service principals created for the AzGovViz authorization and the Azure Web App Entra ID authentication.
Additional topics
Azure Web App configuration
You can configure some aspects of the Azure Web application where AzGovViz is published by editing the webApp.parameters.json file in the bicep folder.
Keep the Azure Governance Visualizer code up-to-date
To keep the Azure Governance Visualizer's code up-to-date, the workflow SyncAzGovViz runs on a schedule to check for new versions. The default setting is that this is enabled to push updates automatically to your repository. If you need to control those new version updates, you will have to set AutoUpdateAzGovViz to false so you would get a pull request every time there is a new version to review.
Keep the Azure Governance Visualizer Accelerator code up-to-date
To keep the Azure Governance Visualizer Accelerator code up-to-date, the workflow SyncAccelerator runs on a schedule to check for new versions. Everytime there is a new update to the accelerator's code, you would get a pull request submitted to your repository and the new release will be merged to a releases folder where you can move to newer versions of this accelerator at your own pace.
Sources to documentation
For more information on Azure Governance Visualizer, please visit the official docs and the Azure landing zone documentation.