Runbook to check Entra Apps with expiring ClientSecrets and Certificates
Hi All,
In the previous Article i explained how to check for Entra Apps with expiring ClientSecrets and Certificates.
In this Blog Article i explain how we can extend this into a Azure Automation Runbook.
Automation Account
The Azure Automation Account needs to have a Managed Identity
Use the AZ PowerShell to get Infos about the Azure Automation Account
###############################################################################
# Get Managed Identity of Azure Automation Account
###############################################################################
Connect-AzAccount -Tenant icewolfch.onmicrosoft.com
Get-AzAutomationAccount -Name icewolfautomation -ResourceGroupName RG_DEV
#Get ManagedIdentity
$AutomationAccount = Get-AzAutomationAccount -Name icewolfautomation -ResourceGroupName RG_DEV
$AutomationAccount.Identity
Service Principal
We can now use the ObjectID of the ManagedIdentity to get all the Details with Microsoft.Graph
###############################################################################
# Get AzureAD Application with Microsoft.Graph PowerShell
###############################################################################
Connect-MgGraph -Scopes Application.Read.All -NoWelcome
$ServicePrincipalDetails = Get-MgServicePrincipal -ServicePrincipalId "547c53c8-9e84-4dc7-8a65-92c59fb1c34f"
$AppID = $ServicePrincipalDetails.AppId
$ObjectId = $ServicePrincipalDetails.Id
$AppDisplayName = $ServicePrincipalDetails.Displayname
$ServicePrincipalDetails | Format-List Id, AppId, DisplayName, ServicePrincipalType
Exchange Online RBAC for Application
I’ve blogged about this earlyer
Here is the short and updated Version
###############################################################################
# Create Exchange Service Principal
###############################################################################
Connect-ExchangeOnline -ShowBanner:$false
New-ServicePrincipal -AppId $AppID -ObjectId $ObjectId -DisplayName "EXO Serviceprincipal $AppDisplayName"
Get-ServicePrincipal | where-object {$_.AppId -eq $AppID}
###############################################################################
#New-ManagementScope
###############################################################################
# New-ManagementScope
# https://learn.microsoft.com/en-us/powershell/module/exchange/new-managementscope?view=exchange-ps
# Filterable properties for the RecipientFilter parameter on Exchange cmdlets
# https://learn.microsoft.com/en-us/powershell/exchange/recipientfilter-properties?view=exchange-ps
Get-ManagementScope
New-ManagementScope -Name "a.bohren" -RecipientRestrictionFilter "PrimarySmtpAddress -eq 'a.bohren@icewolf.ch'"
###############################################################################
#New-ManagementRoleAssignment
###############################################################################
New-ManagementRoleAssignment -App $ObjectId -Role "Application Mail.Send" -CustomResourceScope "a.bohren"
Get-ManagementRoleAssignment | where-object {$_.App -eq $ObjectId}
Show the Management Role details
###############################################################################
#Get-ManagementRoleAssignment
###############################################################################
Get-ManagementRoleAssignment | where-object {$_.App -eq $ObjectId}
Get-ManagementRoleAssignment | where-object {$_.App -eq $ObjectId} | fl
Azure Runbook
Here is the Runbook that can be used in Azure Automation
###############################################################################
# Azure Automation Runbook
# CheckEntraAppAuthenticationExpiration
###############################################################################
# Azure Automation Account
# - Managed Identinty
# Required Modules:
# - Microsoft.Graph.Authentication
# - Microsoft.Graph.Applications
# Required Permissions
# - Application.Read.All
# - Mail.Send (Mail.Send.Shared does not exist in Exchange Online RBAC for Applications)
###############################################################################
# Important
###############################################################################
# Limiting application permissions to specific Exchange Online mailboxes
# https://docs.microsoft.com/en-us/graph/auth-limit-mailbox-access
#
# Limit Microsoft Graph Access to specific Exchange Mailboxes
# https://blog.icewolf.ch/archive/2021/02/06/limit-microsoft-graph-access-to-specific-exchange-mailboxes.aspx
#
# or Limit Graph Access with Exchange Online Role Based Access Control (RBAC) for Applications
# https://blog.icewolf.ch/archive/2023/01/05/exchange-online-role-based-access-control-rbac-for-applications/
###############################################################################
###############################################################################
#Send Mail Function Graph
###############################################################################
Function Send-GraphEmailNotification{
Param(
[parameter(Mandatory=$true)][String]$From,
[parameter(Mandatory=$true)][String]$To,
[parameter(Mandatory=$true)][String]$Subject,
[parameter(Mandatory=$true)][String]$MessageBody
)
$URI = "https://graph.microsoft.com/v1.0/users/$From/sendMail"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Body = @"
{
"message": {
"subject": "$Subject",
"body": {
"contentType": "Text",
"content": "$MessageBody"
},
"toRecipients": [
{
"emailAddress": {
"address": "$To"
}
}
]
}
}
"@
Invoke-GraphRequest -Method "POST" -Uri $uri -Body $Body -ContentType $ContentType
}
###############################################################################
#Main Script
###############################################################################
Write-Output "Connect-MgGraph"
Connect-MgGraph -Identity
#Expiration Comparsion Date
$ExpirationDate = (Get-Date).Adddays(+60)
#FromAddress
$FromAddress = "a.bohren@icewolf.ch"
$NotificationSubject = "Entra App Authentication Expiration"
#Get Entra Apps
Write-Output "Getting Entra Apps"
$EntraApps = Get-MgApplication
#Loop through the Apps
Foreach ($EntraApp in $EntraApps)
{
$AppDisplayName = $EntraApp.DisplayName
$AppId = $EntraApp.AppId
$ID = $EntraApp.ID
Write-Output "$AppID > $ID > $AppDisplayName"
#Get Owner
$OwnerMailArray = @()
$OwnerObject = Get-MgApplicationOwner -ApplicationId $ID
$Owners = $OwnerObject.AdditionalProperties
If ($Null -eq $Owners)
{
Write-Output "No Owner found"
} else {
Foreach ($Owner in $Owners)
{
$UPN = $Owner.userPrincipalName
$Mail = $Owner.mail
$OwnerMailArray += $Mail
Write-Output "OwnerUPN: $UPN > OwnerMail: $Mail"
}
}
#Certificate
If ($Null -ne $EntraApp.KeyCredentials)
{
$Certificates = $EntraApp.KeyCredentials
Foreach ($Certificate in $Certificates)
{
$CertDisplayName = $Certificate.DisplayName
$CertStartDate = $Certificate.StartDateTime
$CertEndDate = $Certificate.EndDateTime
Write-Output "Certificate: $CertDisplayName > StartDate: $CertStartDate > EndDate: $CertEndDate"
If ($ExpirationDate -gt $CertEndDate)
{
Write-Output "$CertDisplayName Certificate will soon expire"
If ($OwnerMailArray.Count -gt 0)
{
#Send Mail to each Owner
Foreach ($OwnerMail in $OwnerMailArray)
{
Write-Output "Send Mail to $OwnerMail > The App $AppDisplayName has an expiring Certificate $CertDisplayName expiring at $CertEndDate"
Send-GraphEmailNotification -From $FromAddress -To $OwnerMail -Subject $NotificationSubject -MessageBody "The App <$AppDisplayName> has an expiring Certificate <$CertDisplayName> expiring at $CertEndDate"
}
}
}
}
}
#ClientSecret
If ($Null -ne $EntraApp.PasswordCredentials)
{
$ClientSecrets = $EntraApp.PasswordCredentials
Foreach ($ClientSecret in $ClientSecrets)
{
$DisplayName = $ClientSecret.DisplayName
$StartDate = $ClientSecret.StartDateTime
$EndDate = $ClientSecret.EndDateTime
Write-Output "ClientSecret: $DisplayName > StartDate: $StartDate > EndDate: $EndDate"
If ($ExpirationDate -gt $EndDate)
{
Write-Output "ClientSecret $DisplayName will soon expire"
If ($OwnerMailArray.Count -gt 0)
{
#Send Mail to each Owner
Foreach ($OwnerMail in $OwnerMailArray)
{
Write-Output "Send Mail to $OwnerMail > The App $AppDisplayName has an expiring Certificate $CertDisplayName expiring at $CertEndDate"
Send-GraphEmailNotification -From $FromAddress -To $OwnerMail -Subject $NotificationSubject -MessageBody "The App <$AppDisplayName> has an expiring ClientSecret <$DisplayName> expiring at $EndDate"
}
}
}
}
}
}
Notification Email
This is how the Notification Email looks like
Regards
Andres Bohren