Microsoft Cloud Access Tokens
Marius Elmiger
The potential risks posed by foreign workload identities
This article explores an example of how Microsoft Entra workload identities can inadvertently extend the security boundary of a Entra tenant to a foreign tenant.
A security boundary is the definition of a logical or physical boundary that should separate IT environments or solutions. For a fresh Active Directory installation, the security perimeter is the forest. For Entra ID, it would be the tenant. Security boundaries can be intentionally or unintentionally extended by introducing relationships with other IT solutions that are not part of the initial implementation. Regular audits, robust protocols, and security tools can help maintain the integrity of these boundaries. Ultimately, the goal is to find a balance between accessibility and security, ensuring that the right entity has the right access at the right time. For more examples of relationships that can extend security boundaries, see the following article Attack Path Analysis.
Entra Workload identities in the Microsoft Cloud describe non-personal accounts assigned to a workload, such as an application, service, virtual machines, script, or container, to authenticate and access other services and resources. Microsoft describes three three types of workload identities in there workload identites article.
Access for service principals to resources can be assigned with delegation or application API permissions and requires administrator or user consent.
API permissions authorize the service principal from the application to call other public APIs if consented by users or administrators. API permissions often come in the Resource.Operation.Constraint
scope format. For example, Directory.Read.All
means that the principal granted this permission can read data in the tenant, such as users, groups and apps.
App roles define access definitions to the local application. One role can grant multiple permissions. For example, the Microsoft Graph application has several application roles defined. Directory.Read.All
is one of them. The easiest way to verify the detailed API permissions granted by, for example, the Directory.Read.All
app role is to visit Merill Fernando’s Microsoft Graph Permission Explorer website.
After a brief introduction to what Security Boundaries, Entra Applications and Entra Service Principals are, the next chapter uses a very practical example to show how a multi-tenant application can introduce a Security Boundary risk. If the explanations above were too brief, the article by Thomas Naunheim explains Entra Workload Identities in detail. Andy Robbins from SpecterOps has also published an article on the recent Microsoft breach What happened? What should Azure Admins do? in which he explains in great detail how external multi-tenant applications were used during the breach. Both articles are highly recommended reading.
The mytenant.onmicrosoft.com
tenant administrator registers a multitenant application from the foreigntenant.onmicrosoft.com
tenant. The application promises smooth Entra role management. After the global administrator accepted the application with the scopes RoleManagement.ReadWrite.Directory
and Directory.Read.All
, a service principal is automatically created in the mytenant.onmicrosoft.com
tenant as a local representation of the application. This action inadvertently extended the security boundary to the untrusted foreigntenant.onmicrosoft.com
tenant.
The following step-by-step POC explores in detail the implications shown in the figure above.
mytenant.onmicrosoft.com
and the foreigntenant.onmicrosoft.com
)foreigntenant.onmicrosoft.com
at https://portal.azure.comMicrosoft Entra ID
App registrations
New registration
Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant)
Daemon application
Node.js console
standard user
. The URL will be needed later for step 1Certificates & secrets
API permissions
Add a permission
Microsoft Graph
Application permissions
RoleManagement.ReadWrite.Directory
and Directory.Read.All
Add permissions
for each of the App rolesWith step 0 completed we are ready to register the foreignApp application in the mytenant.onmicrosoft.com
. The setup could be improved by creating a web application and adding a reply address. However, this is optional for the POC.
mytenant.onmicrosoft.com
at https://porta.azure.comhttps://login.microsoftonline.com/organizations/adminconsent?client_id=e037294a-d64a-4242-977a-3868012d69a5
mytenant.onmicrosoft.com
tenant to the foreignapp.onmicrosoft.com
organization. Whoever that is (?) You could check some publicly available information using the handy tenant information OSINT tool from DrAzureAD. But what has actually happened in the background? By the way, the error: No reply address is registered for the application
can be ignored as everything worked fine also without a reply addressmytenant.onmicrosoft.com
, go to Enterprise Applications
in the Azure portal. You will see that a Service Principal named foreignApp has been successfully created to represent the multitenant application. You can compare the application ID with the application (client) ID in step 0. They are the same.foreignApp
and navigating to Permissions
, the previously approved permissions can be seen including the admin consent status.Ok, the stage is set, now for the fun part.
The next steps are scripted, as this is the only way to log in with a service principal. The script is called consentIsTheMindkiller.ps1 and can be found in the gist repository.
$myTenantId = "cdfdd915-..." # The tenant registering the foreign application (Source: My Tenant) $foreignTenantId = "d2a16643-37f9-..." # The tenant who is hosting the application (Source: Foreign Tenant) $spPassword = "1N98Q~qo7oKGhA3L~t~OgQKVDPL.iasdas32" # The client secret from the app (Source: Foreign Tenant) $appName = "foreignApp" # The app name (Source: Foreign Tenant)
foreignapp.onmicrosoft.com
tenant to get the Application ID$foreignApp = Get-MgServicePrincipal -All -Filter $appFilter
mytenant.onmicrosoft.com
to login with the credentials from foreignapp.onmicrosoft.com
to the mytenant.onmicrosoft.com
tenant.$spPwd= ConvertTo-SecureString $spPassword -AsPlainText -Force $psCred = New-Object System.Management.Automation.PSCredential($foreignApp.AppId, $spPwd) Connect-MgGraph -TenantId $myTenantId -ClientSecretCredential $psCred -NoWelcome
RoleManagement.ReadWrite.Directory
application role granted in step 1, the script adds the foreignapp service principal to the Global Administrator role.$globalAdmin = Get-MgDirectoryRole | Where-Object { $_.DisplayName -eq "Global Administrator" } New-MgDirectoryRoleMemberByRef -DirectoryRoleId $globalAdmin.Id -BodyParameter @{"@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($foreignsp.id)"}
Granting privileged application permissions to a foreign application effectively extends the security perimeter to the foreign application tenant. After all, this is how SaaS works. However, we haven’t found a way for the foreign tenant to know who has signed up to the multi-tenant application over the Azure portal or the Graph API. This would be possible, of course, if the third party hosted a website that directed people to register and ultimately use the application. But if you end up in a tenant and find many foreign multi-tenant apps, it would not be trivial to find a victim tenant to abuse the scenario described above. Unless it is a known application.
What can we do about it? Firstly, it is critical to vet any foreign SaaS application before agreeing to any application permissions or delegations. After that, the following step 3 helps to review already existing foreign service principals in a tenant.
In this step, we are the administrator of the mytenant.onmicrosoft.com
tenant that previously accepted the application permissions.
mytenant.onmicrosoft.com
tenant who is authorised to read service principal information.mytenant.onmicrosoft.com
via the AppOwnerOrganisationId
attribute. The result is displayed on the command line and in the PowerShell Grid view.$foreignsp = Get-MgServicePrincipal -All | Where-Object { $_.AppOwnerOrganizationId -ne $myTenantId -and $_.AppOwnerOrganizationId -ne $null }
approleValue
and appDisplayname
are the granted app roles to the resourceDisplayName
In a production tenant, Step 3 is an important audit task to check the permissions of foreign service principals. Step 3 is also available as a separate script. The script is called checkForForeignServicePrincipals.ps1 and can be found in the gist repository.
One of the many challenges in any IT environment, and especially in the cloud, is not inadvertently extending the security boundary to an unknown, untrusted entity. In a Microsoft cloud tenant, there are several ways to extend the security boundary, for example with Azure Lighthouse, granular delegated admin privileges (GDAP), multi-tenant applications, third-party solutions that only support cloud-only accounts, third-party agents on IaaS workloads, or DevOps solutions. In an Active Directory environment, we have similar challenges, although the cloud has a more dangerous attack surface. As the example above shows, it only takes one click from a privileged administrator to introduce a security boundary violation to an unknown tenant. This makes it all the more important to know what the security boundary of a given tenant really is, and to test new functionality in a non-production tenant. IT administrators should be adequately trained to have the knowledge to operate a cloud environment. We often find that Workload Identities and their capabilities are not fully understood during our assessments, which is why they are listed in our Top 10 Riskiest Cloud Configurations. Microsoft also does not make it easy to manage and audit Workload Identities and their permissions. Tools such as ROADTools, BloodHound, scripts like Export-MsIdAppConsentGrantReport or automated monitoring of Workload Identities permissions and changes as described in Hunting Service Principals with Microsoft Sentinal can help to get Workload Identities under control.
Let our Red Team conduct a professional social engineering test!
Marius Elmiger
Marius Elmiger
Marius Elmiger
Marius Elmiger
Our experts will get in contact with you!