In Azure Function App, I have added two application settings using the Configuration tab. The first Application setting is fetching the SAS token from the Azure Key vault using #Microsoft.KeyVault(SecretUri=##). The other application setting is the endpoint URL. Now I have to concatenate these two variables and use in connection parameter in HTTP and Queue Trigger.
For example, Below StorageConnectionAppSetting will be the key that will have concatenated value.
public static async Task Run([QueueTrigger("myqueue-items", Connection = "StorageConnectionAppSetting")] string queueItem, ILogger log)
Is there any way this concatenation can be done in the Application setting itself.
This isn't currently possible. Even if you were to customize configuration using DI, it won't work for triggers when deploying to the consumption or premium plans as mentioned at the end of the docs.
Related
Have a function app with single cloud function in it. The cloud function is triggered by an HTTP call and pushes the payload to a Azure service bus queue. What needs to be done is, as part of automated deployment, would like to have few variables configured per environment -
Function Name
Queue Name
Queue Connection String
Deployment is to be done using Azure DevOps. Function code is also on Azure DevOps repository which will have branch for each environment, so will need function with different function name for eg - Dev_Function, QA_Function,etc since it needs to connect to corresponding environment queue. Also aware that variables can be configured using App Settings on Azure portal. Any help/insights appreciated!
i think you could keep the function name as it is and change make the Queue name and Connection string to be pickup from Azure function app service configuration.
[FunctionName("SendEmailFunc")]
public static async Task SendEmailFunc([QueueTrigger($"%{FuncAppConstants.Queue.EmailQueueName}%")] EmailMessage emailMessage)
{
}
you can get the queue name at runtime by using this
[QueueTrigger($"%prod_queue_name%")]
and configuration will just look like below in the local.setting.json
"prod_queue_name": "test-email-queue"
and similarly in the Azure function app configuration
And same can be done for the connection string
I'm trying to understand the integration between Azure Functions and Key Vault. In the application settings file on the portal, if I reference a KV endpoint, does the Function runtime retrieve the result once and cache it locally or does it hit the endpoint every time the config key is referenced? In other words, I'm trying to understand if any changes in KV will require the Function app to be restarted or not.
Update:
Versions no longer required for Key Vault references in App Service and Azure Functions
If a version is not specified in the reference, then the app will use the latest version that exists in Key Vault. When newer versions become available, such as with a rotation event, the app will automatically update and begin using the latest version within one day. Any configuration changes made to the app will cause an immediate update to the latest versions of all referenced secrets.
If you use App Service Key Vault References, you will need to update the configuration value in the Azure Portal. Restarting will not change anything. This is because you are referencing an actual secret version. If you update the secret, you will get a new version.
Versions are currently required. When rotating secrets, you will need to update the version in your application configuration
See also Azure Function App use latest version of Key Vault Secret via Application Settings
For now, you don't need to restart your Azure function manually if you update a key value in Key Vault. The azure function will restart automatically for you to load all new values.
Azure functions load values defined in application settings at the start stage, if you use App Service Key Vault References in your Azure function, the key value will also be loaded from Key Vault at the start stage. If you modify application settings on Azure Portal, your Azure function will get restarted to reload all settings:
These are my test steps:
My code is simple, just get the key value from application settings:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string key = Environment.GetEnvironmentVariable("key");
return new OkObjectResult(key);
}
My key config in application settings:
As you can see I did not involve SecretVersion, so that I can get the latest value in KeyVault. If you involve SecretVersion in application settings, as #Alex AIT said, you should modify application settings with the latest SecretVersion as well.
Before I modify the key value:
Then I update the key4demo value in Key vault as: 78910
The Azure function reply 503 which means it is restarting :
After few seconds, my function replys me with the latest value in KV:
no, no need to restart function or anything. Key Vault lives a separate life.
Microsoft Docs
If a version is not specified in the reference, then the app will use the latest version that exists in the key vault. When newer versions become available, such as with a rotation event, the app will automatically update and begin using the latest version within 24 hours. The delay is because App Service caches the values of the key vault references and refetches it every 24 hours. Any configuration changes to the app that results in a site restart causes an immediate refetch of all referenced secrets.
I was able to use the Key Vault inside a function app as described here but when I tried to use the Key Vault to hold the connection string of a function with a queue trigger I have issues with the storage account connection string. The function seems to find the parameter I provide but either doesn't get the secret back or doesn't like the information when it throws the error No valid combination of account information found.
My function is defined as:
[FunctionName("ReadQueueForMessage")]
public static async Task Run([QueueTrigger("%AzureQueueTrigger%", Connection = "AzureWebJobsStorage")] string myQueueItem,
Binder binderinputblob,
ILogger log)
This works fine if I just define the connection string in my local.settings.json. What I'm trying to do is instead of just putting the connection string in the json file, I want to point the function to the Key Vault with this syntax:
"AzureWebJobsStorage": "#Microsoft.KeyVault(SecretUri=https://myappkeyvault.vault.azure.net/secrets/myapp-AzureWebJobsStorage-Queue/the-guid-of-secret)",
I did go to the Key Vault and update the access policies to include the function app so it can read/list the secrets. The documentation here shows making an update to the configuration after it was deployed to Azure. I'm trying to test first in Visual Studio. Maybe that is the issue? Or is it not possible at all to use the secret in this manner?
I'm trying to test first in Visual Studio.
For now using Azure Key Vault references with Azure Functions does not support to work on local, as confirmed by Azure Functions team. If you still want to test on local, you could implemented an incomplete local workaround like this issue.
I test on portal and it works well. You could refer to the following steps as below:
1.In VS Function.cs, then publish to azure:
public static void Run([QueueTrigger("queue", Connection = "AzureWebJobsStorage")]string myQueueItem, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {myQueueItem}");
string connectionString = System.Environment.GetEnvironmentVariable("AzureWebJobsStorage");
log.Info($"The connection string is {connectionString}");
}
2.Set AzureWebJobsStorage on Appsettings setting on portal.
3.Then it will work fine.
With the Nuget packages Azure.Extensions.AspNetCore.Configuration.Secrets and Azure.Identity you can now use the KeyVault as a configuration provider, the same way as in ASP.NET Core. You need to add a class derived from FunctionsStartup to add the KeyVault as a configuration provider, see Add FunctionsStartup class with the KeyVault as a configuration provider.
If you add the AzureWebJobsStorage connection string as a secret to the KeyVault, you can remove it from the Configuration section of your Function App in Azure. Make sure to turn on System assigned in the Identity section and in the KeyVault add an Access Policy with the Secret permissions Get and List for your Function App.
When you run your Function App local for debugging, Azure.Identity automatically uses your Microsoft Account for access to the KeyVault, if it has at least Get and List access to the secrets.
Unfortunately, when you test local, the Function App does NOT read AzureWebJobsStorage from the configuration/KeyVault, but requires it to be stored in local.settings.json. To prevent storing keys on your local computer, you can set AzureWebJobsStorage to "UseDevelopmentStorage=true" in local.settings.json.
For detailed instructions see: Create Azure Function App with Dependency Injection and the Key Vault as Configuration Provider.
Example project: https://github.com/Forestbrook/FunctionWithKeyVaultAndDI
I developed a cron trigger azure fuction who needs to search for soe data in my database.
Localy i can connect whit sql server, so i change the connection string in loca.settings.json to connect in azure sql and published the function, but the function cant connect with database.
I need to do something more than configure the local.settings.json?
The local.settings.json is only used for local testing. It's not even exported to azure.
You need to create a connection string in your application settings.
In Azure Functions - click Platform features and then Configuration.
Set the connection string
A function app hosts the execution of your functions in Azure. As a best security practice, store connection strings and other secrets in your function app settings. Using application settings prevents accidental disclosure of the connection string with your code. You can access app settings for your function app right from Visual Studio.
You must have previously published your app to Azure. If you haven't already done so, Publish your function app to Azure.
In Solution Explorer, right-click the function app project and choose Publish > Manage application settings.... Select Add setting, in New app setting name, type sqldb_connection, and select OK.
Application settings for the function app.
In the new sqldb_connection setting, paste the connection string you copied in the previous section into the Local field and replace {your_username} and {your_password} placeholders with real values. Select Insert value from local to copy the updated value into the Remote field, and then select OK.
Add SQL connection string setting.
The connection strings are stored encrypted in Azure (Remote). To prevent leaking secrets, the local.settings.json project file (Local) should be excluded from source control, such as by using a .gitignore file.
https://learn.microsoft.com/en-us/azure/azure-functions/functions-scenario-database-table-cleanup
If you are using entity framework core to make a connection, Other Way of connection to SQL is by using dependency injection from .netcore library.
You can keep the connection string in Azure Key-vault or the config file from there you can read the same using azure function startup class. which need below code setup in your function app.
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof( TEST.Startup))]
namespace TEST
{
internal class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
Contract.Requires(builder != null);
builder.Services.AddHttpClient();
var configBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddAzureKeyVault($"https://XYZkv.vault.azure.net/");
var configuration = configBuilder.Build();
var conn = configuration["connectionString"];
builder.Services.AddDbContext<yourDBContext>(
options => options.UseSqlServer(configuration["connectionString"]));
}
}
}
after that where ever you are injecting this dbcontext, with context object you can do all CRUD operations by following microsoft's entity framework core library documentation.
Having just dealt with this beast (using a custom handler with Linux), I believe the simple way is to upgrade your App to premium-plan, allowing you to access the "Networking" page from "App Service plans". This should allow you to put both sql-server and app in the same virtual network, which probably makes it easier. (but what do I know?)
Instead, if you don't have the extra cash laying around, you can try what I did, and set up a private endpoint, and use the proxy connection setting for your database:
Create a virtual network
I used Address space: 10.1.0.0/16 (default I think)
Add subnet 10.1.0.0/24 with any name (adding a subnet is required)
Go to "Private link center" and create a private endpoint.
any name, resource-group you fancy
use resource type "Microsoft.Sql/Server" and you should be able to select your sql-server (which I assume you have created already) and also set target sub-resource to "sqlServer" (the only option)
In the next step your virtual network and submask should be auto-selected
set Private DNS integration to yes (or suffer later).
Update your firewall by going to Sql Databases, select your database and click "Set Server Firewall" from the overview tab.
Set Connection Policy to proxy. (You either do this, or upgrade to premium!)
Add existing virtual network (rule with any name)
Whitelist IPs
There probably is some other way, but the azure-cli makes it easy to get all possible IP's your app might use: az functionapp show --resource-group <group_name> --name <app_name> --query possibleOutboundIpAddresses
https://learn.microsoft.com/en-us/azure/app-service/overview-inbound-outbound-ips
whitelist them all! (copy paste exercise)
Find your FQDN from Private link center > Private Endpoints > DNS Configuration. It's probably something like yourdb.privatelink.database.windows.net
Update your app to use this url. You just update your sql server connection string and replace the domain, for example as ADO string: Server=tcp:yourdb.privatelink.database.windows.net,1433;Initial Catalog=somedbname;Persist Security Info=False;User ID=someuser;Password=abc123;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;
Also note that I at some point during all of this I switched to TrustServerCertificate=True and now I can't bother to figure out if it does a difference or not. So I left it as an exercise to the reader to find out.
So what we have done here...?
We have forced your function app to go outside the "azure-sphere" by connecting to the private endpoint. I think that if you bounce between azure-services directly, then you'll need some sort of authentication (like logging in to your DB using AD), and in my case, using custom handler and linux base for my app, I think that means you need some trust negotiation (kerberos perhaps?). I couldn't figure that out, so I came up with this instead.
I am having an issue where my event hub name is not found when I publish my function to a function app (It works fine locally, if I just run it in VS2017). I am recieving the following error on the published function in the azure portal when I open the function.
This is the attribute on my Run method.
public static void Run([EventHubTrigger("%eventHubName%", Connection = "eventHubConnection")]string data, TraceWriter log)
Now if I don't include the %'s wrapped around the eventHubName, when I run it locally it will say that it can't find the eventhub (Using the eventHubName string literally instead of looking into the local.settings.json like the connection string), but it will work when it is published. I am wanting to avoid putting the actual name in the attribute as different environments will have unique event hub names.
Azure Functions will use the local.settings.json file when you are developing locally. When your Function App is running on Azure, it will read the values from the Application Settings.
Using the %zzz% is the correct way to read settings, so this makes me question if you have a setting called eventHubName in Application Setting when you deploy to Azure.
https://learn.microsoft.com/en-us/azure/app-service/web-sites-configure