Have you ever tried to automate the creation of an Azure application registration or service principal object? In this blog post we are going to explore how to automate the creation of Azure AD objects using a Clone Service Principal. The service principal will be able to create other Azure AD service principals.
Introduction
What is a service principal object? A service principal object is used
to access resources that are secured by an Azure AD tenant, the entity that requires access must be represented by a security principal. This is true for both users (user principal) and applications (service principal). Source
For more information see application and service principal objects in Azure Active Directory.
Why is a Clone Service Principal needed? This type of serivce principal is needed if you want to automate the creation of Azure AD objects and decouples a dedicated user principal from the process of creating Azure AD objects.
As speciall permissions are needed for a service principal to talk to the Azure AD APIs the blog posts tries to shed some light on how to create a least privileg service principal to create other service principals.
A use case for a Clone Service Principal is the automated creation of application registrations and service principals in a CI/CD pipeline. In deployment scripts for cloud native applcation and web applications. As well as the automated creation of landings zones for internal customers.
Create a Clone Service Principal
In order to get started we can create an Azure service principal with the Azure CLI. It can either be a tenant level account (non RBAC, no Azure subscription assigned) or a create-for-rbac
service principal. The steps to create an application registration and create a service principal object can be found below:
Note: when creating the service principal, a password will be generated! Consider that the password will be in the output! Make sure when running the creation in automation to deal with the secret accordingly, see considerations.
# Select a name
appName=CloneServicePrincipal
# Create an app and return only appId
appId=(az ad app create --display-name $appName --query appId -o tsv)
# Create a service principal using the returned app id
az ad sp create --id $appId
If you get the error message "Insufficient privileges to complete the operation."
. Doublecheck the Azure AD settings (aad.portal.azure.com) whether User Settings
> App registrations
> Users can register Applications
is set to Yes
.
If this setting is set to No
you need to make sure your current user has at least the Application developer
Azure AD role, for more information about Azure AD roles visit roles and administrators.
Application developer: Users in this role will continue to be able to register app registrations even if the Global Admin has turned off the tenant level switch for “Users can register apps”.
Using the Application developer
role for the next steps will require an additional admin to consent to the following mandatory changes to the service principal permissions. Make sure user with Application administrator
role is available in order to create the Clone Service Principal in Application Permissions.
If “User can register apps” is set to No
. Make sure to also assign the role Application developer
to the newly created service principal. Furthermore, the service principal needs to be granted explicit permissions on the API Microsoft Graph
and Azure Active Directory Graph
(see API Permissions).
Locate the service principal
Visit aad.portal.azure.com and go to Azure Active Directory
>
App Registrations
.
Locate the created service principal by searching All applications
and navigate to API Permissions
Select Add permissions
. You can search for APIs in the tab APIs my organization uses
. Click on Microsoft Graph
to list the API permissions.
API Permissions
The permissions to create Azure AD objects are associated to two APIs. For each API the correct permissions need to be granted (see Application Permissions). You can search for APIs in the Request API permissions
> APIs my organization uses
. You can use this form to reverse search the name for given API ID too (see json output in wrap it up).
To create Azure AD objects the needed APIs are:
API Name | API ID |
---|---|
Microsoft Graph | 00000003-0000-0000-c000-000000000000 |
Windows Azure Active Directory | 00000002-0000-0000-c000-000000000000 |
Application Permissions
We want to request Application permissions
, as our service principal should run as a background service or deamon without a signed-in user. (Note: delegated permission, in delegated scenarios, the effective permissions granted to your app may be constrained by the privileges of the signed-in user in the organization.). For details see delegated permissions, Application permissions, and effective permissions.
Select Application permission
, locate Application
in the drop down list and select Application.ReadWrite.OwnedBy
, hit Add permission
on the bottom and repeat the step for the Azure Active Directory API (!).
You can find the Windows Azure Active Directory API in the bottom of the list Supported legacy APIs
in the portal.
The permissions we are interested in granting are listed below. Review the following table for a detailed description of the differences between All
and OwnedBy
. Both permissions can be used for a Clone Service Principal.
Permission | Description | Admin Consent Required |
---|---|---|
Application.ReadWrite.All | Allows the calling app to create, and manage (read, update, update application secrets and delete) applications and service principals without a signed-in user. Does not allow management of consent grants or application assignments to users or groups. | Yes |
Application.ReadWrite.OwnedBy | Allows the calling app to create other applications and service principals, and fully manage those applications and service principals (read, update, update application secrets and delete), without a signed-in user. It cannot update any applications that it is not an owner of. Does not allow management of consent grants or application assignments to users or groups. | Yes |
You can retrieve all permissions ids for the Microsoft Graph
API by running a PowerShell command from the Azure AD module, thanks Marco Scheel see:
# Make sure to install the module
Install-Module AzureAD
# Retrieve Microsoft Graph API permissions list
Get-AzureADServicePrincipal -filter "DisplayName eq 'Microsoft Graph'").AppRoles |
Select Id, Value |
Sort-Object Value
It returns a list of permissions Ids and Values. The whole list can be found as a download markwarneke.me/application_permissions.json. In particular we are interested in the Application resource permissions. The Id and Value look like this:
[
{
"Id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9",
"Value": "Application.ReadWrite.All"
},
{
"Id": "18a4783c-866b-4cc7-a460-3d5e5662c884",
"Value": "Application.ReadWrite.OwnedBy"
}
]
Up to this point the service principal is only request to be granted permissions to these APIs.
Some API permissions
need admin consent, which means a high privileged Azure AD account needs to “approve” the requested permissions.
As we want to make changes in the Azure AD an admin has to acknowledge and consent to this. The OwnedBy
permission is more restrictive and limits the changes to owned applications only.
You can find a list of permissions and whether admin consent is needed in the Microsoft Graph permissions reference.
A high privileged role is for instance the Application Administrator
Azure AD role, see administrator role permissions in Azure Active Directory. Make sure to have a user principal with at least this role to grant admin consent on the requested permission (Global Administrator would work too).
[The Application Adminsitrator] … also grants the ability to consent to delegated permissions and application permissions, with the exception of permissions on the Microsoft Graph API. Source
If your user principal happens to be at least the Azure AD Application Administrator
role you can hit Grant admin consent for <tenant>
. Otherwise request the consent from from your administrator. Feel free to forward this blog post to your administrator to explain your intent; that is why I created this blog post in the first place.
Using a Clone Service Principal to create other Service Principals
After the role Application developer
is assigned to the Clone Service Principal, and the application permissions for the API Microsoft Graph
and Azure Active Directory Graph
are granted we can try to use the Clone Service Principal to create other Azure AD objects.
To validate that the Clone Service Principal is working, log-in using the previously created service principal and try to create a new Azure AD application. The az login --service-principal
is used to sign in using a service principal.
# Login as the Clone Service Principal
az login --service-principal -u $appId -p $passowrd --tenant $tenant
# Make sure you are actually using the service principal
az account show
# Create a new application
appName2=AppCreatedByCloneServicePrincipal
az ad app create --display-name $appName2
You should get the details of the application returned.
If an error is returned for Insufficient privileges to complete the operation
make sure that the role and permissions are set correctly. Checkthat the changes have been propagated in Azure AD. In large Azure AD tenants, the propagation might take some time.
Wrap it up
To create a Clone Service Principal you can run the following automation steps. Make sure the authenticated user executing the steps has at least the Application Administrator
Azure AD role - as this role is needed for the last step to grant permissions.
Validate that the Clone Service Principal API permission has been assigned correctly, run:
az ad app permission list --id $appId
The output should look like this:
[
{
"additionalProperties": null,
"expiryTime": "",
"resourceAccess": [
{
"additionalProperties": null,
"id": "824c81eb-e3f8-4ee6-8f6d-de7f50d565b7",
"type": "Role"
}
],
"resourceAppId": "00000002-0000-0000-c000-000000000000"
},
{
"additionalProperties": null,
"expiryTime": "",
"resourceAccess": [
{
"additionalProperties": null,
"id": "18a4783c-866b-4cc7-a460-3d5e5662c884",
"type": "Role"
}
],
"resourceAppId": "00000003-0000-0000-c000-000000000000"
}
]
- The
resourceAppId
is the associated API, e.g.Microsfot Graph
. - the
id
is the Application permission, e.g.Application.ReadWrite.OwnedBy
.
Test
Login using the new service principal. Notice the --allow-no-subscriptions
is used because we set up a tenant level account, the account has no Azure subscription assigned and only operats on the tenant level Azure AD & Microsoft Graph APIs.
# Login using the Clone Service Principal
az login --service-principal -u $appId -p $pw --tenant $tenantId --allow-no-subscriptions
# Create a new app
az ad app create --display-name "testmark2"
Limitation
There is a maximum number of service principals a principal can created, for more information see Azure AD service limits and restrictions.
The Application Developer role grants the ability, but the total number of created objects is limited to 250 to prevent hitting the directory-wide object quota. Source
Code: Directory_QuotaExceeded
Message: The directory object quota limit for the Principal has been exceeded. Please ask your administrator to increase the quaote limit or delete objects to reduce the used quota.
To work around this limitation multiple Clone Service Principals can be used.
The Clone Service Principal can also be assigned the Application Administrator
role.
this role has a higher quota.
A work around is to transfer the ownership of the newly created application registrations to a delegate service principals, too.
Clean up of created service principals: Consider that a soft delete for Azure AD application registrations is in place. It can take up to 30 days to remove an Azure AD object completly from the directory. The soft deleted application will count towards you quota limit.
To see the amount of Azure AD objects use:
$objectId=0000000 # ObjectId of the clone service principal or user principal
Connect-AzureAD
# Get the azure ad created objects ALL including soft deleted
Get-AzureADUserCreatedObject -ObjectId $objectId -All $true | measure
Considerations
Make sure these steps are taken deliberately by creating a threat model.
Allowing a service account to modify Azure AD objects has potential risks, some to consider:
- accidental deletion of Azure AD objects like application registrations.
- deliberate deletion of Azure AD objects by a rogue admin.
- creation of malicious applications associated with the Azure AD tenant.
Note: Make sure to review the Threat Model Clone Service Principal.
Make sure the secrets for the Clone Service Principal are handled correctly. A general guidance is to store credentials in Azure Key Vault. Ensure that these secrets are rotated frequently.
Monitor the sign-in activity reports in the Azure Active Directory portal of the Clone Service Principal or consider creating alerts similar to Role security > emergency accounts for unexpected sign-ins.
Create Azure AD Identity Governance for the Clone Service Principal. Make sure the created applications are active and used, recycle unused appliction periodically.
Consider the Clone Service Principal as a high privileged account and secure the secrets and access to it accordingly, see improving security by protecting elevated-privilege accounts at Microsoft and securing privileged access for hybrid and cloud deployments in Azure AD.