Monitor The Azure Active Directory Client Secret Expiration

Whenever an application is live it’s important to keep it up and running without downtime. But what if your application stops suddenly just because you forget to update the expired ClientSecrets? It is going to affect your customers and business and you will get lot of escalation emails. Being an application owner, you don't want your application to have Application Downtime.

To avoid all these let’s implement a PowerShell script with help of Azure Function to monitor the expiration of your Azure AD app client secrets and send an email to the respective users in advance before it expires.

I hope you are you are already aware of below technologies which is needed for this implementation, if not please have a look at each official documentation.

Create Azure Timer Trigger

  • Login to Azure Portal
  • Search for Azure Function App and create the resource with required details.
  • Ensure to choose the Function runtime as PowerShell Core
    Create Azure Timer Trigger
  • Once the resource got created, go to the Functions menu in the left pane and click “Create Trigger” then choose “Timer Trigger
    Create Azure Timer Trigger

How to change the schedule in Timer Trigger

  • Timer triggers are based on schedules, if you want to change the time when the trigger should happen.
  • Click on your function name and in the upcoming screen go to “Code + Test” menu.
  • Select function.json from the files dropdown and look for the “schedule” object in the json to change the schedule timing.
  • Learn more about the which expressions to use for the timing, please have a look at NCRONTAB expressions

           How to change the schedule in Timer Trigger

How to enable AZ PowerShell module in Azure Functions

Azure functions by default support AZ module to perform operations in Azure Resources. Below are the steps to enable it.

Have a look at Azure PowerShell module commands to learn more about it.

  • Go to your Function App and in the left pane click App Files.
  • Select “requirements.psd1” from the files dropdown and uncomment the Az module as the below screen shot. If you wanted specific Az module version also you can modify it.

           How to enable AZ PowerShell module in Azure Functions

Enabling Managed Identity in Azure Functions

We would need to enable Managed identity to grant permission to our Azure Function app to access the Active Directory. Please take a look at use managed identities for App Service and Azure Functions to enable it.

How to assign Application administrator permission to Azure Managed identity

  • Go to Azure Active Directory and in the landing, page select “Roles and administrators”
    How to assign Application administrator permission to Azure Managed identity
  • In the upcoming screen, select “Application administrator” and then click “Add Assignments”.
    How to assign Application administrator permission to Azure Managed identity
  • Then search your managed identity and grant the permission. After granting permission you can find your Azure function app identity under assignments as below,
    How to assign Application administrator permission to Azure Managed identity

Now all the perquisites and the setup done for our implementation let’s see the actual script to do that,

PowerShell Code in Azure Function to monitor Azure AD Client Secrets

  • Add the expiration days to monitor and Webhook post link in Function App configuration as below, so it can be accessed in the function code.
    PowerShell Code in Azure Function to monitor Azure AD Client Secrets
  • Now our script will read all the AD apps for which client secrets will expire before the configured timeframe and fetch the meta details like Description, ExpiryDate, AppID, AppObjectID, AppName and Key Identifier.
  • Even if there are more than one client secrets are expiring in the same Azure AD app. It will also be returned as a separate object in the resulting array.
  • The last few lines of the code will post the Array object to WebHook.
  • Here is the full code go to your Timer Trigger Function and click “Code + Test” and replace the code editor with below code
    # Input bindings are passed in via param block.
    param($Timer)
    
    
    #secret expiration date filter (for example 30 days)
    $LimitExpirationDays = $env:LimitExpirationDays
    
    $SecretsToExpire =@()
    
    #Retrieving the list of secrets that expires in the above range of days
    Get-AzADApplication | ForEach-Object {
        $app = $_
        @(
            Get-AzADAppCredential -ObjectId $_.Id
        ) | Where-Object {
            $_.EndDateTime -lt (Get-Date).AddDays($LimitExpirationDays)
        } | ForEach-Object {
             $expiringSecret = @{
                AppName = $app.DisplayName
                AppObjectID = $app.Id
                AppApplicationId = $app.AppId
                SecretDisplayName = $_.DisplayName
                SecretKeyIdentifier = $_.KeyId
                SecretEndDate = $_.EndDateTime
            }
            $SecretsToExpire += $expiringSecret
        }
    }
    
    #Printing the list of secrets that are near to expire
    if($SecretsToExpire.Count -EQ 0) {
        Write-Output "No secrets found that will expire in this range"
    }
    else {
        Write-Output "Secrets that will expire in this range:"
        Write-Output $SecretsToExpire.Length
        Write-Output $SecretsToExpire | ConvertTo-Json
    
        $headers = @{
        'Content-Type' = 'application/json'
        }
    
        if($SecretsToExpire.Length -EQ 1){
        Invoke-RestMethod -Method 'Post' -Headers $headers -Uri $env:LogicApp_API_Url -Body (ConvertTo-Json @($SecretsToExpire))
        }
        else{
        Invoke-RestMethod -Method 'Post' -Headers $headers -Uri $env:LogicApp_API_Url -Body ($SecretsToExpire | ConvertTo-Json)
        }
    }

Now the next step is to send notification to the user, it can be any kind of webhook/API URL which receive your POST call from PowerShell and process the Request data to send emails. You can make this process easier when you go with Azure Logic Apps as it has default connectors for Mailing.

Now our eyes are on the expiring Client Secrets before it expires which monitors it on daily basis.

Note: If you don’t want to receive the emails or run the trigger, go to your Timer Trigger -> Overview page and Disable the Function temporarily.