////Declare Interface
public interface IKeyVaultService
{
public string GetSecret(string secretName, bool appendPrefix = true);
}
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
public class KeyVaultService : IKeyVaultService
{
private const string _PREFIX = "XXX";
private readonly string _keyVaultBaseUrl;
protected SecretClient _keyVaultClient;
private static readonly ConcurrentDictionary<string, string> _keyVaultSecrets =
new ConcurrentDictionary<string, string>();
private readonly KeyVaultConfigAppSetting _keyVaultLocalConfigAppSetting;
private readonly ILogger _logger;
/// <summary>
/// initialize
/// </summary>
/// <param name="keyVaultLocalOptions"></param>
/// <exception cref="Exception"></exception>
public KeyVaultService(
IOptions<KeyVaultConfigAppSetting> keyVaultLocalOptions
,ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<KeyVaultService>();
_keyVaultLocalConfigAppSetting = keyVaultLocalOptions.Value;
_keyVaultBaseUrl = _keyVaultLocalConfigAppSetting.BaseUrl;
_keyVaultBaseUrl = _keyVaultLocalConfigAppSetting.BaseUrl
?? throw new InvalidOperationException
("KeyVaultBaseUrl is null or not configured");
EnsureConfigured();
}
/// <summary>
/// get secret value from keyvault
/// </summary>
/// <param name="secretName"></param>
/// <param name="appendPrefix"></param>
/// <returns></returns>
public string GetSecret(string secretName, bool appendPrefix = true)
{
try
{
EnsureConfigured();
if (appendPrefix && !secretName.StartsWith(_PREFIX))
secretName = $"{_PREFIX}{secretName}";
_keyVaultSecrets.TryGetValue(secretName, out var secretValue);
if (string.IsNullOrEmpty(secretValue))
{
var secretBundle = _keyVaultClient.GetSecret(secretName);
secretValue = secretBundle.Value?.Value;
if (!string.IsNullOrEmpty(secretValue))
_keyVaultSecrets.TryAdd(secretName, secretValue);
}
return secretValue;
}
catch (Exception ex)
{
_logger.LogError(ex, "Keyvalut Error:{0} {1}", GetType()?.Name, ex.Message);
throw new InvalidOperationException
("An error occurred while accessing the Keyvault.", ex);
}
}
private void EnsureConfigured()
{
if (_keyVaultClient == null)
#if DEBUG
//Create azure key-vault instance using Application client id and client secret.
ConfigureWithClientCredentials();
#else
ConfigureAzureCredentials();
#endif
}
private void ConfigureWithClientCredentials()
{
var tenantId = _keyVaultLocalConfigAppSetting.TenantId;
var sharedSecretKey = _keyVaultLocalConfigAppSetting.SharedSecretKey;
var sharedSecretAppId = _keyVaultLocalConfigAppSetting.AppId;
// If Shared Secret is present and not "Disabled",
// use the shared secret (typically for local development).
if (!string.IsNullOrWhiteSpace(sharedSecretKey)
&& sharedSecretKey != "Disabled")
{
ClientSecretCredential clientCredential =
new ClientSecretCredential
(tenantId, sharedSecretAppId, sharedSecretKey);
_keyVaultClient = new SecretClient
(vaultUri: new Uri(_keyVaultBaseUrl), credential: clientCredential);
}
else
{
//fallback to the default credential authentication
_keyVaultClient = new SecretClient(
vaultUri: new Uri(_keyVaultBaseUrl)
, credential: new DefaultAzureCredential());
}
}
private void ConfigureAzureCredentials()
{
try
{
_keyVaultClient = new SecretClient(
vaultUri: new Uri(_keyVaultBaseUrl)
, credential: new DefaultAzureCredential());
}
catch (Exception ex)
{
_logger.LogError
(ex,"Keyvalut Error: {0} - {1}", GetType()?.Name, ex.Message);
throw;
}
}
}