Demystifying Microsoft Entra Workload Identity Premium Licensing
A Practical PowerShell Approach
Following the recent blog series on "Mastering Workload Identity Security in Microsoft Entra ID," I have received fantastic feedback and many insightful questions. A recurring theme has been a desire for more clarity on licensing for Microsoft Entra Workload Identities Premium. Understanding when and for which workload identities a premium licence is required is crucial for planning and compliance.
This blog post aims to shed more light on this topic. It provides a PowerShell script designed to help you estimate the number of Workload Identity Premium licences you might need based on analysing your service principals and their use of certain premium features like Conditional Access and (conceptually) Access Reviews.
Disclaimer: The script and information provided here are for estimation and educational purposes. Microsoft's licensing terms are the definitive source of truth. Always consult the official Microsoft documentation and your Microsoft licensing specialist for precise licensing requirements and purchasing decisions. This script uses the Microsoft Graph PowerShell SDK.
Understanding Microsoft Entra Workload Identity Premium Licensing - Key Principles
As covered in the main series, Microsoft Entra Workload Identities Premium is a separate license that unlocks advanced security features. Here are the core principles:
Licence per Protected Workload Identity: You generally need a licence for each workload identity (primarily service principals, but can include managed identities in specific scenarios like Access Reviews) that you want to protect or manage using the premium features.
Tenant-Wide Feature Enablement: Purchasing the licences enables the premium features (like Conditional Access for Workload Identities, Identity Protection) across your tenant for eligible workload identities. You don't assign the licence directly to an individual service principal.
Key Features Triggering Licence Need:
Conditional Access for Workload Identities: If a service principal (typically a single-tenant, non-Microsoft registered SP) eligible for this feature is included in the scope of a Conditional Access policy specifically designed for workload identities, it is considered protected and would generally require a license.
Identity Protection for Workload Identities: If your organisation relies on Identity Protection to detect and remediate risks for specific workload identities, a premium feature benefits those identities.
Access Reviews for Workload Identities: If a service principal (including managed identities if assigned privileged Microsoft Entra roles) is included in an Access Review for its role assignments, it is governed by a premium feature.
App Health Recommendations: While some recommendations might be available in the free tier, the full suite of insights and proactive recommendations for workload identity health is part of the premium offering.
Microsoft References for Licensing:
Before diving into the script, here are some essential Microsoft resources:
Microsoft Entra Workload ID frequently asked questions (FAQs): https://learn.microsoft.com/en-us/entra/workload-id/workload-identities-faqs
Microsoft Entra pricing (includes Workload Identities): https://www.microsoft.com/en-us/security/business/microsoft-entra-pricing
Licensing fundamentals for Microsoft Entra ID: https://learn.microsoft.com/en-us/entra/fundamentals/licensing
PowerShell Script for Estimating Workload Identity Premium Licence Needs
The following script retrieves service principals and Conditional Access policies using the Microsoft Graph PowerShell SDK. It then attempts to categorise service principals and identify those that might require licensing based on their use of these features.
Important Notes on the Script:
Microsoft Graph SDK: This script requires Microsoft Graph PowerShell SDK modules. It explicitly attempts to install and import Microsoft.Graph.Identity.SignIns. However, it also uses Get-MgServicePrincipal (from Microsoft.Graph.Applications or Microsoft.Graph.DirectoryObjects) and Connect-MgGraph (from Microsoft.Graph.Authentication). For the script to run correctly, ensure the full Microsoft.Graph module is installed or at least these specific sub-modules.
Permissions: You'll need to connect to Microsoft Graph with sufficient permissions. The script requests "Application.Read.All", "Policy.Read.All", "Directory.Read.All".
Estimation Only: This script provides an estimate. Its logic for identifying "custom" vs "first-party" apps and managed identities is based on specific interpretations of properties and may require adjustment for your environment.
Service Principal Categorisation Logic:
Managed Identities: Identified if $sp.Tags -contains "WindowsAzureManagedIdentity".
Custom Applications: Identified if $sp.AppOwnerOrganizationId -ne "00000003-0000-0000-c000-000000000000". Note: "00000003-0000-0000-c000-000000000000" is the AppId for Microsoft Graph, not a typical AppOwnerOrganizationId. Custom applications registered in your tenant usually have an AppOwnerOrganizationId matching your tenant's ID or $null. Microsoft first-party applications usually have an AppOwnerOrganizationId of f8cdef31-a31e-4b4a-93e4-5f571e91255a. This script's logic for distinguishing custom from first-party apps based on this condition is specific and may not align with standard definitions.
First-Party Microsoft Apps: Categorised by the else condition after the "Custom Application" check.
Conditional Access Check: The Check-ConditionalAccess function checks if a service principal's AppId is included in the IncludeApplications condition of a CA policy. This typically applies to older CA policy configurations or policies broadly targeting applications. Modern CA policies for workload identities specifically target service principal Object IDs in the Assignments section. This script does not currently check the Assignments block for workload identity targeting.
Access Review Logic (Placeholder): The Check-AccessReview function is a placeholder and currently returns $true for every service principal it checks. This means it will count all Managed Identities and all "First-Party Microsoft Apps" (per the script's categorisation) as needing licenses due to this function. You MUST replace this placeholder with actual logic to check your Access Review configurations and get a meaningful estimate for these categories.
Identity Protection: This script does not directly check for Identity Protection usage. Licences are generally needed for workload identities protected by these features.
# Ensure required Microsoft Graph module is installed
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Identity.SignIns)) {
Write-Output "Installing required module: Microsoft.Graph.Identity.SignIns..."
Install-Module Microsoft.Graph.Identity.SignIns -Scope CurrentUser -Force
}
# Import the module
Import-Module Microsoft.Graph.Identity.SignIns
# Connect to Microsoft Graph with required scopes
Connect-MgGraph -Scopes "Application.Read.All", "Policy.Read.All", "Directory.Read.All"
# Get all service principals
$servicePrincipals = Get-MgServicePrincipal -All
# Get all Conditional Access policies
$caPolicies = Get-MgIdentityConditionalAccessPolicy -All
# Initialize counters and list
$customAppCount = 0
$firstPartyAppCount = 0
$managedIdentityCount = 0
$spNeedingLicenses = @()
# Function to check if a service principal is included in access reviews
function Check-AccessReview {
param ($sp)
# Placeholder: Replace with actual logic to check access reviews
return $true
}
# Function to check if a service principal is included in Conditional Access policies
function Check-ConditionalAccess {
param ($sp, $caPolicies)
foreach ($policy in $caPolicies) {
if ($policy.Conditions.Applications.IncludeApplications -contains $sp.AppId) {
return $true
}
}
return $false
}
# Loop through each service principal
foreach ($sp in $servicePrincipals) {
$spType = ""
$needsLicense = $false
if ($sp.Tags -contains "WindowsAzureManagedIdentity") {
if (Check-AccessReview -sp $sp) {
$managedIdentityCount++
$spType = "Managed Identity"
$needsLicense = $true
}
}
elseif ($sp.AppOwnerOrganizationId -ne "00000003-0000-0000-c000-000000000000") {
if (Check-ConditionalAccess -sp $sp -caPolicies $caPolicies) {
$customAppCount++
$spType = "Custom Application"
$needsLicense = $true
}
}
else {
if (Check-AccessReview -sp $sp) {
$firstPartyAppCount++
$spType = "First-Party Microsoft App"
$needsLicense = $true
}
}
if ($needsLicense) {
$spNeedingLicenses += [PSCustomObject]@{
DisplayName = $sp.DisplayName
AppId = $sp.AppId
ObjectId = $sp.Id
Type = $spType
}
}
}
# Output the results in a table
$spNeedingLicenses | Format-Table -AutoSize
# Summary
Write-Output ""
Write-Output "Custom Application Service Principals requiring licenses: $customAppCount"
Write-Output "First-Party Microsoft Application Service Principals requiring licenses: $firstPartyAppCount"
Write-Output "Managed Identities requiring licenses: $managedIdentityCount"
$totalLicenses = $customAppCount + $firstPartyAppCount + $managedIdentityCount
Write-Output "Total licenses needed: $totalLicenses"
Troubleshooting Connection Issues (Connect-MgGraph)
If you encounter authentication failures when the script attempts to run Connect-MgGraph:
Check Entra ID Sign-in Logs (Critical First Step):
As a Microsoft Entra administrator, navigate to the Microsoft Entra admin centre> Identity > Monitoring & health > Sign-in logs.
Filter the logs for the user account attempting to run the PowerShell script.
Look for the failed authentication attempt around the time you ran the script.
Examine the Authentication Details, Basic Info, and Conditional Access tabs for that log entry. This is the most likely place to find specific error codes (like AADSTS numbers) and details about why the authentication failed.
Module Installation: Ensure the Microsoft.Graph module (and its dependencies like Microsoft.Graph.Authentication, Microsoft.Graph.Applications, Microsoft.Graph.Identity.SignIns) is correctly installed: Install-Module Microsoft.Graph -Scope CurrentUser -Force.
Run Interactively: Ensure you are running the script from a PowerShell session on a machine with a modern web browser where you can complete an interactive sign-in process.
Specify Audience for Graph: As implemented in the script, using -Audience 'organisations' with Connect-MgGraph can resolve certain scope validation issues.
Permissions/Consent: Ensure the account used has permissions to grant consent for the requested scopes.
SDK/Module Version: Ensure your Microsoft Graph PowerShell SDK is up-to-date: Update-Module Microsoft.Graph. Then, close and reopen your PowerShell session.
Network Issues: Proxies, firewalls, or other network configurations might block access to Microsoft login URLs.
Interpreting the Script's Output
The script will output:
A table listing service principals it identified as potentially needing licenses, along with their type (as determined by the script's logic) and the reason.
Summary counts for "Custom Applications," "First-Party Microsoft Applications," and "Managed Identities."
A total estimated count based on its logic.
Important notes and caveats regarding the estimation.
Conclusion: Use as a Guide, Not Gospel
This PowerShell script offers a starting point for estimating your Microsoft Entra Workload Identity Premium licence needs. However, due to its specific logic for categorising applications, the placeholder for Access Review checks, and how it checks Conditional Access policies (targeting AppIDs in Conditions), its results should be treated as a preliminary estimate and a tool for further investigation.
For a more accurate assessment, especially regarding Conditional Access policies specifically designed for workload identities (targeting SP ObjectIDs in Assignments), refer to the Graph SDK scripts in Blog 3 of the main series. Always cross-reference with the official Microsoft documentation and engage with your Microsoft account team or licensing specialist to ensure full compliance.
I hope this additional post provides some assistance in navigating the licensing aspects of securing your vital workload identities!