Automate Monitoring Service Principal Secrets In AzureAD

Expiring secrets in AzureAD is a pain we all share. Whilst Microsoft still don’t provide a nice method to monitor them, admins are left to create their own solutions. In most cases, this is manual or rotate when broke.

Here is a solution that can help: https://github.com/amoranio/Get-AZAppExpiringSecrets

I’ve created this script to be universal. Whilst some will be happy to run the script manually, others may want to add further automation. This could include a Logic App and Automation Account. With this, you could have this running on a schedule to continually monitor your environment. Your design could look similar to:


📜 The Script

This is a breakdown on how you can modify the script to meet your needs. As mentioned, this script can be used as a runbook within an automation account, so I’ll explain both methods.

🌤️The Group

Regardless of the option you chose, I’ve tailored this around a group. I’ve done this, as it give you the ability to monitor only those you care about. You can manage and expand the group to multiple, but for now the script manages one. To set this, add the Group ID on line 142.

$groupid = ""

You will need to grant your Service Principal Owner Access so it can read the members.

🤖 Automation Account

If you’re wanting to add automation, you can uncomment the script and use it in your runbook. You can either use without the schedule, and have the admin enter params.

For manual effort, uncomment the first couple of lines (Remove <##>)

param(
    [Parameter(Mandatory=$true)]
    [string]$tenantId,
    [Parameter(Mandatory=$true)]
    [string]$SPClientId,
    [Parameter(Mandatory=$true)]
    [string]$SPClientSecret,
    [Parameter(Mandatory=$true)]
    [string]$groupid
)

If you’re not wanting to have it manual, comment or amend the following lines:

###### Execution Steps #########

$tenantId = ""
$SPClientId = ""
$SPClientSecret = ""
$groupid = ""

In certain cases, you can hard-code these variables. To avoid storing secrets, you can use the variable option within your automation account. This can store the value encrypted. To call these values, you can uncomment the following:

#### Automation Account - Local Variables #######

If you are using an automation account, you can use this if you are storing the passwords. Remember to mask

$tenantId = Get-AutomationVariable -Name "TenantID"
$SPClientId = Get-AutomationVariable -Name "ClientID"
$SPClientSecret = Get-AutomationVariable -Name "XYZ"
$groupid = Get-AutomationVariable -Name "GroupID"

The -Name refers to what it’s Name is within the variables. In this instance, the example is pointing to my encrypted client secret called XYZ.

That’s it. You can then run as you please, and add further automation.

⚡ Local Script

There’s nothing wrong with running it locally, or via a scheduled task. For this, you can either update your details here:

###### Execution Steps #########

$tenantId = ""
$SPClientId = ""
$SPClientSecret = ""
$groupid = ""

or uncomment and run with variables:

param(
    [Parameter(Mandatory=$true)]
    [string]$tenantId,
    [Parameter(Mandatory=$true)]
    [string]$SPClientId,
    [Parameter(Mandatory=$true)]
    [string]$SPClientSecret,
    [Parameter(Mandatory=$true)]
    [string]$groupid
)


🔥What About The Secret?

By no means am I saying to hardcode secrets. Your client ID need to be secure, so you can either pull from a Key Vault, Local Vault, or store.

To give a brief example, you can install the SecretVault using:

Install-Module Microsoft.PowerShell.SecretManagement, Microsoft.PowerShell.SecretStore

Here you can interact with your secrets. Below is a typical example, but you can match similar in your Powershell script.

⚠️ Because the Secret Vault is Password protected, you will have to use Unlock-SecretStore


⚒️ The Authentication

Before you can secure the password, you first need one. This script uses a Service Principal to call the Microsoft Graph API. Because of this, you will need to create a Service Principal first.

You will also need to grant API permissions. There are a few options and depends on your risk appetite.

  • You can either grant it Application.Read.All with gives it more than it needs but makes future creations easier.
  • Application.ReadWrite.OwnedBy which means if it creates the Service Principals you’re monitoring, it owns them by default and can read the secrets. This gives limited access.
  • Owner per app. This is the least privileged access but requires a bit of work. For those you want to monitor, you will have to assign owner access to this Service Principal.


That’s It. You should be good to go.

Let me know how you get on and I always appreciate feedback! 😁

Advertisement

Create a website or blog at WordPress.com

%d bloggers like this: