Within an Azure EntraID enterprise there is often a large number of Application Service Principles. These EntraID Applications are used for applications and services which need to authenticate themselves to your EntraID tenant or authenticate your users.
Microsoft exposes these Applications under the following APIs
- OAuth 2.0
- OpenID Connect
- Graph API
- WS-Federation
- SAML
One of the primary ways EntraID Applications are used is for automation scripts/tools to have a “secret” or “Certificate” to authenticate to the Application, then perform actions within the tenant using that Service Principal identity.
A common issue faced when the number of applications increases is how do you delegate management of the Certificate or Secret to the engineers which own the code/tool which uses it. Often times the delegation is needed purely because of scale, but there are also instances where the engineers need to rotate or update the credentials quickly. The individuals which govern and regulate the EntraID environment want to make it as easy as possible for tool owners to do the right thing and rotate secrets as often as needed.
However, by default Microsoft will only allow application “Owners” to perform the rotation. By over permissioning there is increase risk of intentional or unintentional changes to the application by the designated owners. An owner can change the permissions, core settings, or even assign additional owners who may not have authorization to be in that role.
The solution is to delegate changing specific settings to users through a custom EntraID role + PIM (Privilege Identity Management) to require users to Just-In-Time elevate when they need the permission. The elevation should provide the minimal number of permissions required and only to the specific resources the application owning team has authorization to update.
What will we be doing:
- Creating the custom EntraID role used for all Application Secret Rotations (across all applications)
- Creation of the Security Group that will hold members of the team authorized to change a given Application (or set of applications) secrets, certificates.
- Creation of a PIM JIT rule to allow users to elevate when they need the permission to add/change/remove a secret or certificate.
Prerequisites
- Install required Powershell modules
Install-Module Microsoft.Graph
install-module az
- Permissions within your Azure Tenant to grant permissions to GraphAPI Powershell
- Login to the powershell modules into your Azure Tenant
import-module Microsoft.Graph
Connect-MgGraph -NoWelcome -Scopes "Group.ReadWrite.All", "RoleManagement.ReadWrite.Directory", "User.ReadWrite.All", "Application.Read.All"
Create the custom role
Create a custom Azure Role with permissions specifically for updating secrets.

$params = @{
description = "Authorized to update application secrets"
displayName = "Application Secret Secrets Manager"
rolePermissions = @(
@{
allowedResourceActions = @(
"microsoft.directory/applications/basic/read",
"microsoft.directory/applications/basic/update",
"microsoft.directory/applications/credentials/update",
"microsoft.directory/applications/standard/read"
)
}
)
isEnabled = $true
}
$Role = New-MgRoleManagementDirectoryRoleDefinition -BodyParameter $params
Update the new role’s setting
We will set the role’s elevation rules to limit elevation to 2 hours and require both a ticket and justification to be provided when elevating.

$roleName = "Application Secret Secrets Manager"
$RoleDefinitions = Get-MgRoleManagementDirectoryRoleDefinition -Property Id,displayName
$DRassignments = Get-MgPolicyRoleManagementPolicyAssignment -Filter "scopeId eq '/' and scopeType eq 'DirectoryRole'"
$RoleDefinitionId = ($RoleDefinitions | Where-Object {$_.DisplayName -eq $roleName}).Id
$DirectoryRolePolciyId = ($DRassignments | Where-Object {$_.RoleDefinitionId -eq $RoleDefinitionId}).PolicyId
#get the current expiration rule settings
$ExpirationRule = get-MgPolicyRoleManagementPolicyRule -UnifiedRoleManagementPolicyId $DirectoryRolePolciyId -UnifiedRoleManagementPolicyRuleId "Expiration_EndUser_Assignment"
#Set the elevation period to 2 hours and force an expire time to be set
$ExpirationRule.AdditionalProperties.maximumDuration = "PT2H"
$ExpirationRule.AdditionalProperties.isExpirationRequired = $true
Update-MgPolicyRoleManagementPolicyRule -UnifiedRoleManagementPolicyId $DirectoryRolePolciyId -UnifiedRoleManagementPolicyRuleId $ExpirationRule.Id -AdditionalProperties $ExpirationRule.AdditionalProperties
$EnablementRule = get-MgPolicyRoleManagementPolicyRule -UnifiedRoleManagementPolicyId $DirectoryRolePolciyId -UnifiedRoleManagementPolicyRuleId "Enablement_EndUser_Assignment"
#Set the elevation to require a Ticket Number and Justification to be provided
$EnablementRule_EnabledRules = @(
"Justification"
"Ticketing")
$EnablementRule.AdditionalProperties.enabledRules = $EnablementRule_EnabledRules
Update-MgPolicyRoleManagementPolicyRule -UnifiedRoleManagementPolicyId $DirectoryRolePolciyId -UnifiedRoleManagementPolicyRuleId $EnablementRule.Id -AdditionalProperties $EnablementRule.AdditionalProperties
Create the Security Group
Create a security group that will be the users delegated to modify the permissions on the application. By using a group more than 1 application and more than 1 user can be the delegated secrets manager.
$param = @{
description="Users from team Foo who are allowed to manage the team application secrets."
displayName="Team Foo Application Secret Managers"
mailEnabled=$false
securityEnabled=$true
mailNickname="FooSecretsManagers"
IsAssignableToRole=$true
}
$Group = New-MgGroup -BodyParameter $param
Create an PIM Entitlement
Creating the new entitlement for members of the designated group to elevate into the role to manage application secrets.
The entitlement will scope the access for role to the specific Application’s Service Principal that we lookup as part of the script. This scope is key to ensuring the group can only modify the application and not all applications.
The entitlement is set to expire after 60 days.
Note: The duration attribute uses iso 8601 duration formats – ISO 8601 – Wikipedia

#Get the application that we are going to link the elevation to
$applicationName = "App1"
$application = Get-MgApplication -Search "DisplayName:$applicationName" -ConsistencyLevel eventual
#Define the scope of the role assignment
$resourceScope = '/' + $application.AppId
#create Role Assignment for the group
$params = @{
"PrincipalId" = $group.Id
"RoleDefinitionId" = $role.Id
"Justification" = "Add eligible assignment"
"DirectoryScopeId" = $resourcescope
"Action" = "AdminAssign"
"ScheduleInfo" = @{
"StartDateTime" = Get-Date
"Expiration" = @{
"Type" = "AfterDuration"
"Duration" = "P60D"
}
}
}
$roleEligible = New-MgRoleManagementDirectoryRoleEligibilityScheduleRequest -BodyParameter $params
This entitlement is set to permanent and won’t expire with the “noExpiration” flag
Information on expiration is defined at https://learn.microsoft.com/en-us/graph/api/resources/expirationpattern?view=graph-rest-1.0
#create Role Assignment for the group
$params = @{
"PrincipalId" = $group.Id
"RoleDefinitionId" = $role.Id
"Justification" = "Add eligible assignment"
"DirectoryScopeId" = $resourcescope
"Action" = "AdminAssign"
"ScheduleInfo" = @{
"StartDateTime" = Get-Date
"Expiration" = @{
"Type" = "noExpiration"
}
}
}
$roleEligible = New-MgRoleManagementDirectoryRoleEligibilityScheduleRequest -BodyParameter $params
Time to elevate
After creating the entitlement, the members of the group can now use PIM to elevate at https://portal.azure.com/#view/Microsoft_Azure_PIMCommon/ActivationMenuBlade/~/aadmigratedroles
