8

I was wondering if it's possible to initialize the queue trigger or even the blob trigger off a connection string that is read from azure vault.

Right now, we have to set these data connection via environment settings via blade properties. However, I wanted to just use the service principal to retrieve the token for the azure key vault to get all these connection strings.

I'm trying to figure how to get this working in java.

Thanks, Derek

Thomas
  • 24,234
  • 6
  • 81
  • 125
darewreck
  • 2,576
  • 5
  • 42
  • 67

5 Answers5

12

This feature is tracked and in progress here:

EDIT 28/11/2018: It is currently in preview

Former answer 07/10/2018 This solution won't work for Triggers using the consumption plan.

In the mean time I did some research about your problem and it is possible to read config from key vault if you use Azure Function v2.

I've created an Azure Functions v2 (.NET Standard) from Visual Studio.

It uses:

  • NETStandard.Library v2.0.3
  • Microsoft.NET.Sdk.Functions v1.0.22
  • Microsoft.Azure.WebJobs v3.0.0
  • Microsoft.Azure.WebJobs.Extensions.Storage v3.0.0

Because Azure Functions v2 uses ASP.NET core, I was able to reference this link to configure my functions app to use Azure Key Vault:

Azure Key Vault configuration provider in ASP.NET Core

  1. I've added this nuget package:

I've configured my app to use this nuget package:

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;

[assembly: WebJobsStartup(typeof(FunctionApp1.WebJobsExtensionStartup), "A Web Jobs Extension Sample")]
namespace FunctionApp1
{
    public class WebJobsExtensionStartup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            // Get the existing configuration
            var serviceProvider = builder.Services.BuildServiceProvider();
            var existingConfig = serviceProvider.GetRequiredService<IConfiguration>();

            // Create a new config based on the existing one and add kv
            var configuration = new ConfigurationBuilder()
                .AddConfiguration(existingConfig)
                .AddAzureKeyVault($"https://{existingConfig["keyVaultName"]}.vault.azure.net/")
                .Build();
        
            // replace the existing configuration
            builder.Services
                .Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), configuration));
        }
    }
}

My Azure functions uses MSI:

Azure Functions - Managed Service Identity

I've granted Read/List secrets permissions to the function app on my key vault:

I have a small queue triggered function:

public static class Function2
{
    [FunctionName("Function2")]
    public static void Run([QueueTrigger("%queueName%", Connection = "queueConnectionString")]string myQueueItem, ILogger log)
    {
        log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
    }
}

The queueName is defined in the local.settings.json file (App settings blade once deployed):

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "keyVaultName": "thomastestkv",
    "queueName": "myqueue"
  }
}

The queueConnectionString is configured in my keyvault:

Azure Key Vault - Secrets

Thomas
  • 24,234
  • 6
  • 81
  • 125
  • Thanks!..I'm in the java world thou...so I'm not sure if that is possible. Right now the existing sdk https://github.com/Azure/azure-keyvault-java. Do you have any idea if they provide the same mechanism to configure the initial azure function at load time? – darewreck Oct 06 '18 at 21:48
  • Oh sorry did not know that you were using the java sdk. Dont know how the azure function runtime works... – Thomas Oct 06 '18 at 22:15
  • 1
    Its good info to know thou, if I end up going the .netcore route. At least I know it's possible, and hopefully they make it supported in the java runtime. I'm sure this post will be helpful for anyone one else looking in the future. Most cases they will be using .netcore – darewreck Oct 06 '18 at 22:17
  • I'll try to dig into the java sdk but dont have any java envrionment on my laptop ... – Thomas Oct 07 '18 at 02:37
  • 3
    Please be aware, this approach won't work when running in the consumption plan. The infrastructure run by azure functions that monitors your triggers and figures out when to run the app won't be able to see the service bus and decide when to scale the application. Some of the github issues linked above point to additional work that is happening in functions to better support this scenario. – Paul Batum Nov 16 '18 at 17:50
  • @PaulBatum, thanks for your comment. So it won't work for triggers like servicebus/ queue storage or for any kind of binding ? If I have a input blob binding would it work under the consumption plan ? – Thomas Nov 22 '18 at 07:55
  • Only drawback is overriding IConfiguration might be a problem. It will clear any default function settings load like function timeout https://github.com/Azure/azure-functions-durable-extension/issues/1313 – SanjayD Jul 30 '20 at 09:13
4

Sourcing Application Settings from Key Vault The Key Vault references feature makes it so that your app can work as if it were using App Settings as they have been, meaning no code changes are required. You can get all of the details from our Key Vault reference documentation, but I’ll outline the basics here.

This feature requires a system-assigned managed identity for your app. Later in this post I’ll be talking about user-assigned identities, but we’re keeping these previews separate for now.

You’ll then need to configure an access policy on your Key Vault which gives your application the GET permission for secrets. Learn how to configure an access policy.

Lastly, set the value of any application setting to a reference of the following format:

@Microsoft.KeyVault(SecretUri=secret_uri_with_version)

Where secret_uri_with_version is the full URI for a secret in Key Vault. For example, this would be something like: https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931

enter image description here

That’s it! No changes to your code required!

For this initial preview, you need to explicitly set a secret version, as we don’t yet have built-in rotation handling. This is something we look forward to making available as soon as we can.

User-assigned managed identities (public preview) Our existing support for managed identities is called system-assigned. The idea is that the identity is created by the platform for a specific application and is tied to the lifecycle of the application. If you delete the application, the identity is removed from Azure Active Directory immediately.

Today we’re previewing user-assigned identities, which are created as their own Azure resource and then assigned to a given application. A user-assigned identity can also be assigned to multiple applications, and an application can have multiple user-assigned identities.

enter image description here

more details check this

  • We have 2 user assigned identities assigned to our function for different uses. I don't see how you can specify which identity to use with "@Microsoft.KeyVault(SecretUri=secret_uri_with_version)" and this is failing. We can properly access using Microsoft.Azure.Services.AppAuthentication at runtime passing in the Id of the identity, but not sure how to do this via AppSettings – Matt Sanders May 23 '19 at 23:52
  • @MattSanders, I don't think above "@Microsoft.KeyVault(SecretUri=secret_uri_with_version)" should know about identity, identity represents the application or the user that trying to access the vault, for an example, if you accessing a key through web API application, that application should add as an Identity, – Thilanka Ishara Gunathilake May 24 '19 at 11:18
  • if the user has assigned multiple identities to the application, how would this feature know which one to use? – Matt Sanders May 28 '19 at 17:28
  • I have 2 user assigned identities, 1 has permissions to KeyVault, the other does not. How can you specify the correct user assigned identity to use for retrieving the secret? I'm guessing this is not possible and User Assigned Identities are not supported even though they are listed in your answer. – Matt Sanders May 29 '19 at 19:44
  • @MattSanders, since I can't attach images here, i've put an answer below, please check and share your thoughts, thanks – Thilanka Ishara Gunathilake May 30 '19 at 06:03
  • This approach has the restriction that it doesn't work if the KeyVault has a firewall to limit access to traffic from a VNet subnet. In that case, AddAzureKeyVault works because the app service itself can use the VNet Integration and make the calls via the VNet to KeyVault – hansmbakker Jul 30 '20 at 09:17
1

Update

This is now GA

This was just released as preview a couple days ago.

This feature requires a system-assigned managed identity for your app. Later in this post I’ll be talking about user-assigned identities, but we’re keeping these previews separate for now.

You’ll then need to configure an access policy on your Key Vault which gives your application the GET permission for secrets. Learn how to configure an access policy.

Lastly, set the value of any application setting to a reference of the following format:

@Microsoft.KeyVault(SecretUri=secret_uri_with_version)

Where secret_uri_with_version is the full URI for a secret in Key Vault. For example, this would be something like: https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931

Using Keyvault integration within the function runtime

MrBrooks
  • 186
  • 6
0

I just implemented it in Java following below two references.

  1. https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references

  2. https://medium.com/statuscode/getting-key-vault-secrets-in-azure-functions-37620fd20a0b

in java use System.getenv("SECRET_KEY") to read the values from your app settings.

Happy to help if you need further assistance.

T D
  • 1,080
  • 2
  • 13
  • 20
0

I have already given my answer in above, this answer is for @Matt Sanders's comment, i just want to explain how MSI working in the Azure Environment,

"I have 2 user assigned identities, 1 has permissions to KeyVault, the other does not. How can you specify the correct user assigned an identity to use for retrieving the secret? I'm guessing this is not possible and User Assigned Identities are not supported even though they are listed in your answer. – Matt Sanders"

when you want to use Azure Manage Identity Service, your application must register in the Azure AD, for an example, lets say multiple users accessing your web application and, within your web application, you 'r trying to access vVault's secrets, In that case, vault doesnt care about the users that consume your application, it cares about the application,

please reffer below image,

enter image description here

I as showing the picture, only Azure Function added as an Identity to the vault, other applications are not,

so whoever using Azure function can access vault's secrets, according to this example only A and B can access secrets,

  • Thank you for trying to explain this, but this does not reference the User Assigned Managed Identities listed in the bottom of your original answer. I do not see support for these with your original answer and you should just remove the bottom section about user assigned managed identities from the answer to avoid confusion as it is unrelated to your otherwise great answer. – Matt Sanders May 31 '19 at 07:49