1
votes

If I set connection string of AzureWebJobsServiceBus in local.settings.json, then there is no error. However, I would like to use Azure Key-vault to prevent disclosing connection string.

Below is my error:

Microsoft.Azure.WebJobs.Host: Error indexing method 'MyAzureFunc.Run'. Microsoft.ServiceBus: The Service Bus connection string is not of the expected format. Either there are unexpected properties within the string or the format is incorrect. Please check the string before. trying again.

Here is my code:

public static class MyAzureFunc
{
    private static readonly SettingsContext _settings;

    static MyAzureFunc()
    {
        _settings = new SettingsContext(new Settings
        {
            BaseUrl = Environment.GetEnvironmentVariable("BaseUrl"),
            ServiceBusConnectionString = Environment.GetEnvironmentVariable("ServiceBus"),
            certThumbprint = Environment.GetEnvironmentVariable("CertThumbprint"),
            keyVaultClientId = Environment.GetEnvironmentVariable("KeyVaultClientId"),
            ServiceBusSecretUrl = Environment.GetEnvironmentVariable("ServiceBusSecretUrl")
        });

        Environment.SetEnvironmentVariable("AzureWebJobsServiceBus", _settings.ServiceBusConnectionString);
    }

    [FunctionName("Func")]
    public static async Task Run([ServiceBusTrigger(ServiceBusContext.MyQueueName)] BrokeredMessage msg, TraceWriter log)
    {
    ......
    }
}

public SettingsContext(Settings settings)
{
    new MapperConfiguration(cfg => cfg.CreateMap<Settings, SettingsContext>()).CreateMapper().Map(settings, this);
    if (!string.IsNullOrEmpty(settings.certThumbprint) && !string.IsNullOrEmpty(settings.keyVaultClientId))
    {
        var cert = Helpers.GetCertificate(settings.certThumbprint);
        var assertionCert = new ClientAssertionCertificate(settings.keyVaultClientId, cert);
        KeyVaultClient = GetKeyVaultClient(assertionCert);

        if (ServiceBusConnectionString == "nil" && !string.IsNullOrEmpty(settings.ServiceBusSecretUrl))
        {
            ServiceBusConnectionString = KeyVaultClient.GetSecretAsync(settings.ServiceBusSecretUrl).Result.Value;
        }
    }
}

private static KeyVaultClient GetKeyVaultClient(ClientAssertionCertificate assertionCert)
{
    return new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(async (string authority, string resource, string scope) =>
    {
        var context = new AuthenticationContext(authority, TokenCache.DefaultShared);
        var result = await context.AcquireTokenAsync(resource, assertionCert);
        return result.AccessToken;
    }));
}
1

1 Answers

3
votes

This is actually much simpler than what you are trying ;) See here. KeyVault is natively integrated with Azure Functions / App Services for secure storage of settings.

In your local.settings.json you use the connection string as is (in plain text). This file is never checked in.

In Azure you have an app setting with the same name, but instead of putting the plain text connection string, you put the reference to your KeyVault setting like this:

@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)

The only thing you need to do is to enable Managed Identity of your Function and give that identity read permissions in the KeyVault.