Function Apps using Passwords – KeyVaults!

By | September 18, 2020

This will allow you to securely stick a password or any other secret in a Key Vault for usage in a PowerShell function app (or anything else).

You can of course stick the password or whatever directly in the app settings or even an (encrypted) file in your function app but this way has four main advantages –
1 – The person developing the function never needs to know the credentials
2 – You have a single place to update your passwords
3 – You can keep any password or secret including pfx’s in here (even replacing that KeePass database you have hidden on your personal OneDrive with password from the last 15 places you worked)
4 – It’s something new to play with!

It’s worth noting that the most likely use case you just thought of for this method wont work. That would be building a user account for use with MSOLService or CSOnline, storing the password using this method, building a PSCredential object like

$Cred = New-Object System.Management.Automation.PSCredential (“username”, $password)

and using that in a connect- verb. It works in test, it works running in powershell 5 but when you try it in powershell 7 core and in function apps you will get either a message telling you directly to use a service principal or one that somewhat confusingly says you are trying to use a live ID instead of a Microsoft Account. They both effectively have the same result – MS has stopped non-interactive logins in later versions.

If I figure out a workaround or someone tells me one I’ll update.

Create your service account

Okay lets get it on with it. First off we need an account whose password we are going to be hiding (I’m using the AzureAD locally module here):

$PWProfile = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile
$PWProfile.Password = "<<A Password>>"
$PWProfile.EnforceChangePasswordPolicy = $False
New-AzureADUser -UserPrincipalName M365_Ops_ServiceAccount@fleetops.starfleet.com -PasswordProfile $PWProfile -DisplayName "M365 Ops Service Account" -AccountEnabled $true -MailNickName M365_Ops_ServiceAccount

Then you can grant to new account Roles like the Teams Service Administrator Role:

$roleMember = Get-AzureADUser -ObjectId "M365_Ops_ServiceAccount@fleetops.starfleet.com"
$role = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq 'Teams Service Administrator'}
Add-AzureADDirectoryRoleMember -ObjectId $role.ObjectId -RefObjectId $roleMember.ObjectId

If you have any conditional access or other policy that automatically applies to admin role members (enforcing MFA for example) you will need to disable it for the new user.

Next we need a Function App, if you dont already have one for administrating 365 just create one, I have a post on it.

Create your Key Vault

You will also need a Key Vault, so in Azure Portal go to Key Vaults and create a new one. Stick it in the same resource group and your function app ans storage account then just accept the defaults.

If you then go to resource groups and have a look at the group containing your app you should have your function app, your app service plan, your storage account and your key vault

Now we need our function app to be able to access the key vault. Open the Function app and go to Settings | Identity and turn on System assigned managed identity:

This registers the Function app in Azure AD so you can assign permissions directly to it. Copy out the Object ID.

In the Azure portal open Key Vaults then open your new Key Vault. Go to Access Policies | Add Access Policy | Select Principal and paste in the function app Azure AD Object ID then select it. Set Key, Secret and Certificate permissions how you want them. Get for secrets will do for this purpose but I use the key vault for a lot of other things in Function Apps and ONLY in function apps so I just give Full access to everything. Save the changes to the key vault and you’ll be back at the Key Vault blade.

Hit Secrets, we’re going to add our password for our service account in here. Click generate/Import then enter the secret name and value:

Create this, Click back into secrets and you will see out new secret, click it and you’ll see the versions, there is only one, click that and and copy out the Secret Identifier URI.

Now we have a vault with our password in it accessible by our function app, we just need the ability to query it…Back to the Function Apps Blade!

We need to use an app setting to have the function app grab the password from the key vault. On the Function Apps blade open the function app and go to Settings Configuration, the default tab is the application settings so hit “New Application Setting”. The name can be anything but the value should be:

@Microsoft.KeyVault(SecretUri=<<SecretIdentifier>>)

Hit save and you’ll be back at the blade for your function app

Create your Function

Now we can create a function to do the actual work. Click Functions | Add and Create a new function based off a timer.

Open the function, jump into Code and Test and enter:

# Input bindings are passed in via param block.
param($Timer)

$SecretPW = ls env:APPSETTING_M365OpsServiceAccountPW

$SecretPW.value

If you hit Test/Run and run the app then watch the console you’ll see it spits out your password. Note its in plain text so you will “usually” convert it to a secure string.

You can put effectively anything secret in your KeyVault and call it like this. Yay.

Loading

Leave a Reply

Your email address will not be published. Required fields are marked *