Automate Azure Key Vault Key Refresh with Managed Identity

Summary

In modern software development, security practices often involve securely managing and regularly updating cryptographic keys used for authentication and encryption. Azure Functions provides a powerful serverless computing platform that can be leveraged to automate tasks like key refreshing. In this article, we'll demonstrate how to create an Azure Function in C# that retrieves public keys from a JWKS (JSON Web Key Set) endpoint and stores them securely in Azure Key Vault.

Prerequisites

Before we start, make sure you have the following prerequisites set up.

  1. Azure Subscription: You'll need an Azure account to create Azure Key Vault.
  2. Azure Key Vault: Create an Azure Key Vault instance where the keys will be stored securely.
  3. Azure Functions: Set up an Azure Functions application in your Azure portal.

Setup Azure Key Vault

 Key Vault

Microsoft

Overview

Keyvault

Create a secret and put any random value in my case I have put the value asif123.

Secret

Azure

See the current version of the Secret.

Current version

Show the Secret Value

Secret Value

Copy Client ID & Tenant ID from your Registered App from Microsoft Entra ID.

Entra ID

Now go to the Web browser and place Tenant ID and Client ID to get the JWKS from Microsoft Entra ID.

https://login.microsoftonline.com/Your_Tenant_ID/discovery/keys?appid=Your_Application_ID

 Tenant ID

Setting up the Azure Function

We will create a C# Azure Function app that uses the HttpClient to fetch keys from a JWKS endpoint and then securely stores them in Azure Key Vault.

Create an Azure Function App in Azure Portal by following the steps.

Azure Function

Azure App

Create Function

Resource

Now Enabling Manage Identity on Azure Function App.

Function App

System

Yes

On

Create Azure Function from Visual Studio.

Visual Studio

Copy the URL from browser

 Browser

Copy the Key Vault URL

Vault URL

Create Azure Function in Visual Studio.

Create Azure

Go to the file and paste the copied URLs in highlighted places.

 Highlighted places

copy the following code and replace the highlighted values.

using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Newtonsoft.Json.Linq;
using System;
using static System.Net.WebRequestMethods;

namespace az_function_app_key_refresher
{
    public static class KeyRefreshFunction
    {
        private static readonly HttpClient httpClient = new HttpClient();

        [FunctionName("KeyRefreshFunction")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("Refreshing Public key.");

            // Fetch JWT keys from JWKS endpoint
            string jwksEndpoint = "https://login.microsoftonline.com/3ed13bce-637a-48c0-9488-1d296357a694/discovery/keys?appid=974b51ab-3fc7-4194-8295-66fc2c020a57";
            string jwksJson = await httpClient.GetStringAsync(jwksEndpoint);
            var jwks = JObject.Parse(jwksJson);

            // Store JWT keys in Azure Key Vault
            await StoreKeysInKeyVault(jwks, log);

            return new OkObjectResult("Public key refreshed and stored in Azure Key Vault.");
        }

        private static async Task StoreKeysInKeyVault(JObject jwks, ILogger log)
        {
            var secretClient = new SecretClient(new Uri("https://azure-function-app-key-refresher.azurewebsites.net"), new DefaultAzureCredential());
            string secretName = "mysecret";

            foreach (var key in jwks["keys"])
            {
                string keyId = key["kid"].ToString();
                string keyJson = key["x5c"].ToString().Replace('[',' ').Replace('"',' ').Replace('"',' ').Replace(']',' ').Trim();

                // Store the key in Azure Key Vault
                await secretClient.SetSecretAsync(secretName, keyJson);
                log.LogInformation($"Stored key with ID {keyId} in Azure Key Vault.");
                break;
            }
        }
    }
}

Run the Azure Function with F5 from Visual Studio in the Local environment and you can test it locally by signing in from Visual Studio to your Azure Portal.

Azure portal

Copy the URL and paste it into the Postman and execute this using Get request.

 Postman

http://localhost:7193/api/KeyRefreshFunction

Fresh Function

When you execute this request from Postman.

Send

you will get the message on the console as highlighted below.

Console

Now go to the Azure portal go to the secret and click on it.

Learn

Now you can see that there are two versions of secret and secret points to the current version.

Mysecret

You can see the secret value that has a new value that was extracted from the JWKS URL.

 JWKS URL

Successfully refreshed the secret at Azure Key Vault from Azure Function that was locally executed using Managed Identity.

Summary

This article outlines the process of automating key refreshing in Azure Functions using C# to securely manage and update cryptographic keys fetched from a JWKS (JSON Web Key Set) endpoint and store them in Azure Key Vault. The article emphasizes modern security practices in software development and the use of serverless computing for automation.

Key Points Covered

  • Security Practices: Emphasizes the importance of securely managing and updating cryptographic keys for authentication and encryption in modern software development.
  • Azure Services Used: Demonstrates the integration of Azure Functions and Azure Key Vault to automate key refreshing tasks.
  • Prerequisites: Lists the prerequisites required to set up the Azure Function and Azure Key Vault, including an Azure subscription and Azure Functions application.
  • Setup of Azure Key Vault: Provides step-by-step instructions on setting up Azure Key Vault, creating a secret, and accessing the secret value.
  • Azure Function Configuration: Details the creation and configuration of an Azure Function app using Visual Studio, enabling managed identity, and integrating with Azure Key Vault.
  • Code Implementation: Presents a C# code snippet for the Azure Function (`KeyRefreshFunction`) that retrieves keys from a JWKS endpoint using `HttpClient` and stores them securely in Azure Key Vault using SecretClient.
  • Testing Locally: Guides on running and testing the Azure Function locally from Visual Studio and Postman, showcasing the successful execution of key refreshing using managed identity.
  • Outcome: Concludes with the successful refresh of the Azure Key Vault secret, demonstrating effective automation of key management tasks within a secure environment.

Overall, this summary encapsulates the process of implementing automated key refreshing in Azure Functions, highlighting best practices in security and Azure services integration for secure key management in cloud-based applications.