Search code examples
azurepowershellentra

Azure App Registration - Read Subscriptions/resources/entra GAs


I assume this is a role I am missing..

I created an app registration that has certificate based authentication. When I authenticate I want to be able to pull all subscriptions because I plan on looping through them and finding all VMs in each subscription/resource group.

I also want to pull down the global admins in the entra tenant from this certificate.

Permissions I am assigning my app registration

$app = Get-AzADApplication  -ApplicationId $sp.AppId
$appObjectId = $app.Id

# GraphAPI - Directory.Read.All
# Add-AzADAppPermission -ObjectId $appObjectId -ApiId "00000003-0000-0000-c000-000000000000" -PermissionId "4e9b66a2-74a1-4d86-a0cb-1a01e40e7d77"
# # Add-AzADAppPermission -ObjectId "55fad647-6f5d-489f-b85e-00f96406ee9b" -ApiId "00000003-0000-0000-c000-000000000000" -PermissionId "5f8c59db-677d-491f-a6b8-5f174b11ec1d"
# Add Microsoft Graph Directory.Read.All permission
Add-AzADAppPermission -ObjectId $appObjectId -ApiId "00000003-0000-0000-c000-000000000000" -PermissionId "aef1f2db-fc2a-4d63-bcf5-e9a7a7802c9b"
# Add Microsoft Graph Directory.Read.All permission
Add-AzADAppPermission -ObjectId $appObjectId -ApiId "00000003-0000-0000-c000-000000000000" -PermissionId "df021288-bdef-4463-88db-98f22de89214"

# Azure Service Management - Reader
Add-AzADAppPermission -ObjectId $appObjectId -ApiId "00000002-0000-0000-c000-000000000000" -PermissionId "b7d27f52-6659-42b8-8164-4a0e63a2c156"

Creating app registration:

$cert = New-SelfSignedCertificate -CertStoreLocation "cert:\CurrentUser\My" -Subject $applicationName -KeySpec KeyExchange -NotAfter (Get-Date).AddYears(1)
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())

# Assign Certificate to App in Entra
$sp = New-AzADServicePrincipal -DisplayName $applicationName -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore 
Start-Sleep -Seconds 3

# Export the certificate to a PFX file
$cert | Export-PfxCertificate -FilePath $certFilePath -Password (ConvertTo-SecureString -String $certPassword -Force -AsPlainText)


Solution

  • Initially, I created one certificate same as you and uploaded it to app registration as below:

    enter image description here

    To add Directory.Read.All permission of Application type and Reader role to service principal at root level, make use of below updated script:

    $applicationName = "SriCertApp"
    
    $spId = (Get-AzADServicePrincipal -DisplayName $applicationName).Id
    
    # Assign Reader role to the Service Principal under specific subscription
    New-AzRoleAssignment -ObjectId $spId `
        -RoleDefinitionName "Reader" `
        -Scope "/"
    
    Write-Host "Reader role assigned to Service Principal."
    
    # Get the Azure AD Application by AppId
    $app = Get-AzADApplication -ApplicationId $sp.AppId
    $appObjectId = $app.Id
    
    # Add Microsoft Graph Directory.Read.All permission of Application type
    Add-AzADAppPermission -ObjectId $appObjectId `
        -ApiId "00000003-0000-0000-c000-000000000000" `
        -PermissionId "7ab1d382-f21e-4acd-a863-ba3e13f7da61" `
        -Type Role
    
    Write-Host "Microsoft Graph Directory.Read.All permission granted."
    

    Response:

    enter image description here

    To confirm that, you can check the same in Azure Portal where role and permission assigned successfully like this:

    Reader role:

    enter image description here

    Directory.Read.All permission

    enter image description here

    Make sure to grant admin consent to above permission that allows service principal to read directory data:

    enter image description here

    Now, make use of below script to fetch all VMs across all subscriptions connecting with certificate authentication:

    $appId = "appId"
    $tenantId = "tenantId"
    $thumbprint = "cert_thumbprint"
    
    Connect-AzAccount -ApplicationId $appId -Tenant $tenantId -CertificateThumbprint $thumbprint
    
    $subscriptions = Get-AzSubscription
    $allVms = @()
    
    foreach ($subscription in $subscriptions) {
        Set-AzContext -SubscriptionId $subscription.Id
        $vms = Get-AzVM
    
        foreach ($vm in $vms) {
            $vmDetails = [PSCustomObject]@{
                VMName = $vm.Name
                SubscriptionName = $subscription.Name
                ResourceGroupName = $vm.ResourceGroupName
            }
            $allVms += $vmDetails
        }
    }
    
    $allVms | Format-Table -AutoSize
    $allVms | Export-Csv -Path "C:\test\vms.csv" -NoTypeInformation
    

    Response:

    enter image description here

    To pull down the global admins in the Microsoft Entra tenant with certificate authentication, make use of below Microsoft Graph script:

    $appId = "appId"
    $tenantId = "tenantId"
    $thumbprint = "thumbprint"
    $roleName = "Global Administrator"
    
    Connect-MgGraph -ClientId $appId -TenantId $tenantId -CertificateThumbprint $thumbprint
    
    $adminRole = Get-MgDirectoryRole -Filter "DisplayName eq '$roleName'"
    
    if ($adminRole) {
        $roleMembers = Get-MgDirectoryRoleMember -DirectoryRoleId $adminRole.Id
    
        if ($roleMembers) {
            $roleMembers | ForEach-Object {
                [PSCustomObject]@{
                    DisplayName = $_.AdditionalProperties["displayName"]
                    Id          = $_.Id
                }
            } | Format-Table DisplayName, Id
        } else {
            Write-Host "No members found for the role: $roleName"
        }
    } else {
        Write-Host "Role '$roleName' not found"
    }
    

    Response:

    enter image description here