How to Receive Email Notifications for Expiring Azure App Registration Certificates and Secrets

Krizzia 🤖
6 min readJul 4, 2023

In this guide, I will share a technique I have used to receive notifications for expiring Azure certificates and secrets.

Getting Started

  1. Create an Automation Account

Make sure to enable the “System Assigned Managed Identity” when creating an automation account. I strongly advise using this option instead of the soon-to-be-retired “Run as account.”

2. Assigned Roles to the System Managed Identity

To grant permission access, follow these steps:

Go to Active DirectoryRoles and administrators → Select Application Administrator → Add assignments → Select your Automation Account System Identity or Object (principal) ID → Click “Add” and then “Save”.

If you don’t do this, when you run your runbook, you will encounter permission errors.

3. Create a Runbook

Copy and paste the code below into the runbook and published.

<#
=========================================================================================================================
Required - Powershell Version 5.1
=========================================================================================================================
AUTHOR: KJR
DATE: 01/07/2021
Version: 1.0
=========================================================================================================================
.SYNOPSIS

.DESCRIPTION

#>

try {
Connect-AzAccount -Identity | Out-Null
} catch {
Write-Error -Message $_.Exception
throw $_.Exception
}

$objects = @()
$appRegistrations = Get-AzADApplication | Select-Object -Property AppId, DisplayName, PasswordCredentials, keyCredentials

foreach ($app in $appRegistrations) {
$secrets = @()
foreach ($secret in $app.PasswordCredentials) {
$secrets += @{ "Name" = $secret.DisplayName; "StartDateTime" = $secret.StartDateTime.ToString("MM/dd/yyyy"); "EndDateTime" = $secret.EndDateTime.ToString("MM/dd/yyyy"); "RemainingDays" = ($secret.EndDateTime - (Get-Date)).Days }
}
$certificates = @()
foreach ($certficate in $app.KeyCredentials) {
$certificates += @{ "Name" = $certficate.DisplayName; "StartDateTime" = $certficate.StartDateTime.ToString("MM/dd/yyyy"); "EndDateTime" = $certficate.EndDateTime.ToString("MM/dd/yyyy"); "RemainingDays" = ($certficate.EndDateTime - (Get-Date)).Days }
}
$objects += @{ "AppId" = $app.AppId; "DisplayName" = $app.DisplayName; Secrets = $secrets; Certificates = $certificates}

}
$tbody = @()
foreach ($obj in $objects) {
$approw = $null
$secretsrow = $null
$certsrow = $null

$approw += '
<tr>
<td style="border: 1px solid black; width: 12.4818%;"><strong>Application ID</strong></td>
<td style="border: 1px solid black; width: 75%;" colspan="3">' + $obj.AppId + '</td>
</tr>
<tr>
<td style="border: 1px solid black; width: 12.4818%;"><strong>Name</strong></td>
<td style="border: 1px solid black; width: 75%;" colspan="3">' + $obj.DisplayName + '</td>
</tr>'


if ($obj.Secrets.Count -le 0) {
$secretsrow += '
<tr style="text-align: center;">
<td style="border: 1px solid black; width: 100%;" colspan="4">No records found.</td>
</tr>'
} else {
foreach ($secret in $obj.Secrets) {
$secretsrow += '
<tr style="text-align: center;">
<td style="border: 1px solid black; width: 12.4818%;">' + $secret.Name + '</td>
<td style="border: 1px solid black; width: 12.4818%;">' + $secret.StartDateTime + '</td>
<td style="border: 1px solid black; width: 12.4818%;">' + $secret.EndDateTime + '</td>
<td style="border: 1px solid black; width: 12.4818%;">' + $(if([int]$secret.RemainingDays -le 0) { '<span style="color: rgb(184, 49, 47);">' + $secret.RemainingDays + '</span>' } else { $secret.RemainingDays }) + '</td>
</tr>'
}
}

if ($obj.Certificates.Count -le 0) {
$certsrow += '
<tr style="text-align: center;">
<td style="border: 1px solid black; width: 100%;" colspan="4">No records found.</td>
</tr>'
} else {
foreach ($cert in $obj.Certificates) {
$certsrow += '
<tr style="text-align: center;">
<td style="border: 1px solid black; width: 12.4818%;">' + $cert.Name + '</td>
<td style="border: 1px solid black; width: 12.4818%;">' + $cert.StartDateTime + '</td>
<td style="border: 1px solid black; width: 12.4818%;">' + $cert.EndDateTime + '</td>
<td style="border: 1px solid black; width: 12.4818%;">' + $(if([int]$cert.RemainingDays -le 0) { '<span style="color: rgb(184, 49, 47);">' + $cert.RemainingDays + '</span>' } else { $cert.RemainingDays }) + '</td>
</tr>'
}
}

$tbody += '<table style="width: 90%;border-collapse: collapse"><tbody> ' + $approw + '
<tr style="text-align: center; border: 1px solid black; width: 62.5547%; background-color: rgb(0, 0, 0);">
<td colspan="4">
<div style="text-align: center;"><strong><span style="color: rgb(255, 255, 255);">Secrets List</span></strong></div>
</td>
</tr>
<tr style="text-align: center;">
<td style="border: 1px solid black; width: 12.4818%;">
<div><strong>Name</strong></div>
</td>
<td style="border: 1px solid black; width: 12.4818%;">
<div>&nbsp;<strong>Start Date Time</strong></div>
</td>
<td style="border: 1px solid black; width: 12.4818%;">
<div><strong>End Date Time</strong></div>
</td>
<td style="border: 1px solid black; width: 12.4818%;">
<div><strong>Remaining Day(s)</strong></div>
</td>
</tr> ' + $secretsrow + '
<tr style="text-align: center; border: 1px solid black; width: 62.5547%; background-color: rgb(0, 0, 0);">
<td colspan="4">
<div style="text-align: center;"><strong><span style="color: rgb(255, 255, 255);">Certificates List</span></strong></div>
</td>
</tr>
<tr style="text-align: center;">
<td style="border: 1px solid black; width: 12.4818%;">
<div><strong>Name</strong></div>
</td>
<td style="border: 1px solid black; width: 12.4818%;">
<div>&nbsp;<strong>Start Date Time</strong></div>
</td>
<td style="border: 1px solid black; width: 12.4818%;">
<div><strong>End Date Time</strong></div>
</td>
<td style="border: 1px solid black; width: 12.4818%;">
<div><strong>Remaining Day(s)</strong></div>
</td>
</tr> ' + $certsrow + '
</tbody></table><br>'
}
$tbody

4. Create a Logic App

After creating the Logic App, ensure that you enable the System Managed Identity for this resource and assign the Contributor role to the resource group where your Automation Account was created in Step 1.

5. Configure the Logic App flow.

Step 1: Once you have set up the system identity for the Logic App, navigate to the Overview section, click on “Edit,” and select “Recurrence” as the event trigger.

Ideally, the recommended practice is to set the expiration period for certificates and secrets to at least 90 days or less. By setting shorter expiration periods, you can enhance the security of your applications and systems. In this guide, I have scheduled checks for the status of certificates and secrets twice a month.

Step 2: After configuring the trigger event of our Logic App, let’s proceed to configure the actions. Select “Azure Automation” as the action and select the “Create Job”

Select the (+) icon → Add an action → Azure Automation → Create Job.

Once you have authenticated the Azure Automation using the System Managed Identity, select the details of the automation account you created in Step 1 and Step 2.

Step 3: To obtain the results of the “Create Job” action, let’s add another action called “Get Job Output”.

Select the (+) icon → Add an action → Azure Automation → Get Job Output.

Step 4: Configure Outlook Notification

Lets add another action. Select the (+) icon → Add an action → Outlook → Send email (v2).

6. Validation

Once you have configured your Outlook, you can manually trigger the logic app to verify if everything is functioning correctly. After running it, you should receive an email similar to this.

Now you can see the remaining days before the expiration of secrets and certificates.

As per the request of a fellow tech colleague, I’ve created an article on how to automate the renewal of secrets. If you’re interested, check out my next article.

Thank you for taking the time to read my article. If you found it enjoyable, please consider showing your appreciation by clapping and following. Your support will motivate me to create more guides in the future that are based on real scenarios in the IT world.☺️☺️☺️

Is my blog putting a smile on your face? If so, why not treat me to a coffee to keep the good times brewing? Your java generosity not only perks up my day but also fuels my blogging mojo. And if this brings a laugh to your day, apologies in advance for the ‘tita’ jokes!

--

--