In some of my previous blogs here, we have seen how we could use Azure Functions to to automate processes and SharePoint workloads.

Most of these jobs run using elevated or stored privileged accounts as the Azure Function is in a different context than the user context. There are various ways we could setup these accounts. Some of these approaches are below:

  1. Azure AD Service Accounts
    • Suitable for all operations
    • Need access to resource
    • Reusable across multiple workloads
  2. Azure AD Apps
    • Suitable for Graph Access
    • Need exact permissions set up
    • Might need Tenant Admin authentication
  3. SharePoint App Accounts
    • Suitable for SharePoint workloads.
    • Need Site and App specific privileges

The details of these accounts could be stored in the Azure Functions App Settings (for dev and production) or local.settings.json file during local development.

The most important consideration would be to prevent from exposing password details in the Azure functions in case of unauthorized access. There are two ways we could achieve this:

  1. Encrypting the password and store in the Azure Function (PowerShell)
  2. Using Azure Key Vault to store and access password details (C#)

Encrypting Passwords in Azure Functions

For doing this, first lets’ create an encrypted password using PowerShell using the script below.


## Create an Encrypted Password ##
$AESKey = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey)
Set-Content C:\Temp\<PasswordFileName>.key $AESKey
## Run the above code first, then upload the above file to the Function App##
Function Get-EncryptedPassword
{
param (
[Parameter(Mandatory=$true,HelpMessage='Please specify the key file path')][ValidateScript({Test-Path $_})][String]$KeyPath,
[Parameter(Mandatory=$true,HelpMessage='Please specify password in clear text')][ValidateNotNullOrEmpty()][String]$Password
)
$secPw = ConvertTo-SecureString -AsPlainText $Password -Force
$AESKey = Get-content $KeyPath
$Encryptedpassword = $secPw | ConvertFrom-SecureString -Key $AESKey
$Encryptedpassword
}
Get-EncryptedPassword -KeyPath C:\Temp\<PasswordFileName>.key -Password <Password>

Next, copy the file to a bin folder in Azure Function using Azure File Explorer (Application Settings -> App Service Editor) and decrypt using the code below


$userPass = $env:EncryptedPass
$keyPath = 'D:\home\site\wwwroot\<FunctionName>\bin\<PasswordFileName>.key'
$secPass = $userPass | ConvertTo-SecureString -Key (Get-Content $keyPath)

Using Azure Key Vault

For using Azure Key Vault, the steps are as below

  1. Create an Azure AD App and get the Client ID and Client Secret
  2. Create a Azure Key Vault and add the above Azure AD app to have Get Access to the key vault. The below permissions will suffix to read the secret.
    Azure Key Vault Secret Permissions
  3. Create Secret in key vault, then store the password and the secure Uri
  4. Store the Secret Uri, Client ID and Client Secret in Azure App Settings
  5. Use the below code to get the secure pass.


public SecureString GetSecret()
{
try
{
// Get the Secret Uri from Key Vault
string SecretUri = System.Environment.GetEnvironmentVariable("<KeyValutSecretUri>");
var kvToken = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
var kvSecret = kvToken.GetSecretAsync(SecretUri).Result;
SecureString secpass = new SecureString();
foreach (char charpass in kvSecret.Value)
{
secpass.AppendChar(charpass);
}
return secpass;
}
catch (Exception ex)
{
throw ex;
}
}
public async Task<string> GetToken(string authority, string resource, string scope)
{
AuthenticationResult authResult = null;
try
{
string ClientId = System.Environment.GetEnvironmentVariable("ClientId");
string ClientSecret = System.Environment.GetEnvironmentVariable("ClientSecret");
var authContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(ClientId, ClientSecret);
Task authTask = Task.Run(async () => authResult = await authContext.AcquireTokenAsync(resource, clientCred));
authTask.Wait();
}
catch (Exception ex)
{
throw new Exception($"Function Error at Token Retrieval: {ex.Message}");
}
if (authResult == null)
throw new InvalidOperationException("Failed to obtain the JWT token");
return authResult.AccessToken;
}

Conclusion

Hence above we saw how we could set up accounts in Azure Function for elevated access to SharePoint and Resource locations.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s