0
votes

We are using Azure Functions, which require access to at least 1 Azure Storage location. The Azure Storage Location must support tables, So Azure AD Auth is out. The Connection String for the Storage account, with credential information, must be available to the Function on the environment. Good security practices dictate that we rotate the key with some frequency. We are currently storing keys in Key Vault, and want to continue doing so, rather than storing keys in the Azure Portal.

Are we correct that Azure AD authentication is not valid here since the tokens it produces are not able to be used with tables, which Functions requires?

It would seem that the ideal approach would be to add a new setting in Microsoft.Azure.Storage.CloudStorageAccount,

internal const string AccountKeyVaultLocationSettingString = "AccountKeyVaultLocation";

And then add logic to ParseImpl so that a KeyVault URL representing the secret could be passed into this method, and it would query the key from there.

Another option would be to over-ride Microsoft.Azure.WebJobs.Script.Scaling.StorageConnectionString (and similar connection string settings) so that it will query KeyVault.

Could this be added to the Storage Library? What would be an ETA? Would you welcome contribution on this?

1
If you just want to get Azure storage connection string from Azure Key Vault in Azure function , how about using Azure function managed identity to get from Azure key vault directly ? With this way , you can focus on your logic , there will be no code modification for this integration. For details , see : azure.microsoft.com/en-us/blog/…Stanley Gong
Azure Identity would be the mechanism used to request the key. The issue is in how to configure Azure Storage to know to look for the key in Vault.Daniel
I clicked on the link and see that it appears to be similar to what I am after. The question is, does it make the query one time, or does it requery KeyVault every time it needs the information. For my use case, it needs to refresh the data from KeyVault with some frequency.Daniel
UPDATE: Since Versions are required in the URL, this is not useful. The point is to allow the application to automatically get rotated keys. If we have to manually change the URL, it's not different from manually updating the Key.Daniel
Hi @Daniel, if you are using Azure automation to rotate your keys , you can update the connection string url in your Azure function by Azure automation too at the same time, if you need it I can provide you with a sample . Btw, how about getting your connection string from key vault using key vault sdk in your function logic and connect to your storage then ?Stanley Gong

1 Answers

0
votes

In fact , using this way, you can get your Connection String successfully without version numbers . However, as you said, webapp will load appsettings once and it will not be updated even though your Connection String rotated in Key Vault: We should restart webapp to load latest Connection String version from KV .

You can use Azure app configuration which is a centralized configuration service and you can read latest Connection String from KV easily without restarting your webapp. However, you should care about the security of Azure app configuration connection string ,if you need to rotate it frequently , we goes back.

Maybe using Azure function MSI to get connection string from KV is the best way I know here, try the code below :

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Azure.KeyVault.Models;

namespace FunctionWithAppConfig
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var azureServiceTokenProvider = new AzureServiceTokenProvider();
            string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://vault.azure.net");

            KeyVaultClient kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
            SecretBundle sec = await kv.GetSecretAsync("<your key vault url without version >");
            var StorageConn = sec.Value;

            // connect to your storage ...

            return new OkObjectResult(StorageConn);

        }
    }
}