Using Azure Key Vault with Microsoft 365 PowerShell

Storing Script Secrets Safely in Azure Key Vault

In my article about posting messages to Teams channels using Azure Automation runbooks, I discuss how to use the incoming webhook connector and the Submit-PnpTeamsChannelMessage cmdlet from the PnP PowerShell module. The incoming webhook connector posts a snippet about a report while the PnP cmdlet can post a much bigger body, in this case, a HTML-formatted report created by an Azure Automation runbook.

In a related article, I explained that I had used account credentials stored in the Azure Automation account to authenticate and be able to store the report in a SharePoint Online document library. The runbook used the same credentials to post the message to the Teams channel. I explained that I used this approach because I couldn’t find an easy-to-use method (in PowerShell) to impersonate the identity of a team member to allow me to post information to the site and channel belonging to the team.

Setting up an Azure Key Vault

Several people suggested that I should store the account credentials somewhere else, which brought me to Azure Key Vault, defined as “a cloud service for securely storing and accessing secrets.” Secrets can be anything you want to store securely, like account names, passwords, or website URLs. The point is that once a secret is in a vault, it can only be accessed by an account or app allowed access to that vault.

Before you can create your own vault, you need an Azure subscription. Key Vault. The cost is minimal to store and retrieve a small number of secrets, so that shouldn’t be an issue, especially for organizations with existing Azure subscriptions.

To start, go to the Key Vaults section of the Azure portal and select the option to create a new vault. As you can see in Figure 1, this is where you need to specify the Azure subscription to use along with the resource group (I used an existing resource group, but you can choose to create a new one), and the hosting Azure region (usually the one closest to your location). It takes Azure a few minutes to create the new vault and then it’s ready to store secrets.

Creating a new Key Vault
Figure 1: Creating a new Key Vault

Storing and Managing Secrets

The runbook uses several variables.

  • Account credentials to log into SharePoint Online with PnP.
  • The site URL used to connect to PnP.
  • The group identifier of the team hosting the channel where the script posts messages.
  • The channel identifier of the target channel.
  • The inbound webhook identifier to post messages.

Azure Key Vault can store all these items as secrets. In Figure 2, I’m storing the SharePoint site URL.

Storing a secret in Azure Key Vault
Figure 2: Storing a secret in Azure Key Vault

There’s nothing complicated about the secret storage process, and it won’t take long to populate the full set of secrets required by the runbook (Figure 3).

A set of secrets in Azure Key Vault
Figure 3: A set of secrets in Azure Key Vault

Interestingly, Azure detected that I stored a webhook in a secret and posted a message using the webhook, which turned up in Teams (Figure 4). Although I can’t confirm this, it looks like Microsoft uses TruffleHog to scan items stored in Azure Key Vault.

TruffeHog detects a webhook
Figure 4: TruffeHog detects a webhook

After storing our secrets, the next thing to do is to allow access to the accounts and apps that use the secrets. Azure Key Vault uses access policies for this purpose. I used vault access policies rather than those based on Azure Role-based access control.

Each vault access policy determines what an account or app can do with the secrets. In my case, apps only need to read the secrets (a GET operation). In Figure 5, I’m creating an access policy based on the Secret management template. The access policy allows seven secret permissions because I haven’t trimmed the set down to just Get. The important thing in Figure 5 is that I’ve chosen to allow access to the service principal used for the Run As account. Essentially, this means that when the Run As account authenticates, it can gain access to the secrets in the vault.

Allowing access to an Azure Automation Run As account
Figure 5: Allowing access to an Azure Automation Run As account

Accessing Secrets from the Runbook Script

As noted above, the original runbook script uses a credential stored in the Azure Automation account. The updated script (available from GitHub) replaces that credential and the other variables with lookups against Azure Key Vault. The code used to connect to Azure and fetch the secrets is as follows (the code to connect to Azure is dependent on some other variables established earlier in the script).

$AzConnection = Connect-AzAccount -Tenant $Connection.TenantId -ApplicationId `
   $Connection.ApplicationId -CertificateThumbPrint $Connection.CertificateThumbprint `
  -ServicePrincipal
# Get username and password from Key Vault
$UserName = Get-AzKeyVaultSecret -VaultName "Office365ITPros" -Name "ExoAccountName" -AsPlainText
$UserPassword = Get-AzKeyVaultSecret -VaultName "Office365ITPros" -name "ExoAccountPassword" -AsPlainText
# Create credentials object from the username and password
[securestring]$SecurePassword = ConvertTo-SecureString $UserPassword -AsPlainText -Force
[pscredential]$UserCredentials = New-Object System.Management.Automation.PSCredential ($UserName, $SecurePassword)
# Get Site URL to use with PnP connection
$SiteURL = Get-AzKeyVaultSecret -VaultName "Office365ITPros" -name "SPOSiteURL" -AsPlainText
# Target channel identifier for incoming webhook connector
$TargetChannel = Get-AzKeyVaultSecret -VaultName "Office365ITPros" -name "IncomingWebhookId" -AsPlainText
# Target team and channel in that team to which we post a message containing the report
$TargetTeamId = Get-AzKeyVaultSecret -VaultName "Office365ITPros" -name "TargetTeamId" -AsPlainText
$TargetTeamChannel = Get-AzKeyVaultSecret -VaultName "Office365ITPros" -name "TargetChannelID" -AsPlainText

Getting Secrets with Normal PowerShell

The code shown above works when executed in a runbook. With a tweak to the connection to Azure, the same code can fetch secrets from Azure Key Vault when run interactively or in “normal” scripts. As with the runbook, the prerequisite is that a vault access policy must allow the account used to access the vault. With the policy in place, you can run the Connect-AzAccount cmdlet to sign in and execute the same code to retrieve the secrets (Figure 6).

Accessing secrets in Azure Key Vault using interactive PowerShell
Figure 6: Accessing secrets in Azure Key Vault using interactive PowerShell

Alternatively, you can use the SecretManagement PowerShell module and map your key vault. For example, these commands configure the Key Vault for access through cmdlets from the SecretManagement module and then retrieve one of the secrets stored in the vault:

$AzureSubscription = "35429342-a1a5-4427-9e2d-551840f2ad2a"
Register-SecretVault -Module Az.KeyVault -Name MyKV -VaultParameters @{ AZKVaultName = "Office365ITPros"; SubscriptionId = $AzureSubscription}
$AccountName = Get-Secret -Name ExoAccountName -Vault MyKv -AsPlainText

The decision to use one method or another is entirely up to you. Both do the job.

The Obvious Issue

We’re still using a username and password as account credentials. Although it’s true that we have the secrets safely stashed in Azure Key Vault, it’s still single-factor authentication. You can mitigate this somewhat by using an account with an obscure name and a very complex password, but it’s still a potential weakness. Time to do some more research.

A Safe Place for Secrets

My use of Azure Key Vault is simple but effective. I was pleased with how easy it was to store secrets and access secrets. Apart from a secure place to keep sensitive data, it also means that it’s easy to update variables used in a runbook script. I could make the change directly in the runbook script and the code would be a little faster to run, but I do like the idea of being able to secure important information. Give Azure Key Vault a try and see if it works for you!


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.