Email Notification for Entra ID Application Secret Key Expiry

Introduction:

Azure doesn’t have a feature to send an alert to the Entra ID application users whenever the secret is about to expire out of the box.
This article explains how this system is built to send an alert to the user at least 7 days before whenever the secret expires.

Register the Entra ID application:

Before getting into a code, ensure you have added the required API scope permission in Azure AD B2C app registration for our client credential flow.

Since we are using a client credential flow, the below permissions are the least privilege to read all application details.

Application.Read.All and you also need a Directory.Read.All

Entra ID application permission

Create an Azure Function:

Azure Functions is a serverless computing service from Microsoft Azure that lets you run event-driven code without needing to provision or manage infrastructure. It enables developers to execute code in response to various triggers, including HTTP requests, timers, and messages from other Azure services.

Create a Timer Trigger Azure Function

Azure Function Timer Trigger
 [FunctionName("fn_cron_secret_expiry")]
 public async Task Run([TimerTrigger("0 0 10 * * *")] TimerInfo myTimer, ILogger log)
 {
     var result= await NotifyClientSecretExpiry(log);
      
 }
 public async Task<bool> NotifyClientSecretExpiry(ILogger logger)
 {
     var appList = new List<Models.Application>();
     try
     {
         var scopes = new[] { "https://graph.microsoft.com/.default" };
         var tenantId = Environment.GetEnvironmentVariable("TenantId");
         var clientId = Environment.GetEnvironmentVariable("ClientId");
         var clientSecret = await GetSecretFromKeyVault(logger, "keyName");
         var clientSecretCredential = new ClientSecretCredential(
                         tenantId, clientId, clientSecret);
         var _graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);
        

         DateTime currentDate = DateTime.Now;
         TimeSpan duration = new TimeSpan(7, 0, 0, 0); // 7 days
         DateTime resultDate = currentDate.Add(duration);
         var result = await _graphServiceClient.Applications.Request().GetAsync();
         foreach (var app in result)
         {
             var isToBeExpired = app.PasswordCredentials.Where(e => e.EndDateTime <= resultDate).Count() > 0 ? true : false;

             if (app.PasswordCredentials.Count() > 0)
             {
                 if (isToBeExpired)
                 {
                     appList.Add(new Models.Application
                     {
                         Id = app.Id,
                         ApplicationId = app.AppId,
                         ApplicationName = app.DisplayName,
                         SecretToBeExpired = isToBeExpired
                     });
                 }

             }
         }
     }
     catch (Exception ex)
     {
         logger.LogInformation($"Error Message {ex.Message}");
         //  Console.WriteLine(ex.Message);
     }
     var response= await SendEmailAsync(Environment.GetEnvironmentVariable("EmailTo"), "Entra ID applications client secrets to-be expired/expired", GenerateHtmlContent(appList), logger);
     return response;
 }

The above timer trigger will execute every day at 10 AM, NotifyClientSecretExpiry function checks for the Entra ID application with client secret that will expire after 7 days from the current day or if it’s already expired.


        private async Task<bool> SendEmailAsync(string emailTo, string subject, string emailBody, ILogger logger)
        {
            
            try
            {
                var apiKey = await GetSecretFromKeyVault(logger,"SendGridApiKey");
                var client = new SendGridClient(apiKey);               
                var from = new EmailAddress(Environment.GetEnvironmentVariable("EmailFrom"), "Gowtham CBE");
                var to = new EmailAddress(emailTo, "Gowtham K");
                var plainTextContent = "";              
                var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, emailBody);
                var response = await client.SendEmailAsync(msg);
                return response.IsSuccessStatusCode;
            }
            catch (Exception ex)
            {
                logger.LogInformation($"Error Message {ex.Message}");
               
            }
            return false;
        }

The above function SendEmailAsync uses send grid client will send an email with all the application details will be expired after 7 days from current day or if it’s already expired.

app settings

{
   "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "TenantId": "[Your Tenant ID]",
    "ClientId": "[Your Entra ID application client Id]",
    "EmailFrom": "[Email from address]",
    "EmailTo": "[Email to address]",
    "KeyVaultUri": "[Your KeyVault Uri]"
  }
}

        private static async Task<string> GetSecretFromKeyVault(ILogger logger, string keyName)
        {

            // Get the Microsoft Entra ID access token using Managed Identity
            var credential = new ManagedIdentityCredential();
            var client = new SecretClient(new Uri(Environment.GetEnvironmentVariable("KeyVaultUri")), credential);

            try
            {
                KeyVaultSecret secret = await client.GetSecretAsync(keyName);
                return secret.Value;
            }
            catch (AuthenticationFailedException e)
            {
                logger.LogInformation($"Error Message {e.Message}");
                return string.Empty;
            }

        }

The above function GetSecretFromKeyVault will be used to get the secret from the Azure key vault using ManagedIdentityCrendential .

Summary:

This article provides a step-by-step guide on creating a custom email notification system for when a Microsoft Entra ID application client secret is about to expire. The solution integrates Azure Key Vault for secure storage of the secret, Microsoft Graph API to retrieve detailed information about the Entra ID application, and SendGrid for sending email alerts. The process ensures that administrators are promptly informed, minimizing the risk of downtime or security issues due to expired secrets.

Get complete source code from my GitHub repo.

Happy Coding! 😊

gowthamk91

Leave a Reply

Discover more from Gowtham K

Subscribe now to keep reading and get access to the full archive.

Continue reading