Before diving in, we have already set up a Key Vault on the Azure portal and now, we want to access the stored secrets on Key Vault in our Azure Function.
However, you are probably wondering: "How do I use it?" Can I access the Key Vault in the same way as I did in the ASP.NET CORE web application?
The answer is NO. Don't you lose hope; we are here to demystify the secret.
We can access the Key Vault Secret in our Azure Function in two different ways
- Application settings from Key Vault
@Microsoft.KeyVault(SecretUri=secret_uri_with_version) Allowing Application settings to access KeyVault via secret URL
- Managed Identities for App Services
By giving access rights to our Azure Function to access the Key Vault secrets with the help of Secret URI
https://{name}.vault.azure.net/secrets/{secretname})
Case Study
Let us look at an example where we want to access some secret keys in our Azure function to achieve our business requirement. Considering that we are trying to solve a business problem with this HTTP Trigger Azure function, let us do a proof of concept that the Azure function should be an HTTP trigger Azure function. Once the user tries to consume the Azure function, it should show those secret values in the response.
Here are the 3 requirements that you will discover,
-
Configure the Azure function to communicate with Key Vault when deployed on the local development environment and Azure.
-
Locate where to store keys in the local development environment.
-
Learn how to Deploy Azure function on Azure.
Prerequisite
-
Active Azure subscription
-
-
Azure Function
-
Azure Active Directory
-
Key Vault
How do we proceed?
Breaking down the problem into smaller chunks first that’s how we will be proceeding ahead step by step,
- Create your first HTTP Trigger Azure function. If you are not aware of HTTP Trigger functions, my honest suggestion will to go and read this article HTTP Trigger Azure Function(Serverless Computing).
- Create a Service Library which will interact with Key Vault.
- Access the value from local.settings.json in our development environment.
- Create Azure Resources needed for this Demo.
- Provide Key Vault access identity to the Function app using the PowerShell command, manually from the portal.
Let's get started and create our Azure function using Visual Studio.
Select HTTP Trigger Template and select Azure Functions V1 because, in version V2, I had some issues with the HTTP trigger function when I tested on my local machine while writing this.
Template generated code for HTTP trigger.
- using System.IO;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Azure.WebJobs;
- using Microsoft.Azure.WebJobs.Extensions.Http;
- using Microsoft.AspNetCore.Http;
- using Microsoft.Azure.WebJobs.Host;
- using Newtonsoft.Json;
-
- namespace AzFuncKeyVaultIntegration
- {
- public static class Function1
- {
- [FunctionName("Function1")]
- public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
- {
- log.Info("C# HTTP trigger function processed a request.");
- string name = req.Query["name"];
- string requestBody = new StreamReader(req.Body).ReadToEnd();
- dynamic data = JsonConvert.DeserializeObject(requestBody);
- name = name ?? data?.name;
- return name != null
- ? (ActionResult)new OkObjectResult($"Hello, {name}")
- : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
- }
- }
- }
Now, let's create a Service Library which will have all responsibility of calling Key Vault APIs and return us the actual value of our secret keys.
Creating a new Class Library from our solution
Install the below packages to interact with Key Vault from our services library from NuGet.
- Microsoft.Azure.Services.AppAuthentication Version:1.0.3
- Microsoft.Extensions.Configuration.AzureKeyVault Version: 2.2.0
Once done, create a class named KeyVaultService putting in the below code snippet.
- using Microsoft.Azure.KeyVault;
- using Microsoft.Azure.Services.AppAuthentication;
- using System;
- using System.Threading.Tasks;
-
- namespace Services
- {
- public class KeyVaultService
- {
- public async Task GetSecretValue(string keyName)
- {
- string secret = "";
- AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
- var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
-
-
- var secretBundle = await keyVaultClient.GetSecretAsync(Environment.GetEnvironmentVariable("keyvault") + keyName).ConfigureAwait(false);
- secret = secretBundle.Value;
- Console.WriteLine(secret);
- return secret;
- }
-
- }
- }
Now, reference the service library in your Azure Function project.
So now, let's consider I have created two secrets in Azure Key Vault; for example:
- applicationSecret2
- secret2
Now I want to access the Key Vault secret applicationSecret2 with the help of managed identities and another secret, secret2, with the help of Key Vault references for Application Settings on Azure.
In the ASP.NET core web application, we were using Secret Manager to store our secrets in Development. If you want to read about Secret Manager you can start from here
Secret Manager in ASP.NET CORE. In order to access the managed identities value in a local environment, we will be required to add DNS name in local.settings.json and for secret2 value, we can just create a key-value pair with a value as shown below:
Access the App settings keys value and call the Service function (GetSecretValue) in Function code,
- using System;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Threading.Tasks;
- using Microsoft.Azure.WebJobs;
- using Microsoft.Azure.WebJobs.Extensions.Http;
- using Microsoft.Azure.WebJobs.Host;
- using Services;
-
- namespace AzFuncKeyVaultIntegrationM
- {
- public static class Function1
- {
- [FunctionName("Function1")]
- public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
- {
- log.Info("C# HTTP trigger function processed a request.");
- KeyVaultService _service = new KeyVaultService();
-
- string secretValue = await _service.GetSecretValue("applicationSecret2");
- log.Info("Secret value retrived via Secret Uri" + secretValue);
-
- string name = req.GetQueryNameValuePairs()
- .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
- .Value;
- if (name == null)
- {
-
- dynamic data = await req.Content.ReadAsAsync();
- name = data?.name;
- }
- return name == null
- ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
- : req.CreateResponse(HttpStatusCode.OK, $"Hello {name} using keyvault Syntax from app settings {Environment.GetEnvironmentVariable("secret2")}");
- }
- }
- }
Let's run our application in our development environment. Now check whether our Function app is able to retrieve the secrets or not.
In order to consume this HTTP trigger Azure function, I will be using the Postman Rest HTTP client. We will consume the "http://localhost:7071/api/Function1" endpoint.
Configure Application Settings from Key Vault on Azure
We are successfully able to run our application from our development environment. Now we will deploy our application on Azure and try to access secret secret2 from Key Vault in application settings. This feature works that similarly as we are just using AppSetting key-value pair but internally it retrieves the value from Key Vault. In order to make this work, we have to configure the access policy to Function App, once we deploy our Function app.
Let us first deploy our Azure function on Azure Portal using Visual Studio:
As I don't have any Azure App Service on Azure I will create a new Azure App Service step by step,
Click on Publish.
Then click on Create. Visual Studio will publish our application now. Once this is completed the Azure function will be published, and we can check the status in an Output window.
Let's now login to the Azure portal to see if our Function app has been created or not.
Assign your function app access to the Key Vault step by step,
Once you are done click on OK and save the access policy.
Once done now enable System Identity in order to authenticate to cloud services (e.g. Azure Key Vault, Active Directory).
- Go to function app settings.
- Click on platform features.
- Click on Identity features in the list.
Let us now first get the secret_uri_with_version for secret named applicationSecret1 which will be stored in the secret2 key in appSettings.
Go to the Key Vault resource that you want to consume and then click on Secret. Now in our function app, I want to use the value of my applicationSecret1 secret which is configured in my (environment variable or AppSettings) on Azure as secret2.
Now Click on applicationSecret1 and you will be navigated to version blade view as shown below:
Click on the Current Version row and now copy the Secret identifier value from the new page as shown below:
Now go back to the function app and create a new application variable/application setting named "secret2" and put the value in the given format with your secret URL that we just copied, also add other application setting keys and values that are required for the function app like DNS which was present in the local.settings.json file.
Format of Key Vault Value for secret
@Microsoft.KeyVault(SecretUri=secret identifier value)
Once all steps are completed save the application settings and let's try to consume the deployed Azure function from Postman now.
Click on Function1 and then click on get function URL and copy the URL:
Hit the URL from POSTMAN and you will see the value retrieved from the Key Vault.
So you can see how easily step by step we learned "how to Authorize your Key Vault Secrets to Serverless Azure Function"
I hope you enjoyed reading the article as much as I did writing this up.
If you did, leave your thoughts in the comments below.
Also, I will love it if you share the article on your preferred social media platform.
References