I have recently been deploying Azure Functions and have required API keys for invoking other Azure Functions with in the service.
I first created a registry for storing API keys:
module KeyRegistry
let mutable keyFor : Map<string,string> = Map.ofSeq <| seq []
I then created the following class to register the API keys:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Azure.Security.KeyVault.Secrets;
using Azure.Identity;
using static KeyRegistry;
using static System.Environment;
using static Courier.DataTransfer;
namespace Courier.ServiceBus
{
public static class ServiceKeys
{
static Dictionary<string,string> _secrets = new Dictionary<string, string>();
static string _keyVaultName;
static SecretClient _secretClient;
static ServiceKeys()
{
_keyVaultName = GetEnvironmentVariable("KEY_VAULT_NAME");
_secrets = Secrets.Register();
var vaultUrl = $"https://{_keyVaultName}.vault.azure.net";
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions() { ExcludeVisualStudioCodeCredential = true });
_secretClient = new SecretClient(new Uri(vaultUrl), credential);
}
public static bool Initialized;
public static async Task Initialize()
{
try
{
foreach (var entry in _secrets)
{
var secretName = entry.Value.ToString();
var vaultResponse = await _secretClient.GetSecretAsync(secretName);
var secret = vaultResponse.Value;
var host = secretName.Split('-')[0];
var service = secretName.Split('-')[1];
var serviceKey = new ServiceKey(host, service, secret.Value);
keyFor = keyFor.Add(serviceKey.Service, serviceKey.Key);
}
Initialized = true;
}
catch(Exception ex)
{
var error = ex.GetBaseException().Message;
Debug.WriteLine(error);
throw;
}
}
}
}
The keys could then be used as follows:
let resource(service:string) = DevOps.Configuration.Instance.Value |> function
| Dev -> service
| QA -> service |> function
| "MyFn" -> $"{service}?code={keyFor.[service]}"
| "MyOtherFn" -> $"{service}?code={keyFor.[service]}"
| _ -> "Service key not found"
| PROD -> service |> function
| "MyFn" -> $"{service}?code={keyFor.[service]}"
| "MyOtherFn" -> $"{service}?code={keyFor.[service]}"
| _ -> "Service key not found"